I am trying to implement the follow actions from M. Hartl's tutorial in my rails composer, devise app.
But for some reason i get this error
undefined method `current_user?' for
when using this code
<% unless current_user?(#user) %>
<div id="follow_form">
<% if current_user.following?(#user) %>
<%= render 'unfollow' %>
<% else %>
<%= render 'follow' %>
<% end %>
</div>
<% end %>
Any idea why?
Thanks
Devise gives you the current_user helper by default. However, it doesn't give you current_user? boolean method. You need to define this method yourself in application_helper.rb:
def current_user?(user)
user == current_user
end
Now you have current_helper? defined you can pass in your #user instance variable
<% unless current_user?(#user) %>
<div id="follow_form">
<% if current_user.following?(#user) %>
<%= render 'unfollow' %>
<% else %>
<%= render 'follow' %>
<% end %>
</div>
<% end %>
Thats all you have to do. You don't have to touch your ApplicationController or SessionsHelper in any way. You are simply using current_user which Devise gives you in order to define current_user?(user). This way is much easier to implement. Hope this helps
Update
Hopefully you should have the following setup:
Your ApplicationController
class ApplicationController < ActionController::Base
protect_from_forgery
include SessionsHelper
# Force signout to prevent CSRF attacks
def handle_unverified_request
sign_out
super
end
private
def current_user
#current_user ||= User.find(session[:user_id]) if session[:user_id]
end
helper_method :current_user
def authorize
redirect_to login_url, alert: "Not Autherized" if current_user.nil?
end
def track_activity(trackable, action = params[:action])
current_user.activities.create! action: action, trackable: trackable
end
end
You should also have a sessions_helper
module SessionsHelper
def sign_in(user)
cookies.permanent[:remember_token] = user.remember_token
self.current_user = user
end
def signed_in?
!current_user.nil?
end
def current_user=(user)
#current_user = user
end
def current_user
#current_user ||= User.find_by_remember_token(cookies[:remember_token])
end
def current_user?(user)
user == current_user
end
#CHECK THE ABOVE LINE!
def sign_out
self.current_user = nil
cookies.delete(:remember_token)
end
end
Then you can do in your view the following:
<% unless current_user?(#user) %>
<div id="follow_form">
<% if current_user.following?(#user) %>
<%= render 'unfollow' %>
<% else %>
<%= render 'follow' %>
<% end %>
</div>
<% end %>
Related
ERROR: when logout.
I'm trying to display _admin_user_header partial using an if statement for when 'admin' is logged_in:
Extracted from: _header partial.
<div class="collapse navbar-collapse d-flex justify-content-end">
<% if(current_user && current_user.role == 'admin') %> <== this
<%= render partial: 'admin_user_header' %> <== 2 lines
<% elsif(logged_in?) %>
<%= render partial: 'registered_user_header' %>
<% else %>
<%= render partial: 'anonymous_user_header' %>
<% end %>
</div>
Doing <% if(current_user && current_user.role == 'admin') %> apparently works, but when I try to logout from the current_user account, I get this error:
ActiveRecord::RecordNotFound in HomeController#index
Couldn't find User with 'id'=
Extracted source (around line #25):
23 end
24
25 #current_user = User.find(session[:user_id])
26 end
27
28 def ensure_authenticated
Rails.root:
/Users/dangerrg/Documents/....
Application Trace | Framework Trace | Full Trace
app/controllers/application_controller.rb:25:in `current_user'
app/views/application/_header.html.erb:8:in `_app_views_application__header_html_erb__900908384298268245_70228604326660'
app/views/layouts/application.html.erb:12:in `_app_views_layouts_application_html_erb___299989914533477205_70228570235680'
I've checked other posts answers with a similar problem, looking for solutions, and I tried different ways to accomplish this, but no success yet.
I also check my DB in the Rails console and all users have and :id with its respective value assigned to it.
In application_controller.rb
...
helper_method :logged_in?, :current_user
def logged_in?
session[:user_id].present?
end
...
def current_user
if(#current_user.present?)
return #current_user
end
#current_user = User.find(session[:user_id])
end
...
In home_controler.rb this is the only method:
def index
#tips = Tip.most_recent
end
I'll really appreciate any help on this.
Thanks in advance.
current_user will work only if user logged in. After logout it clears out session[:user_id]. That's why you can not find a user.
User.find(nil)
Before you call current user method that queries DB try to check that session[:user_id] present. That will work:
if(logged_in? && current_user && current_user.role == 'admin')
or
def current_user
return unless logged_id?
if(#current_user.present?)
return #current_user
end
#current_user = User.find(session[:user_id])
end
I think the best option here is to wrap render in if(logged_in?) statement:
<div class="collapse navbar-collapse d-flex justify-content-end">
<% if(logged_in?) %>
<% if(current_user && current_user.role == 'admin') %>
<%= render partial: 'admin_user_header' %>
<% else %>
<%= render partial: 'registered_user_header' %>
<% end %>
<% else %>
<%= render partial: 'anonymous_user_header' %>
<% end %>
</div>
When I'm trying to login I'm getting:
undefined method `admin' for nil:NilClass
which is called from the layouts/_head.html.erb partial
_head.html.erb:
<% if session[:user_id] %>
<% if #current_user.admin %>
<%= button_to 'Swap to user', to_user_path(User.find_by(id: session[:user_id]).id), method: :put,
class: 'btn btn-warning' %>
<% else %>
<%= button_to 'Swap to admin', to_admin_path(User.find_by(id: session[:user_id]).id), method: :put,
class: 'btn btn-warning' %>
<% end %>
<% end %>
As you can see, session[:user_id] exists. Here is application_controller.rb:
class ApplicationController < ActionController::Base
before_action :set_user
protect_from_forgery with: :exception
def set_user
if session[:user_id]
#current_user = User.find_by(session[:user_id])
end
end
end
Also the login button works through Ajax. So why am I getting #current_user as nil, if it's defines before_action in the application controller? (Remember: session[:user_id] != nil)
Your use of find_by is incorrect. It should be:
#current_user = User.find_by(:id => session[:user_id])
So the solve is to define #current_user in create method,like
def create
user = User.find_by(name: params[:name])
respond_to do |format|
if user and user.authenticate(params[:password])
session[:user_id] = user.id
#current_user = user
format.js { }
else
format.js {flash.now[:notice] = 'Wrong pass/name'}
end
end
end
guesss its not absolute right,but one of possible method
I've created two user models called "user" and "shop". When I try to use the #shop variable as shop (like in shop.name) it will not work, but user.name will work. So I missed defining shop at some point, and cannot figure out where to fix it.
Here's the error I get:
NoMethodError (undefined method `name' for nil:NilClass):
app/views/shops/index.html.erb:7:in `block in _app_views_shops_index_html_erb__1785913569146145211_70081842378680'
app/views/shops/index.html.erb:5:in `_app_views_shops_index_html_erb__1785913569146145211_70081842378680'
This index page for user works:
user/index.html.erb
<% provide(:title, 'All users') %>
<h1>All users</h1>
<ul class="users">
<% #users.each do |user| %>
<li>
<%= link_to user.name, user %>
</li>
<% end %>
</ul>
But this one for shops does not b/c of shop.name:
shop/index.html.erb
<% provide(:title, 'All shops') %>
<h1>All shops</h1>
<ul class="shops">
<% #shops.each do |shop| %>
<li>
<%= link_to shop.name, shop %>
</li>
<% end %>
</ul>
Here is the shops controller: shops_controller.rb
class ShopsController < ApplicationController
#add before action for index
before_action :correct_shop, only: [:edit, :update]
def index
#shops = Shop.all
end
def show
#shop = Shop.find(params[:id])
end
def new
#shop = Shop.new
end
def create
#shop = Shop.new(shop_params)
if #shop.save
shop_log_in #shop
flash[:success] = "Thank you for signing up, welcome to AccessOBD!"
redirect_to shop_home_path
else
render 'new'
end
end
def edit
#shop = Shop.find(params[:id])
end
def update
#shop = Shop.find(params[:id])
if #shop.update_attributes(shop_params)
flash[:success] = "Profile updated"
redirect_to #shop
else
render 'edit'
end
end
private
def shop_params
params.require(:shop).permit(:name, :address, :city, :state, :zip, :email, :phone, :password,
:password_confirmation, :picture)
end
def correct_shop
#shop = Shop.find(params[:id])
redirect_to(root_url) unless current_shop?(#shop)
end
end
And here is the session helper for shops: ShopSessionsHelper.rb
module ShopSessionsHelper
# Logs in the given shop.
def shop_log_in(shop)
session[:shop_id] = shop.id
end
# Remembers a shop in a persistent session.
def shop_remember(shop)
shop.remember
cookies.permanent.signed[:shop_id] = shop.id
cookies.permanent[:remember_token] = shop.remember_token
end
def current_shop?(shop)
shop == current_shop
end
# Returns the shop corresponding to the remember token cookie.
def current_shop
if (shop_id = session[:shop_id])
#current_shop ||= Shop.find_by(id: shop_id)
elsif (shop_id = cookies.signed[:shop_id])
shop = Shop.find_by(id: shop_id)
if shop && shop.authenticated?(cookies[:remember_token])
shop_log_in shop
#current_shop = shop
end
end
end
# Returns true if the shop is logged in, false otherwise.
def shop_logged_in?
!current_shop.nil?
end
def shop_forget(shop)
shop.forget
cookies.delete(:shop_id)
cookies.delete(:remember_token)
end
# Logs out the current shop.
def shop_logout
shop_forget(current_shop)
session.delete(:shop_id)
#current_shop = nil
end
# Redirects to stored location (or to the default).
def shop_redirect_back_or(default)
redirect_to(shop)
session.delete(:forwarding_url)
end
# Stores the URL trying to be accessed.
def store_location
session[:forwarding_url] = request.url if request.get?
end
end
index.html.erb former
<% #shops.each do |shop| %>
<li>
<div class= "shop-name pull-left">
<%= link_to shop.name, shop %>
<% if current_shop.admin? && !current_shop?(shop) %>
| <%= link_to "(Delete Shop)", shop, method: :delete,
data: { confirm: "You sure?" } %>
<% end %>
</div>
<div class= "shop-address pull-right">
<p><%= shop.address %> <br> <%= shop.city %>, <%= shop.state %> <%= shop.zip %> <br> <%= shop.phone %></p>
</div>
</li>
<% end %>
Some of your records are nil, to identify them run the following code, you will get index values of those records
<% #shops.each_with_index do |shop, index| %>
<li>
<% unless shop.blank? %>
<%= link_to shop.name, shop %>
<% else %>
<%= "Record nil at " + index.to_s %>
<% end %>
</li>
<% end %>
I'm having issues trying to figure out why i'm getting undefined methodcurrent_user?'`
In my Application controller:
class ApplicationController < ActionController::Base
protect_from_forgery
include SessionsHelper
# Force signout to prevent CSRF attacks
def handle_unverified_request
sign_out
super
end
private
def current_user
#current_user ||= User.find(session[:user_id]) if session[:user_id]
end
helper_method :current_user
def authorize
redirect_to login_url, alert: "Not Autherized" if current_user.nil?
end
def track_activity(trackable, action = params[:action])
current_user.activities.create! action: action, trackable: trackable
end
end
In my session helper:
module SessionsHelper
def sign_in(user)
cookies.permanent[:remember_token] = user.remember_token
self.current_user = user
end
def signed_in?
!current_user.nil?
end
def current_user=(user)
#current_user = user
end
def current_user
#current_user ||= User.find_by_remember_token(cookies[:remember_token])
end
def sign_out
self.current_user = nil
cookies.delete(:remember_token)
end
end
I'm still new to rails I'm following some tutorials, but I'm trying to figure out why I'm getting undefined method for current_user?
This is where my error is occurring- users view folder:
<% unless current_user?(#user) %>
<div id="follow_form">
<% if current_user.following?(#user) %>
<%= render 'unfollow' %>
<% else %>
<%= render 'follow' %>
<% end %>
</div>
<% end %>
You have not defined a current_user? method anywhere, and you are calling current_user?(#user).
Perhaps, you need to call signed_in? instead of current_user?, or define what you mean by current_user?(#user)
You have not defined current_user? method.
there is a difference between current_user and current_user? current_user? always return a boolean response.
but you can try with current_user(#user)? or unless current_user(#user).nil?
Try this:
def current_user?(user)
user == current_user
end
I am trying to create an admin instance through my admins controller create action, but I keep getting an error that says:
ActiveRecord::RecordNotFound in AdminsController#show: Couldn't find User with id=4
The trace indicates that it is attempting to use the sessions helper (for user) instead of the appropriate adminsessions helper.
app/helpers/sessions_helper.rb:20:in `current_user'
app/helpers/sessions_helper.rb:12:in `signed_in?'
app/views/layouts/application.html.erb:13:in
app_views_layouts_application_html_erb__1013605049_93953830
I can log in correctly and the admin is created. I just think the problem has to do with the redirect_to #admin in my admins controller, though I'm not sure.
How do I set it up so that my admins controller uses the adminsessions helper instead of the sessions helper? Any help would be greatly appreciated.
adminsessions_controller.rb
class AdminsessionsController < ApplicationController
def new
#title = "Log in"
end
def show
#title = "Admin session"
end
def create
admin = Admin.authenticate(params[:adminsession][:email],
params[:adminsession][:password])
if admin.nil?
flash.now[:error] = "Invalid email/password combination."
#title = "Log in"
render 'new'
else
sign_in admin
redirect_to admin
end
end
def destroy
sign_out
redirect_to root_path
end
end
admins_controller.rb
class AdminsController < ApplicationController
def index
#user = User.all
end
def show
#admin = Admin.find(params[:id])
end
def new
#admin = Admin.new
#title = "New admin"
end
def create
#admin = Admin.new(params[:admin])
if #admin.save
sign_in #admin
flash[:success] = "Welcome admin!"
redirect_to #admin
else
#title = "New admin"
render 'new'
end
end
end
new.html.erb (form where I create new user)
<div id="signupform_new">
<%= form_for(#admin) do |f| %>
<div class="field">
<%= f.label :username %>
<%= f.text_field :name, :class => "round" %>
</div>
<div class="field">
<%= f.label :email %>
<%= f.text_field :email, :class => "round" %>
</div>
<div class="field">
<%= f.label :password %>
<%= f.password_field :password, :class => "round" %>
</div>
<div class="field">
<%= f.label :password_confirmation, "Confirmation" %>
<%= f.password_field :password_confirmation, :class => "round" %>
</div>
<div class="action">
<%= button_tag "", :class => "acctSubmit" %>
</div>
<% end %>
</div>
sessions_helper.rb
module SessionsHelper
def sign_in(user)
session[:user_id] = user.id
self.current_user = user
end
def signed_in?
!current_user.nil?
end
def current_user=(user)
#current_user = user
end
def current_user
#current_user ||= User.find(session[:user_id]) if session[:user_id]
end
def current_user?(user)
user == current_user
end
def authenticate
deny_access unless signed_in?
end
def sign_out
session[:user_id] = nil
self.current_user = nil
end
def redirect_back_or(default)
redirect_to(session[:return_to] || default)
clear_return_to
end
def deny_access
store_location
redirect_to login_path, :notice => "Please log in to access this page."
end
private
def store_location
session[:return_to] = request.fullpath
end
def clear_return_to
session[:return_to] = nil
end
end
adminsessions_helper.rb
module AdminsessionsHelper
def sign_in(admin)
adminsession[:admin_id] = admin.id
self.current_admin = admin
end
def signed_in?
!current_admin.nil?
end
def current_admin=(admin)
#current_admin = admin
end
def current_admin
#current_admin ||= Admin.find(adminsession[:admin_id]) if adminsession[:admin_id]
end
def current_admin?(admin)
admin == current_admin
end
def authenticate
deny_access unless signed_in?
end
def sign_out
adminsession[:admin_id] = nil
self.current_admin = nil
end
def redirect_back_or(default)
redirect_to(adminsession[:return_to] || default)
clear_return_to
end
def deny_access
store_location
redirect_to login_path, :notice => "Please log in to access this page."
end
private
def store_location
adminsession[:return_to] = request.fullpath
end
def clear_return_to
adminsession[:return_to] = nil
end
end
All helpers are (by default) mixed in and available in all controllers. Looks like the methods you are using should be protected or private members of your controllers instead. You can make them helper methods to be available in your views, i.e. helper_method :signed_in?.
Personally I never liked the lack of namespacing with helpers anyway. I like the presenter pattern much better (see RailsCasts Pro].