I am getting a NoMethodError in Users#show undefined method 'name' for nil:NilClass on the following code.
Show view:
<% provide(:title, #user.name) %>
<div class="row">
...
Users controller:
class UsersController < ApplicationController
def new
#user = User.new
render :layout => false
end
def create
#user = User.new(user_params)
if #user.save
flash[:success] = "Welcome to the BluePlaque Explorer!"
redirect_to #user
else
render 'new'
end
end
def show
#user = User.find(params[:id])
end
private
def user_params
params.require(:user).permit(:first_name, :last_name, :email, :password,
:password_confirmation)
end
def login
render :layout => false
end
end
The show view what displays user's profile page after successful registration. Cannot see what causes it.
NoMethodError in Users#show undefined method 'name' for nil:NilClass
Apart from the apparent fact you don't have a .name method for your User model, there is another problem highlighted by this error... that your #user variable is not set.
Rails/Ruby doesn't handle "undeclared" variables in the expected way; it assigns them to nil:NilClass - it messes up developer's minds because they think the method is the error, when really, it's the lack of #object to call the method on.
The bottom line is that you need the following:
#app/controllers/users_controller.rb
class UsersController < ApplicationController
def show
#user = User.find params[:id]
end
end
This will set your #user variable, with which you'll be able to call .name or whatever:
#app/views/users/show.html.erb
<%= #user.first_name %>
--
Now... a cool trick for you:
#app/models/user.rb
class User < ActiveRecord::Base
def name
first_name + " " + last_name
end
end
This will allow you to call #user.name if #user is set!
You always have able to use try if not sure about presense
<% provide(:title, #user.try(:name)) %>
Related
I'm trying to setup active storage to upload an avatar when a new user register.
I have run:
rails active_storage:install
rails db:migrate
It's a simple app without devise.
I have put "has_one_attached" in model/user.rb
class User < ApplicationRecord
before_save { self.username = username.downcase }
has_one_attached :avatar
end
I have put ":avatar" in strong parameters on user controller:
class UsersController < ApplicationController
def new
#user = User.new
end
def edit
#user = User.find(params[:id])
end
def update
#user = User.find(params[:id])
#user.avatar.attach(params[:avatar])
if #user.update(user_params)
flash[:notice] = "Your account information was succesfully updated"
redirect_to user_path
else
render 'edit'
end
end
def create
#user = User.new(user_params)
#user.avatar.attach(params[:avatar])
if #user.save
flash[:notice] = "Welcome to Edx Wallet"
redirect_to user_path(#user)
else
render 'new'
end
end
private
def user_params
params.require(:user).permit(:username, :avatar)
end
Finally I have put the following code in my navigation view to use a generic avatar in case no user is logged in
<%= image_tag user_avatar(current_user, 40), class: "lg:ml-4 mt-1 lg:mb-0 mb-1 ml-5 pointer-cursor hover:bg-gray-50"%>
And in my application_helper:
def user_avatar(user, size=40)
if user.avatar.attached?
user.avatar.variant(resize: "#{size}x#{size}!")
else
'https://randomuser.me/api/portraits/women/49.jpg'
end
end
But when trying to display Im getting an error:
Showing
/home/edxco/Documents/Microverse/financial_app/app/views/layouts/_nav.html.erb
where line #48 raised:
undefined method `avatar' for nil:NilClass
> def user_avatar(user, size=40)
> if user.avatar.attached?
> user.avatar.variant(resize: "#{size}x#{size}!")
> else
> 'https://randomuser.me/api/portraits/women/49.jpg'
> end
> end
What I am doing wrong? Could you help me, please?
Your user isn't defined. In your helper method try the instance variable #user that you've set in your controller instead of user.
I am getting an undefined method 'errors' for nil:NilClass error when attempting to display errors in a view from validations in Rails. I followed this example Rails validation error messages displays the error messages and array, taking its answer into account.
An example of a validation I have in the user model is:
validates_length_of :dog_name, minimum: 0, maximum: 30, message: 'cannot have more than 30 characters'
View code
<% if #user.errors.any? %>
<div id="errorExplanation">
<ul>
<% #user.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
Users Controller
class UsersController < ApplicationController
#before_action :logged_in_user, only: [:index, :edit, :update, :destroy,
#:following, :followers]
before_filter :requireLogin
#before_action :requireDog
def requireLogin
if session[:user_id] == nil
redirect_to "/"
end
end
def requireDog
#user = User.find(session[:user_id])
if(#user.dog_name == "Empty")
redirect_to "users/new/"
end
end
def index
#users = User.all
end
def show
#user = User.find(params[:id])
#current_user ||= User.find(session[:user_id]) if session[:user_id]
end
def new
#user = User.new
#current_user ||= User.find(session[:user_id]) if session[:user_id]
end
def update
#user = User.find(params[:id])
if #user.update_attributes(profile_params)
redirect_to action: "show"
# Handle a successful update.
else
render 'edit'
end
end
def following
#title = "Following"
#user = User.find(params[:id])
#users = #user.following.paginate(page: params[:page])
render 'show_follow'
end
def followers
#title = "Followers"
#user = User.find(params[:id])
#users = #user.followers.paginate(page: params[:page])
render 'show_follow'
end
def going
#title = "Going"
#user = User.find(params[:id])
#users = #user.going.paginate(page: params[:page])
render 'show_gather'
end
def create
#user = User.new(profile_params)
if #user.save
redirect_to '/users'
else
render 'new'
end
end
private
def profile_params
params.require(:user).permit(:dog_name, :photo, :dog_breed, :dog_gender, :dog_age)
end
end
In other examples the user model/controller did not need to be further modified. The user does indeed exist. Am I missing something in the model or controller?
Firstly, you'd be better switching to the new validates methods:
#app/models/user.rb
class User < ActiveRecord::Base
validates :dog_name, length: { in: 0..30, message: 'cannot have more than 30 characters'}
end
-
Secondly, instead of setting #title each time - why don't you just use action_name?
Each time you load an action, the controller_name and action_name variables are set by default, to be used either in your controller or views. Why not just use the action_name variable in your view?
#app/views/layouts/application.html.erb
<title><%= action_name if controller_name == "Users" %></title>
To answer your question, the error is caused because you're trying to invoke a method on a non-existent variable:
for nil:NilClass
Ruby has a funny way of posting exceptions for undeclared variables -- instead of outwardly saying the variable doesn't exist, it invokes it under the NilClass class.
As a developer, you're then expected to read the message of undeclared method and surmise that it's the variable which isn't set...
The fix for your problem is therefore to find why the variable is not set:
#app/controllers/users_controller.rb
class UsersController < ApplicationController
def new
#user = User.new
end
def create
#user = User.new profile_params
redirect_to users_path if #user.save
end
end
The above should give you the ability to save the user, else it will re-render the new action (and show the error).
I think the problem you have is that you're explicitly loading the new action on validation problems, which will prevent it appending the required data.
Trying to update 2 attributes to a User model, this is my current code in the Users controller:
def update
#user = User.find(params[:id])
if #user.update_attributes(songkickID: params[:user][:songkickID], jamID: params[:user][:jamID])
redirect_to #user
else
redirect_to #user
end
end
The Songkick ID and the Jam ID are entered into 2 different fields. However, with the current code, if I attempt to update the Jam ID on its own, it updates that attribute, but then redirects to the user page (as expected), where the Songkick ID is now nil. Upon entering the Songkick ID again, the Jam ID becomes nil. I suppose this is because they are both part of the same if statement in the controller?
I attempted to use an elsif for the jamID params, but it does not seem to recognise at all (i.e. won't update that attribute for the user). Also attempted || conditional operator.
EDIT: Here's the 2 different forms:
<%= form_for(#user) do |f| %>
<%= f.text_field :jamID, :id=>"jamURL" %>
<%= f.submit "Jam ID", :onclick => "changeImg()", id: "saveJam" %>
<% end %>
and
<%= form_for(#user) do |f| %>
<%= f.text_field :songkickID %>
<%= f.submit "Songkick ID", :type => :image, :src => image_path("songkicklogo.png"), id: "skLogo" %>
<% end %>
And I tried modifiying the code to update_column, but I get wrong number of arguments (1 for 2).
EDIT 2: Following layout from Hartl's Rails Tutorial, I attempted this to define strong parameters:
private
def user_params
params.require(:user).permit(:songkickID, :jamID)
end
But I still get the Forbidden Attributes Error?
EDIT 3: The following code passes, but I worry it doesn't adhere to Rails 4 strong parameters:
Controller:
class UsersController < ApplicationController
def show
#user = User.find(params[:id])
end
def edit
#user = User.find(params[:id])
end
def user_params
params.require(:user).permit(:songkickID, :jamID)
end
def update
#user = User.find(params[:id])
if #user.update_attributes(user_params)
redirect_to #user
else
redirect_to #user
end
end
end
If I move update to below the update method, I get an undefined variable/method error for user_params, and I cannot make it private.
So - why are you explicitly naming the attributes in your update_attributes?
You should be able to use the following:
#user.update_attributes(params[:user])
Remember that if you've named your form fields correctly, params[:user] is a hash that will already have the keys you want (:songkickID etc)
Now - you will get one of two things coming through to your action, which you then pass through to update_attributes as:
{:songkickID => someID}
{:jamID => someOtherID}
which will correctly update your user and only change the one that is passed.
The problem with your earlier code was that what you passed to update attribute was:
{:songkickID => someID, :jamID => nil}
{:songkickID => nil, :jamID => someOtherID}
which was deliberately overwriting the other id with the nil you passed.
EDIT from OP: Thanks for this, and here's my final controller code:
class UsersController < ApplicationController
def show
#user = User.find(params[:id])
end
def edit
#user = User.find(params[:id])
end
def update
#user = User.find(params[:id])
if #user.update_attributes(user_params)
redirect_to #user
else
redirect_to #user
end
end
private
def user_params
params.require(:user).permit(:songkickID, :jamID)
end
end
In last case scenario:
def update
if params[:user][:songkickID]
received_param = { songkickID: params[:user][:songkickID] }
elsif params[:user][:jamID]
received_param = { jamID: params[:user][:jamID] }
end
#user.update_attributes(received_param)
redirect_to #user
end
Note: I removed the last condition since it wasn't useful
I'm doing a ruby on rails tutorial and all of a sudden going to the signup page returns this:
Anyone know a fix? Or for that matter what went wrong? It seemed very sudden and I don't think I changed anything that would affect the signup page...
class UsersController < ApplicationController
def show
#user = User.find(params[:id])
end
def create
#user = User.new(user_params)
if #user.save
redirect_to #user
else
render 'new'
end
end
private
def user_params
params.require(:user).permit(:name, :email, :password,
:password_confirmation)
end
end
It means that your #user object was not initialized..
You need to initialize your #user variable. Here are a couple of options.
Make sure your new method initializes it in your UsersController class:
def new
#user = User.new
end
Another option is to just use a new object right in the form:
<%= form_for(User.new) do |f| %>
And yet another option, is to in your view, before echoing the form_for, put:
<% #user = User.new %>
My best recommendation would be to put the variable in the controller like I did in the first example.
users_controller.rb
class UsersController < ApplicationController
def index
render_404
end
def show
#user = User.where(:username => params[:username])
render_404 if !#user
end
end
basically i want to get each user data based on their username because later i want to include one more table which has meta-data for each user but i keep getting the following error
undefined method `username' for #<ActiveRecord::Relation:0x007fb5dbc52ea0>
Extracted source (around line #1):
1: <%= #user.username %> profile page
#user = User.where(:username => params[:username]).first try this or #user = User.find_by_username(params[:username]). Where returns AR::Relation, not an ActiveRecord object.