On a rails 2.3 application I want to show the detailed error exception information if #user.is_admin? is true. Otherwise show the generic error on 500.rhtml.
What is the best way to approach this?
In your ApplicationController, rescue_from StandardError and in that method, render a view where you print out the exception message and backtrace.
class ApplicationController
rescue_from StandardError, :with => :show_exception
def show_exception(e)
#e = e
render "global/show_exception"
end
end
# app/views/global/show_exception.html.erb
<h1><%= #e.message %></h1>
<pre>
<%= #e.backtrace %>
</pre>
That should do the trick. The other option is to have a before_filter that checks to see if the user is an admin, and then sets the application configuration for consider_all_requests_local to true if so.
before_filter { Rails.application.config.consider_all_requests_local = current_user.try(:is_admin?) }
Related
In my Rails 7 app I'm using several 3rd parties API to provide fetch data. Each time I'm receiving an error I've to rescue with nil to still be able to display redirect user to desired page, e.g.:
# lib/custom_api.rb
module CustomApi
extend self
def fetch_transactions(user_id)
client.transactions.list(user_id:)
# rescue from custom error
rescue Errors::NotFoundError
nil
end
end
# transactions_controller.rb
class TransactionsController < ApplicationController
def index
transaction_list = CustomApi.fetch_transactions(current_user.id)
if transaction_list
#transactions = transaction_list
else
#transactions = transaction_list
flash[:alert] = 'No transactions'
end
end
end
# views/transactions/index.html.erb
<%= turbo_frame_tag 'transactions' do %>
<%= render partial: 'table_headers' %>
<%= render Transactions::TableComponent.new(records: #transactions) if #transactions %>
<% end %>
Everything works well but I've got 50 endpoints where I need to include rescue Errors::NotFoundError and I don't think it's super sufficient to to repeat this line 50 times. Is there a way to avoid that?
In general, using Rescuable is the Rails' way for rescuing from exception in a centralized manner.
Add this to your ApplicationController:
rescue_from Errors::NotFoundError, with: :handle_not_found_error_from_external_api
private
def handle_not_found_error_from_external_api
# handle the error in a generalized way, for example, by returning a response
# that renders a modal or a toast.
end
And remove these lines from your CustomApi:
# rescue from custom error
rescue Errors::NotFoundError
nil
Im trying to test if the format send through the request url is json or not?
so in link_to I sent the format like this
<%= link_to "Embed", {:controller=>'api/oembed' ,:action => 'show',:url => catalog_url, format: 'xml'} %>
In the relevant controller I catch the param and raise the exception like this
format_request = params[:format]
if format_request != "json"
raise DRI::Exceptions::NotImplemented
end
but the exception wont display instead the server simply ran into internal error but if I changed the param inside the controller then exception displayed so if the url is like this
<%= link_to "Embed", {:controller=>'api/oembed' ,:action => 'show',:url => catalog_url, format: 'json'} %>
format_request = "xml"
if format_request != "json"
raise DRI::Exceptions::NotImplemented
end
why 501 exception does not triggered if I send the format as xml in url? Im doing it for the testing purpose that in case if someone send the request with wrong format 501 expetion show up
Use ActionController::MimeResponds instead of badly reinventing the wheel:
# or whatever your base controller class is
class ApplicationController < ActionController::API
# MimeResponds is not included in ActionController::API
include ActionController::MimeResponds
# Defining this in your parent class avoids repeating the same error handling code
rescue_from ActionController::UnknownFormat do
raise DRI::Exceptions::NotImplemented # do you really need to add another layer of complexity?
end
end
module Api
class OembedController < ApplicationController
def oembed
respond_to :json
end
end
end
If you don't use respond_to Rails will implicitly assume that the controller responds to all response formats. But if you explicitly list the formats you respond to with a list of symbols (or the more common block syntax) Rails will raise ActionController::UnknownFormat if the request format is not listed. You can rescue exceptions with rescue_from which lets you use inheritance instead of repeating yourself with the same error handling.
As #max mentions, sending the format: 'xml' is unnecessary because Rails already knows the format of the request.
<%= link_to "Embed", {:controller=>'api/oembed' ,:action => 'show',:url => catalog_url } %>
In the controller:
def oembed
respond_to do |format|
format.json { # do the thing you want }
format.any(:xml, :html) { # render your DRI::Exceptions::NotImplemented }
end
end
Or if you want more control you could throw to a custom action:
def oembed
respond_to do |format|
format.json { # do the thing you want }
format.any(:xml, :html) { render not_implemented }
end
end
def not_implemented
# just suggestions here
flash[:notice] = 'No support for non-JSON requests at this time'
redirect_to return_path
# or if you really want to throw an error
raise DRI::Exceptions::NotImplemented
end
If you really want to reinvent the wheel (it's your wheel, reinvent if you want to):
I'd rename format to something else, it's probably reserved and might give you problems
<%= link_to "Embed", {:controller=>'api/oembed' ,:action => 'show',:url => catalog_url, custom_format: 'xml'} %>
Then, in your controller, you need to explicitly allow this parameter:
def oembed
raise DRI::Exceptions::NotImplemented unless format_params[:custom_format] == 'json'
end
private
def format_params
params.permit(:custom_format)
end
So I handle exceptions with an error controller to display dynamic content to my users in production. I have it in my route file to do:
# Errors
%w( 404 422 500 ).each do |code|
get code, :to => "errors#show", :code => code
end
The only problem is now that I'm routing on errors such as that I lose information in my controller when I want to notify Airbrake. How can I maintain the exception information and send it to Airbrake on a 500? Right now all I get is the env that was occurring at the time of the exception which is less helpful for debugging purposes.
class ErrorsController < ApplicationController
def show
notify_airbrake(env)
render status_code.to_s, :status => status_code
end
protected
def status_code
params[:code] || 500
end
end
Are you handling an error by redirecting to a URL like http://your.site/500? That will be just an HTTP request like any other, losing the exception context you're after. Instead, you probably want to be using ActionController's Rescue functionality. It would look like this:
class ApplicationController < ActionController::Base
rescue_from StandardError, with: :render_error
private
def render_error(error)
notify_airbrake(error)
render text: 500, status: 500
end
end
You can add multiple rescue_from declarations to handle different kinds of error, like the ActiveRecord::RecordNotFound from the Rails guide's example.
So, I have a catch all route that is going to act like a vanity url piece. So, I have a call:
def show_profile
url=VanityUrl.find_by_url!(params[:username])
...
end
I'm seeing somewhat different info for how I should be handling the ActiveRecord::NotFound error. I just want it to return a template in shared/404.html.erb
How would I do this?
You can to use in the application controller
rescue_from ActiveRecord::RecordNotFound, :with => :record_not_found
def record_not_found
# logger, flash[:error], render, redirect, etc if RAILS_ENV == "production"
end
As I understood, if record not found, we need to show /shared/404.html.erb.
def show_profile
url = VanityUrl.find_by_url!(params[:username]) rescue nil
unless url
render "#{RAILS_ROOT}/shared/404.html.erb"
return
end
end
Should work.
Reference: http://guides.rubyonrails.org/layouts_and_rendering.html
I have this code somewhere in my controller:
raise PermissionDenied
When this is executed, I want to show a custom error page written in HAML, rather than the default NameError page.
Can anyone help me? Thanks.
The rescue_from method can be used for global exception handling.
Change theapp/controller/application_controller.rb file to add the exception handler.
class ApplicationController < ActionController::Base
rescue_from ::PermissionDenied, :with => :render_permission_denied
def render_permission_denied(e)
#error = e # Optional, accessible in the error template
log_error(e) # Optional
render :template => 'error_pages/permission_denied', :status => :forbidden
end
end
Now add a haml file called permission_denied.html.haml in app/views/error_pages directory.
%h1 Permission Denied!
%p #{#error.message}
Refer to the rails documentation for more details.