rescue_from ::AbstractController::ActionNotFound not working - ruby-on-rails

I have the following code:
unless Rails.application.config.consider_all_requests_local
rescue_from Exception, with: :render_exception
rescue_from ActiveRecord::RecordNotFound, with: :render_exception
rescue_from ActionController::UnknownController, with: :render_exception
rescue_from ::AbstractController::ActionNotFound, with: :render_exception
rescue_from ActiveRecord::ActiveRecordError, with: :render_exception
rescue_from NoMethodError, with: :render_exception
end
They all work flawless, except ::AbstractController::ActionNotFound
I've also tried
AbstractController::ActionNotFound
ActionController::UnknownAction
error:
AbstractController::ActionNotFound (The action 'show' could not be found for ProductsController):

This similar question suggests that you can no longer catch an ActionNotFound exception. Check the link for workarounds. This suggestion to use a Rack middleware to catch 404s looks the cleanest to me.

To rescue AbstractController::ActionNotFound in a controller, you can try something like this:
class UsersController < ApplicationController
private
def process(action, *args)
super
rescue AbstractController::ActionNotFound
respond_to do |format|
format.html { render :404, status: :not_found }
format.all { render nothing: true, status: :not_found }
end
end
public
# actions must not be private
end
This overrides the process method of AbstractController::Base that raises AbstractController::ActionNotFound (see source).

I think we should catch AbstractController::ActionNotFound in ApplicationController. I have tried following that does not appears to be working.
rescue_from ActionController::ActionNotFound, with: :action_not_found
I have found much cleaner way to handle this exception in ApplicationController. To handle the ActionNotFound Exception in your application, you have to override the action_missing method in your application controller.
def action_missing(m, *args, &block)
Rails.logger.error(m)
redirect_to not_found_path # update your application 404 path here
end
Solution Adapted from: coderwall handling exceptions in your rails application

Overriding process, as described by Grégoire in his answer, seems to work. However, the Rails code says to instead override process_action. That doesn't work, though, because process_action never gets called due to the check for action_name in process.
https://github.com/rails/rails/blob/v3.2.21/actionpack/lib/abstract_controller/base.rb#L115
https://github.com/rails/rails/blob/v3.2.21/actionpack/lib/abstract_controller/base.rb#L161

Related

Need a handler. Pass the with: keyword argument or provide a block

Recently I update my app from Ruby version 2.6.1 to 3.0.1 & I'm using rbenv as a version manager.
but when I try to run the rails server I got an error
=> Booting Puma
=> Rails 6.1.3 application starting in development
=> Run `bin/rails server --help` for more startup options
Exiting
/home/humayun/.rbenv/versions/3.0.1/lib/ruby/gems/3.0.0/gems/activesupport-6.1.3/lib/active_support/rescuable.rb:56:in `rescue_from': Need a handler. Pass the with: keyword argument or provide a block. (ArgumentError)
from /home/humayun/.rbenv/versions/3.0.1/lib/ruby/gems/3.0.0/gems/will_paginate-3.1.8/lib/will_paginate/railtie.rb:67:in `rescue_from'
from /home/humayun/umerfarooq/Alchemy/app/controllers/application_controller.rb:2:in `<class:ApplicationController>'
from /home/humayun/umerfarooq/Alchemy/app/controllers/application_controller.rb:1:in `<main>'
I just read Here about the function which is causing an error on line 56.
applciation_controller.rb
rescue_from Exception, with: :handle_exception
protect_from_forgery prepend: true, with: :exception
before_action :configure_permitted_parameters, if: :devise_controller?
before_action :initialize_api
def not_found
raise ActionController::RoutingError.new('Not Found')
end
def handle_exception(exception = nil)
return render_404 if [ActionController::RoutingError, ActiveRecord::RecordNotFound].include?(exception.class)
render_500
end
I think this is because of depreciation.
can anyone please tell me how to handle these errors?
your handle_exception probably will need a block that render a view or returns a status
as mentioned in the error in app/controllers/application_controller.rb:2 you probably have a rescue_from without an error or a handler you need to follow any of below syntax
class ApplicationController < ActionController::Base
rescue_from User::NotAuthorized, with: :deny_access # self defined exception
rescue_from ActiveRecord::RecordInvalid, with: :show_errors
rescue_from 'MyAppError::Base' do |exception|
render xml: exception, status: 500
end
private
def deny_access
...
end
def show_errors(exception)
exception.record.new_record? ? ...
end
end
as per documentation here https://apidock.com/rails/ActiveSupport/Rescuable/ClassMethods/rescue_from
------- Update:
This is due to the will_paginate gem that you are using that overrides the rescue_from method in your controller alongside the new ruby updates that change the behavior around the keyword attribute
if your base controller include ControllerRescuePatch you might be able to remove it and this will fix it but not sure what will happen to your pagination.
Otherwise, hold off the ruby update until the will_paginate update their code to fix this

Redirect to 404 when rails app crash

i am new in rails. I want to add redirection to "404 page" whenever my "app crashed" or "page not found" or in case of "exception".
If someone have good tutorials please share with me or provide some simple solution.
I read this Rails_admin redirect to 404 but it did not solved my problem.
The Rails guide has a chapter about exception handling. You can use rescue_from to run a custom method, when an exception is raised. The following example is from that guide and should be added to your application_controller:
rescue_from ActiveRecord::RecordNotFound, with: :record_not_found
private
def record_not_found
render plain: "404 Not Found", status: 404
end
You may want to change the exception type to whatever exceptions you want to catch. I guess that you can also catch from every exception by:
rescue_from StandardError, with: :record_not_found
Note: I would consider this a bad practise and would instead just design my 500 error page to look the same then my 404 page.
I have this method in my application_controller.rb
def not_found
raise ActionController::RoutingError.new('Not Found')
end
and then in any controller when I do a find:
#model = Model.find_by(id: params[:id]) or not_found
I'm using Rails 2 at the moment though so it might be slightly different for your version.
For 404 i.e. page not found, we can redirect page to custom route.
For this you need create new route,
match "*path", to: "handle_errors#page_not_found", via: :all
which will redirect to page_not_found action of handle_errors controller.
Obviously you need to create a new controller handle_errors
For any other exception occurred in app, you can handle it using some customer method in application controller as
rescue_from ActiveRecord::RecordNotFound, :with => :record_not_found_error_handler
rescue_from ActiveRecord::RecordNotUnique, :with => :default_error_handler
as so on ...
with defination of methods as,
def default_error_handler(e)
render 'handle_errors/page_404', :status => 404
end
def record_not_found_error_handler(e)
render 'handle_errors/record_not_found'
end

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.

Rescue From If JSON

I'd like to rescue from a RecordNotFound exception if, and only if, the request is JSON. Now if I was doing this for a skip_before_action, I would do the below:
skip_before_action :verify_authenticity_token, if: :json_request?
Is there syntax for this in rescue_from? Something like:
rescue_from ActiveRecord::RecordNotFound, :with => :record_not_found, if: :json_request?
Helper method:
protected
def json_request?
request.format.json?
end
I am assuming if the request is not JSON then you want to raise? If so you should be able to do this
rescue_from ActiveRecord::RecordNotFound { request.format.json? ? record_not_found : super }
OR
rescue_from ActiveRecord::RecordNotFound, with: lambda{|e| request.format.json? ? record_not_found(e) : raise(e) }
These will have identical impact because if a block is given it assigns it to the options[:with] where as if with: is supplied it uses this as the block and ignores any other block passed to it
rescue_from takes a splat argument called *klasses and a block. It then parses *klasses to determine the options passed in of which it only cares about :with. It then applies the :with block to the key(s) which will represent exception class names to handle.
There is no additional options that will be acknowledged.
Please be advised I have not tested this
You could do:
rescue_from ActiveRecord::RecordNotFound do
record_not_found if json_request?
end
I dont think there is another syntax for that exact case :-(

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