I'm just starting out with Rails and I got stuck with displaying properties that only belongs to signed in user.
I have a user, post model with the following associations
class User < ActiveRecord::Base
has_many :posts, dependent: :destroy
end
class Post < ActiveRecord::Base
belongs_to :user
end
and on post controller I'm trying to access current user's posts with session helper method called current_user but it complains that posts is undefined
def index
#posts = current_user.posts
end
This is the helper method
def current_user
remember_token = User.digest(cookies[:remember_token])
#current_user ||= User.find_by(remember_token: remember_token)
end
Can someone please shed some light on it?
Error Message
NoMethodError in PostsController#index
undefined method `posts' for nil:NilClass
It's is not the method posts is undefined. Your current_user object is nil and that means the user with this remember_token is not found. If you never want a undefined method posts for nil:NilClass type in current_user.try(:posts) so that if the user is logged out they won't see the error. Or create this method in your application controller.
application_controller.rb
private
def is_logged_in?
current_user.present?
end
And call this method in the before_filter section of your controller.
Anyways why not use devise gem for your authentication process. It's is very reliable and comes with the current_user and authenticate_user! methods defined out of the box
It says that the value your current_user is nil, and nil does not have method posts.
Check your user's remember token, and print the parameter you feed to find_by.
Eeeer... is it complaining on the view or the controller? tell us exactly what it complains about (copy paste the result). Maybe use #posts in your view instead of posts (ofcourse posts is undefined, #posts is defined).
Related
I'm working on a login/logout system. Instead of using devise, I created an active records User model and use sessions to remember if a user is logged in. Everything was working fine until I added these lines in the application_controller.rb to have a layout before login and one after.
layout :set_layout
def set_layout
if session[:current_user_id]
'afterlogin'
else
'application'
end
end
Now, after I log in and cancancan is being used somewhere in a html page I get undefined local variable or method 'current_user'. I think that I have to add a current_user method but I'm not exactly where and how to define it.
Edit: I already had something similar in another class that is being used by login:
class Admin::ApplicationController < ApplicationController
before_action :authorize
def authorize
begin
#current_user ||= User.find(session[:current_user_id]) if session[:current_user_id]
rescue ActiveRecord::RecordNotFound
session.destroy
redirect_to '/login',alert: 'Please login'
end
end
end
Should I modify this after I add that method ?
CanCanCan expects a current_user method to exist in the controller.
First, set up some authentication (such as Authlogic or Devise).
See Changing Defaults if you need different behavior.
I would suggest you to install Devise so that it comes with a complimentary current_user method.
FYI: https://github.com/plataformatec/devise
UPDATE
when a user logins successfully, you can store the user's id in session.
session[:current_user_id]=user.id
so that, in your applicationcontroller, you can do
def current_user
#current_user ||= session[:current_user_id] && User.find_by_id(session[:current_user_id])
end
helper_method :current_user
In a create method in a controller I have:
if logged_in_admin?
#invitation.set_ids
In the Invitation model:
def set_ids
self.person_one_id = current_user.id
end
current_user is a method in app/helpers/sessions_helper.rb and defines the currently logged in user. I use this method successfully in many controller methods. However, for the use case above I get the error message undefined local variable or method 'current_user' for #<Invitation:0x007f699086bf40>.
Why do I get this error message? Is this because this time I'm using the helper method in a model file and is this not allowed? If such is not allowed, what would be the best way to securely set person_one_id for #invitation equal to the id of the currently logged in user?
current_user not available in a model layer(it's MVC, your helpers on the CV layer and model know nothing about the current_user helper). Pass user_id from your helper as argument:
some_helper.rb
def my_helper
if logged_in_admin?
#invitation.set_ids(current_user.id)
# .....
model.rb:
def set_ids(user_id)
self.person_one_id = user_id
end
You have to add the following line to your ApplicationController:
class ApplicationController < ActionController::Base
protect_from_forgery with: :exception
include SessionsHelper
end
Now you should be able to use the methods inside your controllers / models.
hi i am trying to access current_user within a model for the purpose of creating an element on the fly with find_or_create_by.
the following is the method within my model
def opponent_name=(name)
self.opponent = Opponent.find_or_create_by_name_and_team_id(name,current_user.team_id) if name.present?
end
but the error i am getting is
NameError in EventsController#create
undefined local variable or method `current_user' for #<Event:0x007fb575e92000>
current_user is not accessible from within model files in Rails, only controllers, views and helpers.
What you should do is to pass the current_user.team_id to the opponent_name method like this:
def opponent_name=(name, current_user_team_id)
self.opponent = Opponent.find_or_create_by_name_and_team_id(name,current_user.team_id) if name.present?
end
Access current_user in Model File:
# code in Applcation Controller:
class ApplicationController < ActionController::Base
before_filter :global_user
def global_user
Comment.user = current_user
end
end
#Code in your Model File :
class Comment < ActiveRecord::Base
cattr_accessor :user # it's accessible outside Comment
attr_accessible :commenter
def assign_user
self.commenter = self.user.name
end
end
Pardon me, if It violates any MVC Architecture Rules.
Its not a good way to access the current_user in a model, this logic belongs to the controller. But if you realy cant find a workaround you should put it into a thread. But keep in mind this is not the way how it should be build.
https://rails-bestpractices.com/posts/2010/08/23/fetch-current-user-in-models/
Rails 5.2 introduced current attributes:
https://api.rubyonrails.org/classes/ActiveSupport/CurrentAttributes.html
but as always... you must have in mind that using global states like this might let to some unpredictable behaviour 🤷♀️ :
https://ryanbigg.com/2017/06/current-considered-harmful
I'm using Devise to handle users in a shopping application. What I want to do is create a new cart each time a user signs in (and ideally, destroy the same cart each time a user signs out, but I'll just stick to that first part for this question).
So far, I've looked at this question: Devise call backs
And I came up with this:
class ApplicationController < ActionController::Base
helper :all
protect_from_forgery
before_filter :fetch_categories
.
.
.
Warden::Manager.after_authentication do
session[:cart_id] ||= Cart.create!.id
end
end
...But clearly this isn't correct, because I'm getting this error:
NameError in Devise::SessionsController#create
undefined local variable or method `session' for ApplicationController:Class
Is there some other way I can tell the application controller to respond to a user sign in, or should I be putting this code elsewhere (other than the application controller)? Thanks for any help.
Glancing at the docs, it looks like you can do something like this:
Warden::Manager.after_authentication do |user, auth, opts|
auth.session[:cart_id] ||= Cart.create!.id
end
Simpally write a before filter
In application controller
before_filter :set_current_user
def set_current_user
Authorization.current_user = current_user
end
and
you can check throughout application
using
` if !current_user.nil?
end`
I'm trying to design a comment system for my RoR blogging site, and I am having some conceptual problems with the architecture. As far as models are concerned, I have Blogposts, Users, and Comments.
A User has_many Blogposts
A Blogpost belongs_to one User
A Blogpost has_many Comments
A Comment may or may not belong to a registered User (I want people not registered with the site to be able to comment as well).
My question is this: in order to enforce the link between a comment and a blogpost, I create each new comment (#comment) through the blogpost association (#blogpost.comments.build(:args)). However, I do not know how to associate a particular registered User with his/her comment. I left the user_id attribute OUT of the attr_accessible for the Comment model because I wanted to prevent the possibility of people attributing comments to the wrong users.
Any ideas on how best to implement a commenting system with such a relation? Thanks so much in advance!
Assuming:
User has_many comments
Comment belongs_to user
In your controller when saving the comment, you can simply do:
#comment.user = current_user if current_user
#comment.save
If the comment is done by an unregistered user #comment.user just stays empty.
You can just have an association :
User has_many comments through blog_posts
So, now you can do :
current_user.comments
Another way to do it is via blog_post:
current_user.blog_post.comments
Moreover, you can use the nice act_as_commentable plugin :)
https://github.com/jackdempsey/acts_as_commentable
There's no need to have user_id as attr_accessible if you have access to the currently logged in user in your save or post new comment methods.
If they aren't logged in then you expect current user to be empty / false.
This should be available if you're using any of the authentication plugins such as authlogic or devise. In my experience with authlogic you typically have a current_user method in your ApplicationController.
class ApplicationController
helper_method :current_user_session, :current_user
private
def current_user_session
return #current_user_session if defined?(#current_user_session)
#current_user_session = UserSession.find
end
def current_user
return #current_user if defined?(#current_user)
#current_user = current_user_session && current_user_session.user
end
end
Above code from the Authlogic quick example
You can add an association between Comment and User, then create the comment with current_user:
# User.rb
has_many :comments
# Comment
belongs_to :user
Setting up the associations only really adds the association methods, so there's no problem with creating Comment without a logged in user. You don't want to build the comment off of current_user as current_user.comments.create(...), because that will throw a NilClass error if nobody is logged in.
#user = current_user # #user should be nil if commenter is not logged in
# be fancy and use a block
#blogpost.comments.create(params[:comment]) do |c|
c.user = #user
end
As long as there is no validation for User in Comment, the nil user should just pass through without trouble.