In Rails, is there a way to display different error messages on a production rails server (a nice graphic) vs a development server (detailed error information, stack trace, etc.)?
Found one solution. In ApplicationController, add:
rescue_from Exception, :with => :rescue_all_exceptions if RAILS_ENV == 'production'
def rescue_all_exceptions(exception)
case exception
# do production-ey exception stuff
end
end
I'd be interested to hear other options...
Related
I'm looking to gracefully handle AWS Aurora's failover mechanism in a Rails 6 app.
Other solutions I've found swap out a specific Rack middleware adapter with one that will reset all ActiveRecord connections if a specific type of exception is raised. That middleware has been removed in Rails 6 so this solution no longer works.
The exception that gets raised is an ActiveRecord::StatementInvalid: "PG::ReadOnlySqlTransaction: ERROR: cannot execute UPDATE in a read-only transaction".
Would the following be an idiomatic way to rescue this exception and reset the connection pool as needed?
class ApplicationController < ActionController::Base
rescue_from ActiveRecord::StatementInvalid, with: :check_read_only_failover
private
def check_read_only_failover(exception)
if /Lost connection|gone away|read-only/.match?(exception.message)
ActiveRecord::Base.clear_all_connections!
end
end
(The regex above was lifted from the linked solution; I have no reason to believe the error condition has changed.)
I'm trying to use exception_notification for the first time. I watched the Railscast and followed instructions from the author in http://smartinez87.github.io/exception_notification/. Everything seems to work fine with some sort of exceptions but not with others.
I tested and received email error notificatios from my dev environment with errors such as "An ActionView::Template::Error occurred in static_pages#home:". But, there are some Exceptions such as RoutingException and RecordNotFound that are not being catched by ExceptionNotification, and I don't know why, as I have not any rescue_from strategy of any kind in my application_controller.
I'm using rails 3.2.12 and checked the middleware stack array, and I can see ExceptionNotification is just the last one, and it seems that some kind of exceptions does not go their way down the stack, so Exception Notification is not aware of them.
So, the question are: what am i doing wrong? what is the difference between ActionController::RoutingError or ActiveRecord::RecordNotFound which are not catched by ExceptionNotification and ActionView::Template::Error which is catched and causes Exception Notification to send the notification email to my inbox.
Thanks in advance
These exception types are being ignored as part of the default configuration of that gem. See line 25 here: https://github.com/smartinez87/exception_notification/blob/master/lib/exception_notifier.rb which currently reads:
##ignored_exceptions = %w{ActiveRecord::RecordNotFound AbstractController::ActionNotFound ActionController::RoutingError ActionController::UnknownFormat}
You can override this behavior in your environment file (i.e. development.rb, etc).
Example to notify on ALL errors:
config.middleware.use ExceptionNotifier,
ignore_exceptions: []
Example to add RuntimeError to the default ignore list:
config.middleware.use ExceptionNotifier,
ignore_exceptions: ExceptionNotifier.default_ignore_exceptions + [RuntimeError]
In the production environment configuration I can't seem to find a configuration parameter to tell the server that when an ActiveRecord Class.find() throws an exception, that it should really be an exception. In development mode, it throws an ActiveRecord::RecordNotFound exception, but in production it rescues it and renders a 404. I seem to remember this being something you could turn on/off? I would rather not monkey patch the 404 which is the only solution I have seen so far.
The .find(id) method should be used whenever you want an exception to be thrown if the id cannot be found as described in the documentation. If you don't want an exception to be thrown, you should use .find_by_id(id).
https://github.com/rails/rails/blob/4-0-stable/activerecord/lib/active_record/railtie.rb#L26
adds a mapping
'ActiveRecord::RecordNotFound' => :not_found
asking action_dispatch to rescue 'ActiveRecord::RecordNotFound' with :not_found response.
Doing -
YourAppName::Application.config.action_dispatch.rescue_responses.delete('ActiveRecord::RecordNotFound')
in your initializer might get what you're expecting.
I am upgrading my application from Rails 2.3.14 to Rails 3.0.1
I always get this error if there is any error in the view
Development mode eh? Here is the error - #<ActionView::Template::Error: ActionView::Template::Error>
app/controllers/application_controller.rb:158:in `render_500'
This is the code written for render_500 in application_controller.rb
def render_500(error)
if Rails.env.production?
render :file => Rails.root.join('public','access_denied.html'), :status => 500
else
raise Exception, I18n.t('str_error')+" - #{error.inspect}"
end
end
I am debugging the code now by writing puts statements.
Please help me with a solution. Thanks in advance.
Well, the application is behaving properly. The Development mode eh? Here is the error is the string inside I18n.t('str_error'). You are just raising an exception, and rendering nothing, just this string, so there is no problem.
Template error can be many things, but the one more common is assets that are not precompiled and stuff. Do a little research on this, maybe it is the problem, but keep in mind that the code provided is working as expected.
I have been happily using the DelayedJob idiom:
foo.send_later(:bar)
This calls the method bar on the object foo in the DelayedJob process.
And I've been using DaemonSpawn to kick off the DelayedJob process on my server.
But... if foo throws an exception Hoptoad doesn't catch it.
Is this a bug in any of these packages... or do I need to change some configuration... or do I need to insert some exception handling in DS or DJ that will call the Hoptoad notifier?
In response to the first comment below.
class DelayedJobWorker < DaemonSpawn::Base
def start(args)
ENV['RAILS_ENV'] ||= args.first || 'development'
Dir.chdir RAILS_ROOT
require File.join('config', 'environment')
Delayed::Worker.new.start
end
Try monkeypatching Delayed::Worker#handle_failed_job :
# lib/delayed_job_airbrake.rb
module Delayed
class Worker
protected
def handle_failed_job_with_airbrake(job, error)
say "Delayed job failed -- logging to Airbrake"
HoptoadNotifier.notify(error)
handle_failed_job_without_airbrake(job, error)
end
alias_method_chain :handle_failed_job, :airbrake
end
end
This worked for me.
(in a Rails 3.0.10 app using delayed_job 2.1.4 and hoptoad_notifier 2.4.11)
Check out the source for Delayed::Job... there's a snippet like:
# This is a good hook if you need to report job processing errors in additional or different ways
def log_exception(error)
logger.error "* [JOB] #{name} failed with #{error.class.name}: #{error.message} - #{attempts} failed attempts"
logger.error(error)
end
I haven't tried it, but I think you could do something like:
class Delayed::Job
def log_exception_with_hoptoad(error)
log_exception_without_hoptoad(error)
HoptoadNotifier.notify(error)
end
alias_method_chain :log_exception, :hoptoad
end
Hoptoad uses the Rails rescue_action_in_public hook method to intercept exceptions and log them. This method is only executed when the request is dispatched by a Rails controller.
For this reason, Hoptoad is completely unaware of any exception generated, for example, by rake tasks or the rails script/runner.
If you want to have Hoptoad tracking your exception, you should manually integrate it.
It should be quite straightforward. The following code fragment demonstrates how Hoptoad is invoked
def rescue_action_in_public_with_hoptoad exception
notify_hoptoad(exception) unless ignore?(exception) || ignore_user_agent?
rescue_action_in_public_without_hoptoad(exception)
end
Just include Hoptoad library in your environment and call notify_hoptoad(exception) should work. Make sure your environment provides the same API of a Rails controller or Hoptoad might complain.
Just throwing it out there - your daemon should require the rails environment that you're working on. It should look something along the lines of:
RAILS_ENV = ARGV.first || ENV['RAILS_ENV'] || 'production'
require File.join('config', 'environment')
This way you can specify environment in which daemon is called.
Since it runs delayed job chances are daemon already does that (it needs activerecord), but maybe you're only requiring minimal activerecord to make delayed_job happy without rails.