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_at
和updated_at
@uzaif 您介意进一步解释吗?谢谢!
你能显示用户表的架构吗?你也重启了服务器,你可以尝试在控制台中创建一个用户
带有回溯输出的要点链接给出 404 错误
@cmhobbs 你可以为用户表发布你的架构吗?
【参考方案1】:
一旦你发现有问题的回调就是这个:
before_create :activate_license
def activate_license
self.active_license = true
self.licensed_date = Time.now
end
事情开始变得清晰起来。 activate_licence
是 before 回调。 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
对象(它也是返回的方法中的最后一个赋值)。而且,事实上,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
→ 所有健全性检查都没有了!
现在,一切都清楚了:使用 <=>
运算符与 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”