Hi,
I’ve run into an situation with ActiveRecord 2.3 in which JRuby 1.5.6’s
behavior does not match MRI 1.8.7 and 1.9.2. The more I look into it,
the odder it seems. This gist contains the simplest script I’ve been
able to come up with to reproduce the problem:
In prose: if you have a model with a BigDecimal primary key and you call
#save! on it while the model is invalid, a NoMethodError is thrown
instead of the expected ActiveRecord::RecordInvalid exception. The
exception is “undefined method coerce' for true:TrueClass (NoMethodError)" and it occurs in ".../active_record/base.rb:2981:in
convert_number_column_value’”; it happens in during the transaction
rollback (full stacktrace on the gist). I’ve observed this with AR
2.3.5, 2.3.8, and 2.3.10 on JRuby 1.5.3 and 1.5.6 on Java 1.6.0_22 on OS
X 10.6.6. I’ve seen it with both Oracle and SQLite. It does not happen
if the PK is (as would be more common) an integer.
I’ve been looking into this problem and trying to isolate it, but I
haven’t been able to reproduce it in a simpler scenario than that in the
above gist. The method from which the exception is thrown is very
simple:
def convert_number_column_value(value)
if value == false
0
elsif value == true
1
elsif value.is_a?(String) && value.blank?
nil
else
value
end
end
The exception is thrown on the “elsif value == true” line. “value” is a
BigDecimal instance. However, executing this code on its own with a
freshly created BigDecimal instance does not throw the NoMethodError.
What’s even odder is that, if you modify active_record/base.rb to swap
the first two conditions like this
def convert_number_column_value(value)
if value == true
1
elsif value == false
0
elsif value.is_a?(String) && value.blank?
nil
else
value
end
end
when you re-run the reproduction script, the exception is thrown on the
“elsif value == false” line. Odder still, if you add any number of
invocations of value == true or value == false, the exception will
always be thrown on the last one. Similarly odd, if you modify AR to
invoke convert_number_column_value
on the same object at earlier
points within the same execution flow (including, e.g., the on the line
before the normal invocation), only the last invocation will throw the
NoMethodError.
I’m not familiar with JRuby’s internals. I’ve been looking at
org.jruby.RubyBigDecimal for some idea of what might cause this problem,
but I haven’t come up with anything. Any ideas?
Rhett