undefined method `admin?' for nil:NilClass
Solution 1
current_user
will be nil if a user is not logged in according to your code. So you need to do this:
<% if current_user && current_user.admin? %>
or using the try
method Rails adds to all objects.
<% if current_user.try(:admin?) %>
Solution 2
as Dogbert said, current_user
will be nil if the user is not logged in.
I would suggest two other alternatives:
1) in the current_user
method return a special type "guest" user instead of nil. Il will be useful in case you want to do something else with it later, for example in response to some user action.
As inspiration, look at how Ryan Bates explains the Ability
class of his gem cancan: link.
The first thing he does is creating an unitilized (and not persisted in DB) user. An that Ability
class will be instantiated each time Rails will parse an ERB template with that kind of user verification.
So, you could do:
def current_user
@current_user ||= ((User.find(session[:user_id]) if session[:user_id]) || User.new)
end
So, if (User.find(session[:user_id]) if session[:user_id])
returns nil
, the @current_user
will be set to an uninitialized User with no identity in DB.
2) define a new metod just to check if the user is an admin, for example:
# your unmodified current_user implementation
def current_user
@current_user ||= User.find(session[:user_id]) if session[:user_id]
end
def is_an_admin?
if current_user && current_user.admin?
end
So that you can use it in this way:
<% if is_an_admin? %>
<div>
<%= do stuff....%>
...It might be an extra method call, but it might also make your code more readable.
Solution 3
I know this is old, but if someone is googling the error as I did, there is actually no error in Rails Tutorial, but they forgot to highlight one thing they added.
Listing 9.54
before_action :logged_in_user, only: [:index, :edit, :update, :destroy]
Note that they added :destroy action here, not added before, which makes sure that the user is logged to perform destroy action and just then checks if he's an admin
before_action :admin_user, only: :destroy
Correction:
As of the time of this edit 12/14/2015, the rails tutorial now adds the :destroy action in Listing 9.53. If you miss that one as I did, you will get this error.
![Holly](https://i.stack.imgur.com/wS47p.gif?s=256&g=1)
Holly
I am a user who prefers to keep an air of mystery about myself, apparently.
Updated on June 04, 2022Comments
-
Holly about 2 years
I followed railscast #250 Authentication from Scratch & got everthing wworking fine. Now I'm trying to only display edit & destroy links on my index page to admin user's.
I've set up mu User database with a admin boolean field & tried putting a simple if statement in the view of another model (hikingtrails) to only display certain links to admin users but I get this error when I try it out,
undefined method 'admin?' for nil:NilClass
Database Schema
create_table "users", :force => true do |t| t.string "email" t.string "password_digest" t.boolean "admin" t.datetime "created_at", :null => false t.datetime "updated_at", :null => false end
User Model
class User < ActiveRecord::Base attr_accessible :email, :password, :password_confirmation#, :admin validates :email, :uniqueness => true has_secure_password end
Application Controller
class ApplicationController < ActionController::Base protect_from_forgery # fetch the currently logged-in user record to see if the user is currently logged in # putting this method in ApplicationController so that it’s available in all controllers private def current_user # checks for a User based on the session’s user id that was stored when they logged in, and stores result in an instance variable @current_user ||= User.find(session[:user_id]) if session[:user_id] end # to give access to this method from all the views, the helper_method makes it a helper method helper_method :current_user # basic authorization, user must be logged in! def authorize redirect_to login_url, alert: "You must be logged in to perform this action" if current_user.nil? end end
views/hikingtrails/index.html.erb
<% if current_user.admin? %> <%= link_to t('.edit', :default => t("helpers.links.edit")), edit_hikingtrail_path(hikingtrail), :class => 'btn btn-mini' %> <%= link_to t('.destroy', :default => t("helpers.links.destroy")), hikingtrail_path(hikingtrail), :method => :delete, :data => { :confirm => t('.confirm', :default => t("helpers.links.confirm", :default => 'Are you sure?')) }, :class => 'btn btn-mini btn-danger' %> <% end %>
-
Dogbert about 11 years-1. That won't help this problem at all, and also create a huge security vulnerability.
-
OneChillDude about 11 yearsYa,
attr_accessible
determines the existence of mass assignment capabilities, not getter methods. You should edit/delete this. Flagged -
Holly about 11 yearsThanks Dogbert,
<% if current_user.try(:admin?) %>
worked perfectly for me. I wonder why didn't work<% if current_user.admin? %>
as it did before in a tutorial I did in college -
James OB about 11 yearsyes, ok it should be on attr_reader. im just pointing out that its commented out
-
tompave about 11 yearsprobably because in that tutorial
current_user
always returned a valid object. See my answer below. -
dtburgess over 8 yearsthis was exactly correct with respect to the problem I was having with the hartl rails tutorial. However, as of this writing this line is updated in listing 9.53