DjezzzL
DjezzzL

Reputation: 845

Why can't I handle a limit exception in ActiveRecord?

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

Answers (1)

Kristján
Kristján

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

Related Questions