Rails 3.2 to 4.0 Update: Undefined to_datetime method for false: FalseClass

I am updating a Rails application that has inherited from 3.2 to 4.0.1. I followed him and finished the regional guide:

http://edgeguides.rubyonrails.org/upgrading_ruby_on_rails.html#upgrading-from-rails-3-2-to-rails-4-0

Everything is fixed for me, with the exception of one error, which, it seems to me, cannot find the root cause. When I try to save a user model object, I encounter the following error:

[1] pry(main)> User.create(name: "test user", email: " testuser@frobnitz.com ", password: "testPassword123", password_confirmation: "testPassword123") (0.6ms) BEGIN (0.9ms) ROLLBACK NoMethodError: undefined method `to_datetime' for false:FalseClass from /home/cmhobbs/src/serve2perform/.gem/ruby/2.3.0/gems/activesupport-4.0.1/lib/active_support/core_ext/date_time/calculations.rb:161:in `<=>' 

activesupport 4.0.1 and rals 4.0.1. I use chgems and I again cleaned the .gem/ directory and Gemfile.lock .

Here is the essence of the user model.

And here is the whole output of backtrace , I could get from pry .

Here is a link to the user table schema .

+7
ruby-on-rails ruby-on-rails-3 ruby-on-rails-4 activesupport activemodel
source share
2 answers

Once you find that the insult callback will be as follows:

  before_create :activate_license def activate_license self.active_license = true self.licensed_date = Time.now end 

things are becoming clearer. activate_licence is before the callback. Before callbacks can stop the whole chain of callbacks by returning false (or throwing an exception).

If we carefully consider the debugging output that you provided by adding a few puts lines to the Rails callbacks code, we can really find a comparison of this callback result with a false one ( here I deleted some irrelevant parts of the code):

 result = activate_license halted = (result == false) if halted halted_callback_hook(":activate_license") end 

Since the support for stopping before callbacks by returning false (that is, the Rails code shown above) has not practically changed from Rails 3.2 to Rails 4.0.1 , the problem should lie in the comparison itself.

The callback returns a DateTime object (this is the last assignment in the method, which is also returned). Indeed, the DateTime comparison has changed significantly between the two versions of Rails (also note that the == operator is usually evaluated using the <=> operator ):

  • in Rails 3.2 it was this :

     def <=>(other) if other.kind_of?(Infinity) super elsif other.respond_to? :to_datetime super other.to_datetime else nil end end 

    pay attention in particular to respond_to? check if the other object is also a date or time object, otherwise nil returned.

  • whereas in Rails 4.0.1 this one has changed to below:

     def <=>(other) super other.to_datetime end 

    → all health checks failed !

Now everything is clear: the result of the callback ( DateTime object) is compared using the operator <=> with false and under Rails 4.0, the comparison tries to convert the false object to DateTime without any sanity checks, which, of course, fails and throws an exception.

To fix this problem, just make sure your callback returns what Rails can compare to false without any problems , for example. true , since your callback should never stop the chain:

  def activate_license self.active_license = true self.licensed_date = Time.now true end 

Now everything should work as expected.

+7
source share

You can bind even in the main classes, please do something similar and check what other , where it came from.

/home/cmhobbs/src/serve2perform/.gem/ruby/2.3.0/gems/activesupport-4.0.1/lib/active_support/core_ext/date_time/calculations.rb

 def <=>(other) binding.pry if other.kind_of?(Infinity) super elsif other.respond_to? :to_datetime super other.to_datetime rescue nil else nil end end 
+2
source share

All Articles