rescue from ActiveRecord::RecordNotFound in Rails - ruby-on-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

Related

display braintree errors on fail

hi i am trying to get my braintree account to display errors when creating a transaction but it doesn't appear to be working
- flash.each do |key, value|
%div{:class => "alert alert-#{key}"}= value
def update
result = Braintree::Transaction.sale(
:amount => params[:amount_to_add].to_f,
# :order_id => "order id",
:customer_id => customer.customer_cim_id,
:tax_amount => (params[:amount_to_add].to_f / 11).round(2),
:options => {
:submit_for_settlement => true
}
)
if result.success?
logger.info "Added to #{params[:amount_to_add].to_f} to #{customer.first_name} #{customer.last_name} (#{customer.customer_cim_id})"
customer.store_credit.add_credit(params[:amount_to_add].to_f)
redirect_to myaccount_store_credit_path
# , :notice => "Successfully updated store credit."
else
result.errors.each do |error|
puts error.message
customer.errors.add(:base, error.message)
render :show, :notice => error.message
end
end
end
I believe the reason you're probably unable to see the errors is because of the :notice option on your render method, which is redundant because render doesn't seem to be using the :notice option, only redirect_to. You may just add the errors to your to your flash, but note that in your view you have to loop through the errors within the flash to render it.
Another way I would think you do this though is add the payment method to your User model
class User|Customer
...
def process_braintree_payment(amount)
result = Braintree::Transaction.sale(
:amount => amount.to_f,
# :order_id => "order id",
:customer_id => customer_cim_id,
:tax_amount => (amount.to_f / 11).round(2),
:options => {
:submit_for_settlement => true
}
)
add_braintree_errors(result.error) unless result.success?
end
def add_braintree_errors(error_object)
error_object.each do |error|
errors.add(:braintree, error.message)
end
end
end
class XController
def update
#customer.process_braintree_payment(params[:amount_to_add])
if #customer.errors.empty?
logger.info "Added to #{params[:amount_to_add].to_f} to #{#customer.first_name} #{#customer.last_name} (#{#customer.customer_cim_id})"
#customer.store_credit.add_credit(params[:amount_to_add].to_f)
redirect_to myaccount_store_credit_path
# , :notice => "Successfully updated store credit."
else
render :show
end
end
end
In your view, you have access to the #customer variable or better you could store the error object in the ActionController#flash, note however, using the same keys for your flash messages, would overwrite the previous value.

before_filter not being called rails?

I have a custom method outside the generic CRUD in my friendships controller called request. My problem is that I have before_filter :require_auth set to run before all methods in my FriendshipsController.
It was working fine except for the request method.
(This makes me think it has something to do with it being out of normal CRUD?)
When I call the request method now it skips the :require_auth and goes straight to the request method which is giving me errors as I define some variables in :require_auth that I need inside the request method.
Here is my FriendshipsController:
class FriendshipsController < ApplicationController
skip_before_filter :verify_authenticity_token, :only => [:create]
before_filter :require_auth
def create
#friendship = Friendship.new(user_id: params[:user_id], friend_id: params[:friend_id], status: params[:status])
if #friendship.save
render :status => 200, :json => {:message => "Friendship Created"}
else
render :status => 500, :json => { :message => "Problem creating friendship" }
end
end
def request
# friendID = params[:friend_id]
# userID = #currentuser.id
binding.pry
#userid = #currentuser.id
#friendid = params[:friend_id]
unless (#userid == #friendid || Friendship.exists?(user_id: #userid,friend_id: #friendid))
create(:user_id => userID, :friend_id => friendID, :status => 'pending')
create(:user_id => friendID, :friend_id => userID, :status => 'requested')
end
end
end
Here is my ApplicationController where I define require_auth:
class ApplicationController < ActionController::Base
# Prevent CSRF attacks by raising an exception.
# For APIs, you may want to use :null_session instead.
# protect_from_forgery with: :null_session
def require_auth
binding.pry
auth_token = request.headers["HTTP_AUTH_TOKEN"]
#user = User.find_by_auth_token(auth_token)
if #user.auth_token
#currentuser = #user
else
render :status => 401, :json => {:error => "Requires authorization"}
return false
end
end
end
Chris Peters was right in the comments. My problem was that rails already has request defined. I simple changed the method name to something else and it works.
Thanks.

How to display custom error message for ActiveRecord::JDBCError in Ruby on Rails?

I have a HTML table in my View to create, update and delete the records for a table called Mast_Freq.
The Primary key of this table is referenced by foreign key 'MastFreq' in table 'AssFreq' and some other tables. So, When I try to delete some record in the MastFreq I got the error message like the following.
ActiveRecord::JDBCError: [Sybase][JDBC Driver][SQL Anywhere]Primary key for row in table 'MastFreq' is referenced by foreign key 'MastFreq' in table 'AssFreq': DELETE FROM "MastFreq" WHERE "MastFreq"."Frequency_Code" = 'A'
How can i display a custom error message to the user instead of this error message. This record should not be delete.
Frequency_Code is the primary key of the table MastFreq.
Controller:
----------
class Asset::MastFreqsController < AssetController
rescue_from ActiveRecord::JDBCError, :with => :jdbc_error
def destroy
begin
#asset_master_frequency = Asset::MastFreq.find(params[:id])
result = #asset_master_frequency.destroy
respond_to do |format|
format.html{ redirect_to :action => :index}
format.json{ render :json => result}
end
rescue ActiveRecord::JDBCError
end
end
protected
def jdbc_error(exception)
flash[:error] = "You Cannot delete this Frequency Code" + exception.inspect
redirect_to asset_master_frequencies_path
end
end
You can rescue from errors in controllers or models by enclosing functionality in a begin/rescue/end block, as described by #user2463570.
But since you want to present a message to your user you can catch all errors of a specific type in a controller by adding the following line:
rescue_from ActiveRecord::JDBCError, :with => :jdbc_error
def jdbc_error(exception)
flash[:error] = 'There was an error.......' + exception.inspect
redirect_to root_url
end
And show the error flash on the page
<%= flash[:error] %>
Some more information here: ActiveSupport/Rescuable/ClassMethods.html
Included your code:
Controller:
----------
class Asset::MastFreqsController < AssetController
rescue_from ActiveRecord::JDBCError, :with => :jdbc_error
def destroy
#asset_master_frequency = Asset::MastFreq.find(params[:id])
result = #asset_master_frequency.destroy
respond_to do |format|
format.html{ redirect_to :action => :index}
format.json{ render :json => result}
end
end
protected
def jdbc_error
flash[:error] = 'You Cannot delete this Frequency Code'
redirect_to asset_master_frequencies_path
end
end
you can try this
begin
===
your code
==
rescue ActiveRecord::JDBCError
puts "your custom error messages"
end

How to avoid the error on nil object

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.

Passing Values to Controllers

I'm trying to allow users to 'favorite' links (that is, create a new Favorite record with their user_id and the link_id) This is what I have so far..
When I click favorite (as a user), the new record is assigned to the user_id but the link_id field is nil. How can I pass the link_id into my FavoritesController?
My View Code
Added Link Model Code
class FavoritesController < ApplicationController
def create
#user = User.find(session[:user_id])
#favorite = #user.favorites.create :link_id => params[:id]
redirect_to :back
end
end
The Favorite model belongs to :user and :link
Note: I've also tried this but when I click 'favorite', there's an error "Couldn't find Link without an ID."
Update
<%= link_to "Favorite", :controller => :favorites, :action => :create, :link_id => link.id %>
with
class FavoritesController < ApplicationController
def create
#user = User.find(session[:user_id])
#favorite = #user.favorites.create :link_id => :params[:link_id]
redirect_to :back
end
end
Returns "can't convert Symbol into Integer"
app/controllers/favorites_controller.rb:4:in []
app/controllers/favorites_controller.rb:4:in create
I've tried forcing it into an Integer several ways with .to_i
You could try the following
In your view:
<%= link_to "Favorite", :controller => :favorites, :action => :create, :link_id => link.id %>
In your controller:
class FavoritesController < ApplicationController
def create
#user = User.find(:first, :conditions => ["id = ?", session[:id]])
#favorite = #user.favorites.create
#favorite.update_attributes(:link_id => params[:link_id])
redirect_to :back
end
end
Just as a side note, when finding records, i tend to use:
.find(:first, :conditions => ["id = ?", session[:id]])
as it will escape most stuff submitted by user and returns one record.
I have broken the steps up in your controller, but you could combine them into one like this:
def create
#user = User.find(:first, :conditions => ["id = ?", session[:id]])
#favorite = #user.favorites.create(:link_id => params[:link_id])
redirect_to :back
end
hopefully that should work
You should try:
#user = User.find(session[:user_id])
#favorite = Favorite.create :link_id => params[:id]
#favorite.user = #user
It fails because params[:id] is nil. Put
throw params
at the beginning of the create method and check what you have available there. Please psot also the code in your view.

Resources