How to avoid the error on nil object - ruby-on-rails

Record id 116 doesn't exist so it should return nil to #conversation.
I tried to make it redirect when it gets nil, but it still shows the error when I access example.com/messages/show?id=116 .
The error is
undefined method `is_participant?' for nil:NilClass
I definitely see 'is_participant' method existing in
/usr/local/lib/ruby/gems/1.9.1/gems/mailboxer-0.7.0/app/models/conversation.rb
messages_controller.rb
def show
#conversation = Conversation.find_by_id(params[:id])
unless #conversation.is_participant?(current_user)
flash[:alert] = "You do not have permission to view that conversation."
redirect_to :controller => 'messages', :action => 'received'
end
#messages = Message.find_by_id(params[:id])
current_user.read(#conversation)
end

You need to check that #conversation is not nil before you call a method on it. Try
unless #conversation.present? && #conversation.is_participant?(current_user)

You can check for presence of a value or rescue for that error.
def show
#conversation = Conversation.find_by_id(params[:id])
redirect_to somewhere_path if #conversation.nil?
unless #conversation.is_participant?(current_user)
flash[:alert] = "You do not have permission to view that conversation."
redirect_to :controller => 'messages', :action => 'received'
end
#messages = Message.find_by_id(params[:id])
current_user.read(#conversation)
end
or the Rescue!
def show
#conversation = Conversation.find_by_id(params[:id])
unless #conversation.is_participant?(current_user)
flash[:alert] = "You do not have permission to view that conversation."
redirect_to :controller => 'messages', :action => 'received'
end
#messages = Message.find_by_id(params[:id])
current_user.read(#conversation)
rescue NoMethodError
redirect_to somewhere_path
end
Notice that the rescue way is not very friendly, since it can rescue other error and making you have a pain to debug some errors. For example if current_user has no method named read, it would throw and error that would be catch there and you wouldn't notice it came from there.

Christoph Petschnig answer is right, just wanted to mention there is a nice shorthand for
unless #conversation.present? && #conversation.is_participant?(current_user)
which is
unless #conversation.try(:is_participant? , current_user)
try will return nil is #conversation is nil which eventually evaluates to false in the if statement.

Related

Rails - attribute is not saved

I have this code:
if request.post? and #user.save
#contact.user_id = #user.id
#contact.save
flash[:notice] = l(:e_user_saved)
redirect_to :action => 'list'
end
But when rails saves the contact, the user_id remains null.
When I debug I see that it assigns the value, but when it saves it saves null. Why???
contact.save probably failed. You're not checking the return value, so you don't know.
Check the contact.errors hash to see what went wrong.
You should probably have contact.save in an if block:
if #contact.save
flash[:notice] = l(:e_user_saved)
redirect_to :action => 'list'
else
# some error handling
# and redirect somewhere else
end

Ruby Exception - If Statement rescue doesn't handling exception

I everyone, I've some issue to handling exception in ruby. I doesn't understand why my statement doesn't work.
Error : Couldn't find User with id=14
I want to redirect to the login page.
def login_required
begin
if session[:user_id] == nil
redirect_to login_path, :notice => "You are not logged"
elsif User.find(session[:user_id])
return nil
end
rescue ActiveRecord::RecordNotFound
redirect_to login_path, :notice => "No user corresponding in database"
end
end
Hope you can help me.
Cordially,
Aubin
def login_required
begin
if session[:user_id] == nil
redirect_to login_path, :notice => "You are not logged"
elsif User.find_by_id(session[:user_id]).nil?
#rescue ActiveRecord::RecordNotFound (use if u want to use User.find)
redirect_to login_path, :notice => "No user corresponding in database"
return nil
end
end
end
The only reason for this to not work is that ActiveRecord is actually finding a row
User.find(session[:user_id])
Try logging the session[:user_id] and looking into DB using SQL.
On another note, you can use
session[:user_id].nil?
instead of
session[:user_id] == nil
I would rewrite your method as follows:
def login_required
return redirect_to(login_path,
:notice => "You are not logged") if session[:user_id].blank?
user = User.find_by_id(session[:user_id])
return user if user.present?
redirect_to login_path, :notice => "No user corresponding in database"
end

Rails how to redirect if record is not found

I am trying to redirect if the record is not found.
The page is not redirect and I get the error record not found.
My controller:
def index
#link = Link.find(params[:id])
respond_to do |format|
if #link.blank?
format.html { redirect_to(root_url, :notice => 'Record not found') }
else
format.html { render :action => "index" }
end
end
end
What I've been doing is putting this at the end of the method:
rescue ActiveRecord::RecordNotFound
redirect_to root_url, :flash => { :error => "Record not found." }
Even better, put it as an around_filter for your controller:
around_filter :catch_not_found
private
def catch_not_found
yield
rescue ActiveRecord::RecordNotFound
redirect_to root_url, :flash => { :error => "Record not found." }
end
error is generated by Link.find - it raises exception if object was not found
you can simplify your code quite a bit:
def index
#link = Link.find_by_id(params[:id])
redirect_to(root_url, :notice => 'Record not found') unless #link
respond_to do |format|
format.html
end
end
You are on the right track, just capture the RecordNotFound exception:
def index
#link = Link.find(params[:id])
# should render index.html.erb by default
rescue ActiveRecord::RecordNotFound
redirect_to(root_url, :notice => 'Record not found')
end
Very tricky one ... I found a simple solution for this.... This solution works for me
#link = Link.where(:id => params[:id]).first
I am using .first because .where will return an array.Yes, of-course this array has only one element. So, When there is no record with such id, it will return an empty array, assign a blank element to #link ... Now check #link is either blank or not....
Conclusion: No need to provide exception handling for a simple check
It is problem with .find it throws exception when no record exist ... Use .where it will return an empty array
And Sorry for my Bad English
I would prefer to use find_by. find_by will find the first record matching the specified conditions. If the record is not found it will return nil, but does not raise exception, so that you can redirect to other page.
def index
#link = Link.find_by(id: params[:id])
redirect_to(root_url, :notice => 'Record not found') unless #link
end

ruby on rails session information grab

When i run in my page this code :
<% user = User.find(session[:userid]) %>
i get the error :
line #1 raised:
Couldn't find User without an ID
although i have in my authentification in my sessions_controller this :
def create
if user = User.authenticate(params[:username],params[:password])
session[:user_id]= user.id
session[:language_id]= user.language_id
User.find(user.id).update_attributes(:last_login => Time.now)
redirect_to root_path , :notice => (I18n.t :"session.login_success")
else
flash.now[:alert] = (I18n.t :"session.error")
render :action => 'new'
end
end
and the session should contain the userid
In your log-in you set session[:user_id], and you try to find session[:userid] (note the spurious underscore). That's why.
Your controller is looking for params session[:user_id], but in your views it is session[:userid] so it will complain that session[:user_id] is nil.

rescue from ActiveRecord::RecordNotFound in Rails

A user can only edit its own post, so I use the following to check if a user can enter the edit form:
def edit
#post = Load.find(:first, :conditions => { :user_id => session[:user_id], :id => params[:id]})
rescue ActiveRecord::RecordNotFound
flash[:notice] = "Wrong post it"
redirect_to :action => 'index'
end
But it is not working, any ideas what I am doing wrong?
If you want to use the rescue statement you need to use find() in a way it raises exceptions, that is, passing the id you want to find.
def edit
#post = Load.scoped_by_user_id(session[:user_id]).find(params[:id])
rescue ActiveRecord::RecordNotFound
flash[:notice] = "Wrong post it"
redirect_to :action => 'index'
end
You can also use ActionController's rescue_from method. To do it for the whole application at once!
class ApplicationController < ActionController::Base
rescue_from ActiveRecord::RecordNotFound, :with => :record_not_found
def record_not_found
render 'record_not_found' # Assuming you have a template named 'record_not_found'
end
end
Turns out you were using rescue and find(:first) incorrectly.
find :first returns nil if no record matches the conditions. It doesn't raise ActiveRecord::RecordNotFound
try
def edit
#post = Load.find(:first, :conditions => { :user_id => session[:user_id], :id => params[:id]})
if #post.nil?
flash[:notice] = "Wrong post it"
redirect_to :action => 'index'
end
end

Resources