Rails - Execute javascript code on cancan access denied - ruby-on-rails

Let's say I have a rescue code on my application controller for handling access denied from cancan, like this:
class ApplicationController < ActionController::Base
rescue_from CanCan::AccessDenied do |exception|
#handle the exception
end
end
What I would like to do is, when the exception is raised, to show a popup to the user. But for that I should run a javascript code. How could I achieve that? Thanks in advance!

Related

Precedence of error handlers: rescue_from vs rescue in a method

In my application_controller.rb I have the following line
rescue_from Pundit::NotAuthorizedError, with: :user_not_authorized
Now, in one method, I would like to handle that specific error differently and I've added this to one method in a controller.
class MyClass < ApplicationController
def my_method
# raising the Pundit::NotAuthorizedError in the method
authorize resource, :my_method?
rescue Pundit::NotAuthorizedError
# code on how to deal with the error
end
end
If I execute the code, the error handler from application_controller.rb will be handling my error instead of the error handler in the method.
So my question is, what is the precedence of the error handlers and is there any way I can change this, so that the error is handled in the method and not globally?
Please forget my previous answer, I myself made a mistake when reproducing your issue. In deed I am not able to reproduce it.
Please have a look at this little demo app I created:
https://github.com/andi-dev/rescue-handler-demo/blob/master/app/controllers/peas_controller.rb
The rescue_from handler is not executed, and the browser shows what I render from the rescue block within the action-method.

How can I re-raise a Ruby exception in a Rails rescue_from statement?

My Rails 4 app uses RocketPants for its JSON API and Pundit for authorization.
I have code in my /app/controllers/api/v1/base_controller.rb file to handle errors from Pundit. Whenever a user isn't authorized to update a resource, Pundit throws a NotAuthorizedError exception and I rescue it with my user_not_authorized method:
class API::V1::BaseController < RocketPants::Base
include Pundit
version 1
rescue_from Pundit::NotAuthorizedError, with: :user_not_authorized
def user_not_authorized
error! :forbidden
end
end
When I call the error! method that RocketPants provides from my exception handler, I expect to get a JSON response like this:
{
"error": "forbidden",
"error_description": "The requested action was forbidden."
}
Instead, however, calling error! just immediately blows up the request:
Completed 500 Internal Server Error in 143ms
RocketPants::Forbidden - RocketPants::Forbidden:
rocket_pants (1.13.1) lib/rocket_pants/controller/error_handling.rb:44:in `error!'
app/controllers/api/v1/base_controller.rb:61:in `user_not_authorized'
Full stack trace here.
Why isn't the error! method doing what it should when called from my Pundit exception handler?
If I put error! :forbidden in the middle of my controller action, it works as expected.
For context, the controller that inherits from base_controller.rb and calls Pundit's authorize method looks like this:
class API::V1::MealsController < API::V1::BaseController
before_filter :find_entity
def create
meal = #entity.meals.build(meal_params)
authorize(#entity, :update?)
if meal.save
expose meal, status: :created
else
expose meal.errors, status: 422
end
end
end
Apparently raising exceptions in a rescue_from is a bad idea and according to the Rails docs, exceptions raised in a handler are not bubbled up:
Exceptions raised inside exception handlers are not propagated up.
Docs: http://api.rubyonrails.org/classes/ActiveSupport/Rescuable/ClassMethods.html
Instead of re-raising RocketPants' exception, I'm simply creating and returning the JSON error message myself:
def user_not_authorized
# error! :forbidden
head 403
error = { error: 'Action not allowed.', error_description: 'Sorry, you are not allowed to perform this action.'}
expose error
end
This works!
UPDATE
I've since found an even cleaner solution: just map the Pundit exception to the RocketPants exception. This means that whenever a Pundit::NotAuthorizedError error is raised it'll be treated as a RocketPants::Forbidden error.
Got the entire solution down to a single line of code at the top of base_controller.rb:
map_error! Pundit::NotAuthorizedError, RocketPants::Forbidden
No handler required.

Rails: rescue_from and rethrow

I want to track my user's exception with mixpanel so I added this code in my application_controller:
class ApplicationController < ActionController::Base
rescue_from Exception do |exception|
if Rails.env.production?
tracker.track(session[:mixpanel_unauth_id], 'Exception', {:exception => exception.to_s})
rescue_action_without_handler(exception)
end
end
I just want to intercept the error for mixpanel than the error must be re thrown normally.
In production a have a method not found error on rescue_action_without_handler
In development I have a blank white page when an error happen.
How to solve this problem?
I use Rails 3.2

How to catch exceptions in controller's actions properly?

There is the following code:
def index
#posts = User.find_by(login: params[:user_id]).posts
end
As you can see this code can generate exception if there is no user with some login (nil pointer exception). How can I catch this exception and handle it properly? I know how to catch exceptions in Ruby, but I want to know how to do in a good Rails style. The same problem may occur in different controllers - may be I should create an action wrapper, catch exception and render 500 error?
The easiest way is to use ApplicationController's rescue_from:
class ApplicationController < ActionController::Base
rescue_from ActiveRecord::RecordNotFound, with: :record_not_found
private
def record_not_found
render 'my/custom/template', status: 404
end
end
def index
#posts = User.find_by!(login: params[:user_id]).posts
rescue ActiveRecord::RecordNotFound => error
# handle user not found case
end
You can also use rescue_from http://edgeapi.rubyonrails.org/classes/ActiveSupport/Rescuable/ClassMethods.html if you want to catch the error globally for the controller.

Can I execute a method everytime I get an exception on Rails 3?

I tried almost everything on web, all I want is to call a method whenever an exception like "ActiveRecord::RecordNotFound" or "No route matches" appears.
Rescues from ApplicationController does not work, but why?
class ApplicationController < ActionController::Base
protect_from_forgery
private
def self.send_report_error(message)
Notifier.page_failure(message).deliver
end
rescue ActiveRecord::RecordNotFound
# handle not found error
send_report_error ActiveRecord::RecordNotFound.to_s
rescue ActiveRecord::ActiveRecordError
# handle other ActiveRecord errors
send_report_error ActiveRecord::ActiveRecordError.to_s
rescue # StandardError
# handle most other errors
send_report_error "common error"
rescue Exception
# handle everything else
send_report_error "common exception"
end
Use rescue_from. For example:
class ApplicationController < ActionController::Base
rescue_from ActiveRecord::RecordNotFound, :with => :send_report_error
end
http://api.rubyonrails.org/classes/ActiveSupport/Rescuable/ClassMethods.html

Resources