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

Posted

技术标签:

【中文标题】Rails 3.2 到 4.0 升级:未定义方法 to_datetime for false:FalseClass【英文标题】:Rails 3.2 to 4.0 Upgrade: Undefined method to_datetime for false:FalseClass 【发布时间】:2016-08-16 18:46:07 【问题描述】:

我正在将我从 3.2 继承的 Rails 应用程序升级到 4.0.1。我在这里遵循并完成了边缘指南:

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。

【问题讨论】:

这是因为created_atupdated_at @uzaif 您介意进一步解释吗?谢谢! 你能显示用户表的架构吗?你也重启了服务器,你可以尝试在控制台中创建一个用户 带有回溯输出的要点链接给出 404 错误 @cmhobbs 你可以为用户表发布你的架构吗? 【参考方案1】:

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

  before_create :activate_license

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

事情开始变得清晰起来。 activate_licencebefore 回调。 Before 回调可以halt the whole callbacks chain by returning false(或引发异常)。

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

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

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

回调返回一个DateTime 对象(它也是返回的方法中的最后一个赋值)。而且,事实上,DateTimes 的比较在两个 Rails 版本之间发生了显着变化(还要注意 == 运算符通常是 evaluated using the &lt;=&gt; 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

→ 所有健全性检查都没有了

现在,一切都清楚了:使用 &lt;=&gt; 运算符与 false 比较回调的结果(DateTime 对象),在 Rails 4.0 下,比较尝试将 false 对象转换为 @ 987654347@ 没有任何健全性检查,这当然会失败并引发异常。

要解决此问题,只需确保您的回调返回 Rails 可以与 false 比较而没有任何问题的内容,例如true,因为你的回调永远不应该停止链:

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

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

【讨论】:

【参考方案2】:

您甚至可以在核心类中进行绑定,请执行以下操作并检查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

【讨论】:

通过在 gem 文件中覆盖这个,它可以工作 -> 我们有什么不使用这个的解决方案吗?

以上是关于Rails 3.2 到 4.0 升级:未定义方法 to_datetime for false:FalseClass的主要内容,如果未能解决你的问题,请参考以下文章

升级到 Rails 4.2.5.1 后 nil:NilClass 的未定义方法“缓存”

升级到 ruby​​ 3 和 rails 6.1 后未定义的方法“file_fixture_path”

升级到 Rails 6.1.0 后 ActiveStorage::Blob 的未定义方法“service_name”

Rails 3.2:activemerchant 中未定义的方法“class_inheritable_accessor”

从滑轨3.2升级到导轨4

无法识别启动活动:升级到 Android Studio 4.0 后未找到默认活动