ruby-on-rails - Rails 3.2 到 4.0 升级 : Undefined method to_datetime for false:FalseClass

标签 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

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

[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 .

最佳答案

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

  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 (或引发异常)。

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

因为通过返回 false 支持在回调之前暂停(即上面显示的 Rails 代码)实际上没有改变 Rails 3.2Rails 4.0.1 ,问题一定在于比较本身。

回调返回 DateTime对象(它是方法中的最后一个赋值,也返回)。而且,确实,DateTime 的比较s 在两个 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下面的裸代码:
    def <=>(other)
      super other.to_datetime
    end
    

    → 全部 健全性检查没有了 !

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

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

    现在一切都应该再次按预期工作。

    关于ruby-on-rails - Rails 3.2 到 4.0 升级 : Undefined method to_datetime for false:FalseClass,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36805639/

    相关文章:

    ruby-on-rails - 不显示 Rails 3 的 Kaminari

    mysql - as_json 忽略 .where() 子句的第二部分

    ruby-on-rails - Rails 模型 has_many , belongs_to 关系

    javascript - 没有 Javascript 的 capybara Click_Button 失败

    ruby-on-rails - 如何在Rails Admin中隐藏添加新选项

    css - 如何使用 active_link_to 将边框直接定位在事件链接上? rails 4

    javascript - 链接以关闭页面 Rails 4

    ruby-on-rails - 在 rails 嵌套属性中编辑连接表值

    database - 无法删除不在表中的 Nil 数据

    mysql - 将 mysql 查询移动到模型