Reputation: 845
Today I found a fantastic exception which I cannot handle.
When I write this code:
def example
Integer('example show')
rescue
p 'All is good, I handle it'
end
> example
#=> 'All is good, I handle it'
But when ActiveRecord
throws the exception, I get:
def example
SomeModel.all.limit('example show')
rescue
p 'All is bad, I cannot handle it'
end
> example
#=> ArgumentError: invalid value for Integer(): "example show"
I thought it was some magical deep exception or nested exception, but this works fine too:
class A
def a
b
end
def b
Integer('show example')
end
end
begin
A.new.a
rescue
p 'All is good, I can handle it'
end
=> 'All is good, I can handle it'
Upvotes: 0
Views: 65
Reputation: 18803
This is happening because the evaluation of SomeModel.all.limit
is delayed until outside your rescue
block. all.limit
returns an ActiveRecord::Relation
that doesn't actually run until it has to, so example
returns just fine, and then later you try to use the value and Rails fails to convert example show
to an Integer
. Here's a demonstration from my console:
> def example
* User.all.limit('something')
* rescue
* puts 'Rescued'
* end
=> :example
> foo = example
=> #<#<Class:#<ActiveRecord::Relation::ActiveRecord_Relation_User:0x007ffb5b52e168>>:0x3ffdada970b4>
> foo.to_a
ArgumentError: invalid value for Integer(): "something"
I'd recommend handling the conversion of something
to an Integer
yourself so you can catch this properly in your example
method. Otherwise, you need to rescue
whenever you access the return value of example
, which isn't going to go well. You can also force instantiation of the relation inside example
by calling SomeModel.all.limit('something').load
. That will raise the exception where your rescue
can catch it the way you expect.
Upvotes: 3