Reputation: 3189
I am getting this NoMethodError
for current_user.user_id. Below is the table of my users model. I don't know what that error means, since current_user.user_id exists. What could cause this issue? I am lost here. As far as I remember I wasn't getting this error, I kept of adding new things to the project and somewhere I got messed up. though I was making changes that were not related to user mode. after why NoMethodError if current_user.user_id is there? Clueless and confused.
Error -
Started GET "/item/list" for 10.10.10.10 at 2012-05-01 23:19:19 -0400
Processing by Item#list as */*
Completed 500 Internal Server Error in 0ms
NoMethodError (undefined method `user_id' for nil:NilClass):
app/controllers/Item_controller.rb:52:in `list'
User Model table -
mysql> explain users;
+------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------+--------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| user_id | varchar(255) | YES | | NULL | |
| name | varchar(255) | YES | | NULL | |
| created_at | datetime | NO | | NULL | |
| updated_at | datetime | NO | | NULL | |
+------------+--------------+------+-----+---------+----------------+
Item controller that uses current_user.user_id -
def list
@mylist = Item.find(:all, :select => 'item_num', :conditions => { :id => current_user.user_id, :item_status => ["New"]} )
respond_to do |format|
format.html { render :partial => 'item_list'}
format.js
end
return @mylist
end
def current_user
@current_user ||= User.find(session[:user_id]) if session[:user_id]
end
def debug
render :text => current_user.user_id #prints correct user_id
end
Upvotes: 1
Views: 999
Reputation: 43153
You're getting this because current_user
is turning up nil. Your current user function doesn't do what you think it does, let's take a look:
def current_user
@current_user ||= User.find(session[:user_id]) if session[:user_id]
end
So, this executes in this order:
IF there is a session[:user_id]
, continue | or else return nil
Then, if @current_user
is set, return @current_user
| or else continue
Then, set @current_user
to User.find(session[:user_id])
NOTE: User.find()
will raise an exception if it cannot find a user. User.find_by_user_id()
would just return nil
without raising an exception. Be sure and choose the behavior you want.
Your method is ok, it means that you're going to get nil
whenever session[:user_id]
is not set. You just need to catch that in your code. Because nil
is falsy this is pretty easy. In any ruby code:
any_method if current_user
In your controller you would need to do:
def list
if current_user
@mylist = Item.find(:all, :select => 'item_num', :conditions => { :id => current_user.user_id, :item_status => ["New"]} )
respond_to do |format|
format.html { render :partial => 'item_list'}
format.js
end
else
redirect_to login_path, :notice => "You must be logged in to continue."
end
end
Note that (1) in Ruby you don't need to say return
, the last line of every method is returned automatically, and (2) Rails controller methods end when you redirect or render, there is no return.
To make this cleaner I would probably say you need a before_filter. Something like this in your controller should do the trick:
before_filter :require_login
def require_login
redirect_to login_path, :message => 'You must be logged in to view this page.' unless current_user
end
Then all your methods will redirect the person to login if they aren't logged in already. You can also specify only certain methods to use this filter using the :only or :except options.
Because you're likely to use that throughout your app you might move the current_user
and require_login
methods to your application controller.
One last thing though, your code and your question reflect that you're not familiar with some of the really basic ideas of rails and REST. You'll really speed up your development if you learn the "Rails Way" of doing things. A great, free resource to get you on track would be Michael Hartl's Rails 3 Tutorial. You should work through it, you'll be really glad you did, and when you're done you'll be WAY ahead of where you are now.
Upvotes: 2
Reputation: 21180
The problem does not seem to be that your User model does not respond to the method user_id, but according to the error message, the method current_user
returns nil and nil does not respond to user_id. So the reason is probably that you call this action even without any user being logged in.
One way to get around it would be to first check if current_user returns anything before calling user_id. Maybe like this:
@mylist = Item.find(:all, :select => 'item_num', :conditions => { :id => (current_user && current_user.user_id), :item_status => ["New"]} )
If curret_user is nil it will evaluate to false and then user_id will not be called, instead it will query for Items where id is NULL. If that is the appropriate behavior for your app, that I leave up to you.
And as a side note, your syntax is not really Rails 3. I would change it to this:
@mylist = Item.select(:item_num).where(:id => (current_user && current_user.user_id), :item_status => ["New"])
Upvotes: 2
Reputation: 3181
The error message is telling you that current_user
is set to nil
when you try to call user_id
on it. I can't tell you why current_user
is nil
based on the code you've included, but if you can track down how/where current_user
assigns the user, that's where you'll find your problem. It doesn't have anything to do with your database.
Upvotes: 3