Question

Could use a little help working through an issue I am encountering following the rails tutorial...The first error I receive is the following when trying to access the users index as a 'visitor' (non-logged in user):

Showing /Users/user/Documents/production_app/app/views/users/_user.html.erb where line #3 raised:

undefined method `admin?' for nil:NilClass

My original code:

_USER.HTML.ERB (USER PARTIAL)

<li>
  <%= link_to user.name, user %>
  <% if current_user.admin? && !current_user?(user) %>
    | <%= link_to "delete", user, method: :delete,
                              data: { confirm: "You sure?" } %>
  <% end %>
</li>

INDEX.HTML.ERB (USERS INDEX)

<% provide(:title, 'All users') %>
<h1>All users</h1>

<%= will_paginate %>

<ul class="users">
  <%= render @users %>
</ul>

<%= will_paginate %>

USERS CONTROLLER

class UsersController < ApplicationController
  before_action :signed_in_user,  only: [:edit, :update, :destroy]
  before_action :correct_user,    only: [:edit, :update]
  before_action :admin_user,      only: :destroy

  def index
    @users = User.paginate(page: params[:page], :per_page => 10)
  end

  def show
    @user = User.find(params[:id])
  end

  def new
    @user = User.new
  end

  def create
    @user = User.new(user_params)
    if @user.save
      sign_in @user
      flash[:success] = "Welcome to the Production App!"
      redirect_to @user
    else
      render 'new'
    end 
  end

  def edit
    # @user = User.find(params[:id]) // section 9.14 REMOVED AS A RESULT OF THE NEW CORRECT_USER BEFORE FILTER
  end

  def update
    # @user = User.find(params[:id]) // section 9.14 REMOVED AS A RESULT OF THE NEW CORRECT_USER BEFORE FILTER
    if @user.update_attributes(user_params)
      # Handle a successful update
      flash[:success] = "Profile updated"
      redirect_to @user
    else
      render 'edit'
    end
  end

  def destroy
    User.find(params[:id]).destroy
    flash[:success] = "User deleted."
    redirect_to users_url
  end

  private

    def user_params
      params.require(:user).permit(:name, :email, :password, :password_confirmation)
    end

    # Before filters

    def signed_in_user
      unless signed_in?
        store_location
        flash[:warning] = "Please sign in to access this page."
        redirect_to signin_url
      end
    end

    def correct_user
      @user = User.find(params[:id])
      redirect_to(root_url) unless current_user?(@user)
    end

    def admin_user
      redirect_to(root_url) unless current_user.admin?
    end
end

SESSIONS CONTROLLER

class SessionsController < ApplicationController
  def new
  end

  def create
    user = User.find_by(email: params[:session][:email].downcase)
    if user && user.authenticate(params[:session][:password])
      # Sign in the user & redirect to users show page
      sign_in user
      redirect_back_or user
    else
      flash.now[:danger] = 'Invalid email/password combination'
      render 'new'
    end
  end

  def destroy
    sign_out
    redirect_to root_url
  end
end

SESSIONS HELPER

module SessionsHelper
  def sign_in(user)
    remember_token = User.new_remember_token
    cookies.permanent[:remember_token] = remember_token
    user.update_attribute(:remember_token, User.hash(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
    remember_token = User.hash(cookies[:remember_token])
    @current_user ||= User.find_by(remember_token: remember_token)
  end

  def current_user?(user)
    user == current_user
  end

  def sign_out
    current_user.update_attribute(:remember_token,
                                  User.hash(User.new_remember_token))
    cookies.delete(:remember_token)
    self.current_user = nil
  end

  def redirect_back_or(default)
    redirect_to(session[:return_to] || default)
    session.delete(:return_to)
  end

  def store_location
    session[:return_to] = request.url if request.get?
  end
end

USER MODEL

class User < ActiveRecord::Base
  before_save { self.email = email.downcase }
  before_create :create_remember_token

  validates :name, presence: true, length: { maximum: 50 }
  VALID_EMAIL_REGEX = /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i
  validates :email, presence: true, format: { with: VALID_EMAIL_REGEX },
                    uniqueness: { case_sensitive: false }

  has_secure_password
  validates :password, length: { minimum: 6 }

  def User.new_remember_token
    SecureRandom.urlsafe_base64
  end

  def User.hash(token)
    Digest::SHA1.hexdigest(token.to_s)
  end

  private

    def create_remember_token
      self.remember_token = User.hash(User.new_remember_token)
    end
end

Now...I understand from other posts on stackOverflow that this is occurring because the admin user is set to nil for visitors. However when i followed a couple people suggestions it created a new problem...I changed:

<% if current_user.admin? && !current_user?(user) %>

from the _user.html.erb partial to:

<% if current_user.try(:admin?) && !current_user?(user) %>

as per a suggestion and NOW my error is the following:

/Users/user/Documents/production_app/app/views/users/_user.html.erb:9: syntax error, unexpected keyword_ensure, expecting keyword_end /Users/user/Documents/production_app/app/views/users/_user.html.erb:11: syntax error, unexpected end-of-input, expecting keyword_end

Extracted source (around line #7):

<ul class="users">
7  <%= render @users %>
</ul>

<%= will_paginate %>

I'm sure i'm missing something small/stupid...Any direction on what I"m doing wrong would be much appreciated...

thanks,

Was it helpful?

Solution

Looking purely at your original code, it seems you want to provide a delete link only if there is an admin user logged in.

You are getting the undefined method 'admin?' for nil:NilClass error because current_user is nil; i.e. there is no user logged in.

If not providing the delete link is correct for visitors, you can easily fix this with:

<% if current_user && current_user.admin? && !current_user?(user) %>

i.e. simply check if there is a current_user before checking if that user is an administrator.

OTHER TIPS

As it seems the user partial is meant to be rendered in a page where the user is logged in already. Your current_user is nil. In Ruby you cannot call methods on nil objects. So the user doesn't seem to be not logged in.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top