Reputation: 21
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
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
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
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