Why am I getting undefined method `read' for nil:NilClass when I am trying to email an uploaded attachment?
listings_controller.rb
def send_resume_email
#listing = Listing.find(params[:id])
#user = User.find_by_id(params[:id])
UserMailer.new_resume(params[:resume].read(), params[:resume].original_filename, #user, #listing).deliver
redirect_to findjobs_path, notice: 'Message sent'
end
user_mailer.rb
def new_resume(user, listing, file, filename)
#listing = listing
#user = user
attachments[filename] = file
#url = 'http://www.new.com'
mail(to: listing.user.email, subject: 'Thanks for the awesome site')
end
I really appreciate your help.
There are several issues with your code.
First, you are trying to find two resources using the same id param. The params[:id] should belong to either the user or the listing. Which one is it?
On another note, User.find_by_id(params[:id]) is redundant. User.find(params[:id]) should suffice, since the default lookup value for find is id.
#listing = Listing.find(params[:id])
#user = User.find_by_id(params[:id])
Finally, you are calling the method read() on a params hash.
UserMailer.new_resume(params[:resume].read(), params[:resume].original_filename, #user, #listing).deliver
Where is the hash coming from? And how does params[:resume] have an instantiated object that you can call read() on? Usually param hashes are a result of form submissions or a browser request, so it is unlikely to contain an instantiated object that you can call methods on.
And this is the source of your error. The error tells you that params[:resume] is nil. Therefore calling any method on it will raise an error.
The error is just what it says:
params[:resume].nil?
would evaluate to true, and of course, nil:NilClass has no method read.
You can check that your parameter is being populated by
unless params[:resume].blank?
r = params[:resume].read
end
Related
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>)
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)
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...
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.
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