cmh*_*bbs 7 ruby-on-rails activesupport activemodel ruby-on-rails-3 ruby-on-rails-4
我正在升级我从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 `<=>'
Run Code Online (Sandbox Code Playgroud)
activesupportrals安装了4.0.1和4.0.1.我使用chgems并清除了我的.gem/目录,Gemfile.lock然后再捆绑.
而这里是所有的回溯输出的,我可以从中获取pry.
一旦你发现有问题的回调就是这个:
before_create :activate_license
def activate_license
self.active_license = true
self.licensed_date = Time.now
end
Run Code Online (Sandbox Code Playgroud)
事情开始变得更加清晰.这activate_licence是一个回调之前.在回调之前,可以通过返回false(或引发异常)来暂停整个回调链.
如果我们在您通过手动添加一些提供的调试输出仔细看puts线到Rails的回调代码中,我们的确可以发现这个回调的比较与假的结果(在这里 -我删除了代码的一些不重要的部分):
result = activate_license
halted = (result == false)
if halted
halted_callback_hook(":activate_license")
end
Run Code Online (Sandbox Code Playgroud)
因为返回之前停止回调false(即上面显示的Rails代码)的支持实际上没有从Rails 3.2改为Rails 4.0.1,所以问题必须在于比较本身.
回调返回一个DateTime对象(它也是方法中的最后一个赋值,也是返回的).实际上,DateTimes 的比较在两个Rails版本之间发生了显着变化(同时请注意,==运算符通常使用<=>运算符进行评估):
在Rails 3.2中是这样的:
def <=>(other)
if other.kind_of?(Infinity)
super
elsif other.respond_to? :to_datetime
super other.to_datetime
else
nil
end
end
Run Code Online (Sandbox Code Playgroud)
请特别注意respond_to?检查other对象是否也是日期或时间对象,否则返回nil.
而在Rails 4.0.1中,这改为下面的裸代码:
def <=>(other)
super other.to_datetime
end
Run Code Online (Sandbox Code Playgroud)
→所有的理智检查都消失了!
现在,一切都很清楚:回调的结果(一个DateTime对象)使用<=>运算符与falseRails 4.0进行比较,比较尝试将false对象转换为DateTime没有任何健全性检查,这当然失败并抛出异常.
要解决这个问题,只需确保你的回调返回Rails可以比较的东西false而没有任何问题,例如true,因为你的回调永远不应该停止链:
def activate_license
self.active_license = true
self.licensed_date = Time.now
true
end
Run Code Online (Sandbox Code Playgroud)
现在一切都应该按预期工作了.
| 归档时间: |
|
| 查看次数: |
2440 次 |
| 最近记录: |