Rails 3.2到4.0升级:false的未定义方法to_datetime:FalseClass

时间:2016-04-23 01:37:25

标签: ruby-on-rails ruby-on-rails-3 ruby-on-rails-4 activemodel activesupport

我正在升级我从3.2继承到4.0.1的Rails应用程序。我跟着并完成了边缘指南:

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

除了一个我似乎无法找到根本原因的错误之外,我已经解决了所有问题。当我尝试保存用户模型对象时,我遇到以下错误:

[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和rals 4.0.1。我使用chgems并且在再次捆绑之前清除了我的.gem/目录和Gemfile.lock

这是Gist of the User model.

here is all of the backtrace output我可以从pry获得。

这是link to the User table schema

2 个答案:

答案 0 :(得分:7)

一旦你发现有问题的回调就是这个:

  before_create :activate_license

  def activate_license
    self.active_license = true
    self.licensed_date = Time.now
  end
事情开始变得更加清晰。 activate_licence之前的回调。 之前回调可以halt the whole callbacks chain by returning false(或引发异常)。

如果我们通过在Rails回调代码中手动添加一些puts行来仔细查看您提供的调试输出,我们确实可以找到此回调结果与false(here - I的比较删除了一些不重要的代码部分):

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

因为通过返回false(即上面显示的Rails代码)回调之前停止支持实际上没有从Rails 3.2更改为Rails 4.0.1,所以问题必须在于比较本身

回调返回一个DateTime对象(它也是方法中的最后一个赋值,也是返回的)。实际上,DateTime的比较在两个Rails版本之间发生了显着变化(同时请注意==运算符通常是evaluated using the <=> operator):

    Rails 3.2中的
  • this

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

    特别注意respond_to?检查other对象是否也是日期或时间对象,否则返回nil

  • 而在Rails 4.0.1中,changed to下面的代码为<{3}}:

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

    →所有完整性检查都已消失

现在,一切都很清楚:使用DateTime运算符和<=>比较回调的结果(false对象),并且在Rails 4.0下,比较尝试转换false DateTimefalse没有任何健全性检查,当然会失败并抛出异常。

要解决此问题,只需确保您的回调返回Rails可以与true进行比较而没有任何问题的内容,例如: def activate_license self.active_license = true self.licensed_date = Time.now true end ,因为你的回调永远不应该停止链:

start = '2012-04-23'
end = '2013-01-23'

>>> pd.DatetimeIndex([pd.datetime(ts.year, ts.month, int(end.split("-")[-1])) 
                      for ts in pd.date_range(start, end, freq='BM')])

DatetimeIndex(['2012-04-23', '2012-05-23', '2012-06-23', '2012-07-23', '2012-08-23', '2012-09-23', '2012-10-23', '2012-11-23', '2012-12-23'], dtype='datetime64[ns]', freq=None)

现在一切都应该按照预期再次发挥作用。

答案 1 :(得分:3)

你甚至可以在核心类中绑定,请执行类似的操作并查看other的内容,来自何处。

/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