-undefined method `user' for nil:NilClass - ruby-on-rails

On the update controller action, rails returns following error,
undefined method `user' for nil:NilClass
Issue is supposed to be in following,
def update
#profile = Profile.find_by(user_id: params[:id])
if #profile.user == current_user
#profile.update(profile_params)
flash[:info] = "Profile successfully updated"
else
It doesn't make sense why this is an issue, since I used the exact same code to find profiles in my other actions and they worked perfectly.

Profile.find_by is returning nil ie: no user was found.
So, when you try #profile.user, you are trying to access user on a nil.
Make sure the profile exists with the user_id matching params[:id] and that params[:id] isn't blank or nil.
A way to get rid of the fatal error would be to check if #profile is nil or not before using it:
def update
#profile = Profile.find_by(user_id: params[:id])
if #profile.present?
if #profile.user == current_user
#profile.update(profile_params)
flash[:info] = "Profile successfully updated"
else
end
else
# Profile not found
end
end
Or, you could use the bang variation of find_by:
Profile.find_by!
Which will throw an exception if nothing is found (which you can then rescue from)

Related

ruby on rails undefined method 'valid' when using update

I am using the same commands that I previously used in successful projects but now I suddenly can't validate any updates to the object(in this case, User). Everything else works fine but any attempt to check my validations for an update results in this error-
'undefined method `valid?' for # '
It is finding successfully finding the user and if I skip the .valid? statement then it will update, just without checking any of my model validations. I recently switched from SQLite to PostgreSQL, I am not sure if that's giving me the problem. I am new to Ruby but I couldn't find anything on this specific problem.
Please let me know if I should include the entirety of my controller or any of my model but as my create works fine, I feel like all the relative code is just in this little section-
class UsersController < ApplicationController
def update
#user = User.find(params[:id])
puts "#Is this working???!! #{#user}" ///prints #Is this working???!! #<User:0x00000001f24468>
#user = User.update(user_params)
if #user.valid?
redirect_to "/users/#{#user.id}"
else
flash[:errors] = #user.errors.full_messages
redirect_to "/users/#{#user.id}/edit"
end
end
private
def user_params
params.require(:user).permit(:name, :email, :password)
end
Your problem is here:
#user = User.update(user_params)
If you put in your check after, you would see: #Is this working???!! true, which would ironically enough inform you that it's not working.
That's because User.update(user_params) returns true or false depending on whether it is successful or not. This means your #user object is now simply either true or false, which you can't call valid on.
If you want to handle successfully updating / failing to do so, try:
def update
#user = User.find(params[:id])
if #user.update(user_params)
redirect_to "/users/#{#user.id}"
else
flash[:errors] = #user.errors.full_messages
redirect_to "/users/#{#user.id}/edit"
end
end
ActiveRecord update(id, attributes)
Updates an object (or multiple objects) and saves it to the database, if validations pass. The resulting object is returned whether the object was saved successfully to the database or not.
Then, you can do this checking if #user.update(user_params)
def update
#user = User.find(params[:id]) //Find user
if #user.update(user_params) // Update user if validations pass
redirect_to "/users/#{#user.id}"
else
flash[:errors] = #user.errors.full_messages
redirect_to "/users/#{#user.id}/edit"
end
end
Or, you can call the update method directly in your model class, but the first argument must be the user ID
User.update(params[:id], user_params)
Thank you both for your quick answers. I was replying to tell you that I already tried that and it worked but did not validate. But as two of you told me the same thing, I decided to test it out again and the validations did indeed work this time so thank you (although I definitely have a user with an email of 'asdf' from last time).
Intestering enough, I found another answer although I have no idea why it worked. I added another puts statement after the update and realized my object had been converted to an array so I came up with this other (worse) alternative answer-
def update
#user = User.find(params[:id])
puts "#Is this working???!! #{#user}"
#user = User.update(user_params)
puts "#Is this working???!! #{#user}" ///prints #Is this working???!! [#<User id: 2, name: "James Dean", etc..>]
if #user[0].valid?
redirect_to "/users/#{#user[0].id}"
else
flash[:errors] = #user[0].errors.full_messages
redirect_to "/users/#{#user[0].id}/edit"
end
end

NoMethodError in UserController#register undefined method `save' for nil:NilClass

Trying to learn ruby on rails following Michael Hartl's tutorial, when I try to go to the registration page in the book I get this:
NoMethodError in UserController#register
undefined method `save' for nil:NilClass
here is the code from the user_controller.rb file:
class UserController < ApplicationController
def index
#title = "RailsSpace User Hub"
end
def register
#title = "Register"
if request.post? and params[:user]
#user = User.new(user_params)
end
if #user.save
flash[:notice] = "User #{#user.screen_name} created!"
redirect_to :action => "index"
end
end
private
def user_params
# Add the user attributes that you sent with post (form) to the permit
method.
params.require(:user).permit(:name, :screen_name)
end
end
It's complaining about line 11 where it says: if #user.save I'm just following the tutorial I don't know what's going on.
Try to understand what the error message is saying. You're trying to call .save on #user but where you are calling it, #user may not be defined. The problem is you can't call .save on a nil object so it throws NoMethodError.
You're logic is incorrect so you must first make sure #user is instantiating a new User instance. It should be more like this:
def register
#title = "Register"
if request.post? && params[:user]
#user = User.new(user_params)
if #user.save
flash[:notice] = "User #{#user.screen_name} created!"
redirect_to :action => "index"
else
# handle erorrs here
flash[:alert] = "Please fix errors: #{#user.errors.full_messages.inspect}"
redirect_to :back #this may need to change depending, just an example.
end
end
end
NoMethodError in UserController#register undefined method 'save' for nil:NilClass
The error is thrown because you are calling save on a nil; and it is because nil object does not have this method. the save is a instance method belonging to ActiveRecord::Base class.
The reason #user is nil is because #user is an instance variable in the UserController class which you have not given it any value. Any variable starting with # inside a class is an instance variable in Ruby.
To solve this problem, you should set a value to #user, and in this case it should be a User instance. You can either create a new user object by doing #user = User.new(user_params) or you fetch a record from the Database by doing #user = User.find(<some_id>)

Rendering template from another controller causes NoMethodError

I'm working on a rails app that contains a Users controller and an Images controller. This is the create method in the Images controller:
def create
#image = current_user.images.build(image_params)
if #image.save
flash[:success] = "Image uploaded!"
redirect_to current_user
else
render 'users/show' #Error occurs here
end
end
Successful saves are handled fine, but if the image is too large or non-existent and 'users/show' is rendered, rails gives the error:
NoMethodError (undefined method `name' for nil:NilClass):
app/views/users/show.html.erb:1:in `_app_views_users_show_html_erb___2850090823537495038_37901140'
app/controllers/images_controller.rb:12:in `create'
I expect this happened because I hadn't initialized all the variables necessary for 'users/show' within my Images controller, so I moved the content from the show method of the Users controller to a new method in the Application controller and called it before rendering the page from Images. Here's the intitialize method:
def initialize_show
#user = User.find(params[:id])
#images = #user.images.paginate(page: params[:page])
#image = current_user.images.build if logged_in?
end
And the new create method:
def create
#image = current_user.images.build(image_params)
if #image.save
flash[:success] = "Image uploaded!"
redirect_to current_user
else
initialize_show # Called this method
render 'users/show'
end
end
Now rails is giving the error:
ActiveRecord::RecordNotFound (Couldn't find User with 'id'=):
app/controllers/application_controller.rb:6:in `initialize_show'
app/controllers/images_controller.rb:12:in `create'
What am I missing here? This is my first rails app so I appreciate the help.
ptd provided the answer in a comment above. #user wasn't getting initialized because the id param wasn't posted to images#create. Here's the solution:
def create
#image = current_user.images.build(image_params)
if #image.save
flash[:success] = "Image uploaded!"
redirect_to current_user
else
#user = current_user
initialize_show # I removed the #user initialization in this method
render 'users/show'
end
end
It looks like your template (users/show) uses something (#vars) that is not available in this case. Can you show that template code? Maybe you have something line #user.name there but this var is not initialized in case you have described...

Mailer action error

I've written a mailer that wroks prooperly. But i'm having problems with getting the action that invokes the mailer to work.
When a comment is created, within the comment body, for every mention of #someusername, if that user exits, they are sent an email to their email address.
Here is what I have:
def create
#commentable = find_commentable
#comment = #commentable.comments.build(params[:comment])
#comment.user = current_user
if #comment.save
flash[:notice] = "Successfully created comment."
redirect_to #commentable
end
end
else
render :action => 'new'
end
This is the error I keep getting:
undefined method `email' for nil:NilClass
end
Here is where the error is coming from(inside the mailer):
#user = user
#url = 'http://domain.com'
mail(to: #user.email)
end
end
email is being called on a nil #user, and #user is going to always be nil.
Looking at this line:
unless #user_check = nil
Using a single equals is assignment, not an equality comparison.
You'll want to do:
unless #user_check == nil
or the more idomatic Ruby:
unless #user_check.nil?
Taking unless #user_check = nil statement for inspection:--
= is assignment and == is equality comparison operator. I guess you just missed using == because of typo.
Use ruby .nil? method instead.
like unless #user_check.nil?
Use delayed_job to send emails.

While using session based model , getting error "undefined local variable or method session for " in rails

code which giving error is in CommentsController
if #comments.save
user_session.add_comment(#comments) // this is cause of error
# session[:comment_ids] ||= []
# session[:comment_ids] << #comments.id
flash[:notice] = "Comment Successfully created"
redirect_to #post
else
redirect_to :back
end
When I go to edit comment which is stored in session for 1 minute. I got this error:
NameError in CommentsController#create
undefined local variable or method `session' for #<UserSession:0xaca0684>
add_comment is defined in session model.
One more thing I want to say that error occurs because I used a centralized location through session model otherwise commented code above was working fine.
If I understand correctly, you've refactored the commented out code into the user_session object.
If you read the error message you see that the error references a variable session for #<UserSession:0xXXXXX>. From this I understand that you tried to reference the session object from within the UserSession class, but you did not pass it to the user_session object.
You should add it to the method's signature, and use it like this:
class UserSession
def add_comment(session, comment)
session[:comment_ids] ||= []
session[:comment_ids] << comment.id
end
end
And in your controller:
if #comment.save
user_session.add_comment(session, #comment)
flash[:notice] = "Comment Successfully created"
redirect_to #post
else
redirect_to :back
end

Resources