user3930620
user3930620

Reputation: 21

Undefined method error while trying to reach view

I am trying to learn Rails. I am following a book but I keep getting the following error:

undefined method `first_name' for nil:NilClass error

Here are the codes.

I don't understand why @user.first_name couldn't reach to users/show view. a bit help wouldn't be bad.

Controller:

class UsersController < ApplicationController
    def new
        @user = User.new
    end
    def create 
        @user = User.new(params.require(:user).permit!)
        if @user.save
            flash[:notice] = "Welcome"
            redirect_to @user
        else
            render :new
        end
    end
    private
    def user_params
        params.require(:user).permit!
    end
    def show
        @user = User.find(params[:id])
        render layout: 'profile'
    end
end

model:

class User < ActiveRecord::Base
        has_secure_password
        validates :username,   presence: true,
                               uniqueness: {case_sensitive: false},
                               length: {in: 4..12},
                               format: {with: /\A[a-zA-Z][a-zA-Z0-9_-]*\Z/}

        validates :first_name, presence: true
        validates :last_name,  presence: true
        validates :email,      presence: true,
                               uniqueness: {case_sensitive: false},
                               email: true
        validates :password,   presence: true,
                               length: {minimum: 6}


    end

View:

<div class="row">
<div class="large-12 columns">
<div class="large-2 columns">
<img src="http://placehold.it/160x160" class="profile-image" alt="">
</div>
<div class="large-10 columns">
<p><%= "#{@user.first_name}" %></p>
<div class="button-bar">
<ul class="button-group-radius">
<li><%= link_to "Subject", user_path(@user, page: 'subjects'), class: 'small button secondary' %></li>
<li><%= link_to "Comments", user_path(@user, sayfa: 'comments'), class: 'small button secondary' %></li>
<li><%= link_to "Edit My Profile", edit_user_path(@user), class: 'small button secondary' %></li>
<li><%= link_to "Delete My Account", @user, class: 'small button alert', method: :delete %></li>
</ul>
</div>
</div>
<div class="large-12 colums">
Subject..
</div>
</div>
</div>

Upvotes: 0

Views: 220

Answers (3)

Marc Lainez
Marc Lainez

Reputation: 3080

Move your show method up, above the private keyword, and it should work.

The reason is that by default, rails render the routes associated view.

For instance:

resources :users, only: :index

Coupled with the following controller

class UsersController < ApplicationController
end

And calling /users

Will automatically render the users/index view, even if you don't see it. When you write the action method yourself, you're actually overriding the default behaviour.

In your case you have a private show method, meaning it's not accessible when you call the show/:id route. It falls back to the default behaviour. Only public methods are callable as actions.

You should probably read the ActionController guide to understand what's happening.

Upvotes: 0

RAJ
RAJ

Reputation: 9747

You need to move show action out of private scope:

class UsersController < ApplicationController
  ...
  ...
  def show
    @user = User.find(params[:id])
    render layout: 'profile'
  end

  private
  def user_params
    params.require(:user).permit!
  end
end

Improvement:

Your can write

<p><%= @user.first_name %></p>

instead of

<p><%= "#{@user.first_name}" %></p>

Upvotes: 1

Jesse Mignac
Jesse Mignac

Reputation: 305

There are two things you can fix in your code. First, you need to pull the "show" action out of the private section, so it can be seen by the whole application. Every method you put after the word "private" will be private, not only the next one. If you keep the show action there, it won't be found.

The second thing is that you have a private method called user_params that sets the strong params already, so you can keep the "create" action a little simplier by refactoring the arguments to user_párams, because they are returning the same thing. In Ruby, one of the pillars is DRY - Don't repeat yourself. your controller would be something like this:

 def new
    @user = User.new
end
def create 
    @user = User.new(user_params)
    if @user.save
        flash[:notice] = "Welcome"
        redirect_to @user
    else
        render :new
    end
end
def show
    @user = User.find(params[:id])
    render layout: 'profile'
end
private
def user_params
    params.require(:user).permit!
end

Upvotes: 1

Related Questions