In my Rails 3 app, I am fetching path_info by:
Rails.application.routes.recognize_path(url, { :method => request.request_method }) rescue {}
If a crawler hits a URL like "http://localhost:3000/admin_", the above code raises following error:
LoadError: Expected /Users/user/myRailsApp/app/controllers/admin_controller.rb to define Admin_Controller
from /Users/user/.rvm/gems/ree-1.8.7-2012.02/gems/activesupport-3.0.20/lib/active_support/dependencies.rb:492:in `load_missing_constant'
I have two questions:
Why is rescue not working? If I change it to rescue LoadError => e, exception is handled gracefully.
Is there any other alternative rather than rescuing such exception(s)?
If you omit the exception type, by default rescue will rescue only StandardError exceptions and subclasses.
LoadError doesn't inherit from StandardError:
LoadError.ancestors
=> [LoadError, ScriptError, Exception, Object, Kernel, BasicObject]
Therefore, the one-line rescue pattern doesn't work with a LoadError.
Related
If a template causes an ActiveRecord::RecordNotFound exception to be raised, the original exception is swallowed up by ActionView and turned into an ActionView::Template::Error.
It seems that in Rails 5 there was an original_exception method but that appears to be gone in Rails 6.
I'd like to be able to inspect the cause of the ActionView::Template::Error so I can show better contextual errors.
Is there any way to do so?
If you catch the ActionView::Template::Error, there should be a #cause method defined on it which returns the original exception. Example:
begin
begin
raise ArgumentError
rescue
raise RuntimeError
end
rescue => e
puts "#{ e } caused by #{ e.cause }"
end
prints
RuntimeError caused by ArgumentError
I have the following code in Rails routing:
class LegacyRedirector
InvalidUrlError = Class.new(ActionController::RoutingError)
def call(params, request)
URI.parse(request.path)
rescue URI::InvalidURIError => e
raise InvalidUrlError.new(e.message)
end
end
# routes.rb
match 'a', to: redirect(LegacyRedirector.new)
This is for catching invaild URLs. However when I test it in browser for curl, it would still display URI::InvalidURIError, not my new error class. It seems the rescue block was never reached, yet I am sure I am rescuing the correct type. How can that be?
URI::InvalidURIError at /twitter/typeahead-js/wikis/home[
=========================================================
> bad URI(is not URI?): "/twitter/typeahead-js/wikis/home["
lib/gitlab/routing.rb, line 31
------------------------------
``` ruby
> 31 URI.parse(request.path)
32 rescue URI::InvalidURIError => e
33 raise InvalidUrlError.new(e.message)
34 end
```
One possible cause could be better_errors.
If an error is raised in a rescue block, its cause would be the original error. better_errors displays that cause instead, meaning the backtrace will not be in the rescue block. This gives you the illusion that it is never rescued.
This was recently fixed, see https://github.com/BetterErrors/better_errors/pull/459 for more details
I am attempting to add puffing-billy to a Rails app by following the instructions here.
Running the test suite raises:
in `require': cannot load such file -- capybara/webkit (LoadError)
I am using Poltergeist not Webkit, and so don't need to load this file.
The error originates from the following line in puffing-billy
# /lib/billy/browsers/capybara.rb
DRIVERS = {
poltergeist: 'capybara/poltergeist',
webkit: 'capybara/webkit',
selenium: 'selenium/webdriver'
}
def self.register_drivers
DRIVERS.each do |name, driver|
require driver rescue next # this line should be rescued
send("register_#{name}_driver")
end
end
What could prevent require driver from being rescued and cause this error, and what is a methodical approach to debug this?
In general it's a bad idea to use an inline rescuse in Ruby (having rescue be at the end of the line). Here is a nice article w/ more details: https://www.new-bamboo.co.uk/blog/2015/09/23/dont-inline-rescue-in-ruby/
Inline rescue and a "unfiltered" rescue (without specifying the type of error you want caught) both catch any exceptions that inherit from StandardError LoadError is not a descendant of StandardError so it's is not caught by your inline rescue.
Here is a chart of error hierarchy in Ruby:
http://blog.honeybadger.io/understanding-the-ruby-exception-hierarchy/
So here is your code modified so it will work and also not catch unintentional errors:
DRIVERS.each do |name, driver|
begin
require driver
send("register_#{name}_driver")
rescue LoadError
# This skips to the next driver
# It would be nice to add logging here to notify that the driver was skipped
end
end
I'm trying to figure out the best way to catch a specific error thrown AND the error's message in Ruby on Rails. My use case is that I encounter a timeout error every now and then which is thrown with a general error and I want to treat the timeout error differently than other errors within the same general error. I'm not sure what other type of errors could be thrown in the general error but I assume more of them exist. I have some sample code below of how I'm currently handling it, but I was thinking there might be a better way which I haven't found yet?
tries = 0
begin
tries += 1
<code>
rescue Foo::Bar => e
case e.to_s
when 'More specific timeout error message'
retry unless tries >= 5
else
# Let me see other error messages
log.info("Error: #{e.to_s}")
end
end
You can use multi rescue, to handle different errors.
begin
# DO SOMETHING
rescue Net::Timeout => e # change it to the error your want to catch, check the log.
# handle it
rescue SyntaxError => e # just an example
# handle it
rescue => e # any error that not catch by above rescue go here.
# handle it
end
Read more:
http://phrogz.net/programmingruby/tut_exceptions.html
You can try Rollbar, it help report error on production.
Take a look at retriable gem. It seems like a good fit for what you're proposing. Usually you'd rescue from an specific error type, but retriable also gives you the choice to rescue based on the error message.
begin
Retriable.retriable on: { Foo::Bar => /More specific timeout error message/ }, tries: 3 do
# will retry if an error of type Foo::Bar is raised
# and its message matches /More specific timeout error message/
# code here...
end
rescue => e # rescue for everything else
puts e.message # same as e.to_s
end
I wrote a simple ROR application and i raised an exception using airbrake. This is my code as follows
require 'airbrake'
require 'config/initializers/airbrake'
begin
raise "Serious problems happened"
params = {
:api_key => Airbrake.api_key,
:error_message => 'Notification',
:backtrace => caller,
:parameters => {},
:session => {}
}
rescue => e
Airbrake.notify(:error_class => "Special Error", :error_message => "Spe
cial Error: #{e.message}", :parameters => params)
end
When i run the above code, i'm getting the following exception
/root/ruby-1.9.2-p290/lib/ruby/site_ruby/1.9.1/rubygems/cus
tom_require.rb:55:in `require': no such file to load -- config/initializers/airb
rake (LoadError)
from /root/ruby-1.9.2-p290/lib/ruby/site_ruby/1.9.1
/rubygems/custom_require.rb:55:in `require'
from sample.rb:2:in `<main>''
But i have airbrake.rb in config/initializers, I don't know why the path is not taken.
What could be the issue here
You don't generally require your initializers explicitly. Code in config/initializers/ gets automatically loaded by your application.
Furthermore, if you've set up your Airbrake initializer properly, you can use a handy little helper called notify_airbrake to fire off Airbrake traces:
begin
...
rescue Exception => e
notify_airbrake e
end
That's all there is to it!