HMC*_*tch 11 activerecord ruby-on-rails-3
我正在尝试使用设置对象的一些默认值after_initialize.我遇到的问题是无论对象是如何创建的,我都希望调用它.
我的课:
class Foo < ActiveRecord::Base
serialize :data
after_initialize :init
def init
self.data ||= {}
self.bar ||= "bar"
self.baz ||= "baz"
end
end
Run Code Online (Sandbox Code Playgroud)
一切工作正常,如果我打电话Foo.new,Foo.new(:bar => "things")和Foo.create(:baz => 'stuff').然而,当我使用块用create的after_initialize回调没有得到运行.
obj = Foo.create do |f|
f.bar = "words"
f.data = { :attr_1 => 1, :attr_2 => 2 }
end
Run Code Online (Sandbox Code Playgroud)
这只是产生obj.baz=> nil而不是"baz"正确设置其他属性.
我是否因为执行回调的方式而遗漏了某些内容,与使用块调用create并且没有或者是默认值被块阻塞的区别?
UPDATE
发现了这个问题.
事实证明,create使用阻止和不使用调用是微妙的不同.当你在create没有块的情况下调用并且只是传入一个参数哈希时,对于你正在调用的所有意图和目的Foo.new({<hash of argument>}).save,after_initialize回调就像你期望的那样在保存之前执行.
当你create用一个块打电话时会发生一些不同的事情.使用Foo.new您传入的任何参数调用事件的顺序,然后after_initialize调用,然后块运行.因此,如果您正在使用块(就像我一样)与哈希参数互换,只是为了让事情更具可读性,您可以得到一点,因为您after_initialize在实际设置的所有参数之前运行.
我有点因为我在after_initialize设置一些额外的必需属性时做了一些额外的工作,这些属性基于传递的值.因为在after_initialize调用时没有实际设置,所以没有设置正确并且我的验证失败.
我最终不得不接听电话init.一旦开启after_initialize,一旦开启before_validation.不是最干净的,但它解决了这个问题.
谢谢Brandon指出我正确的方向.
我无法重现这一点.我碰巧有一个应用程序方便与以下(简化)类:
class Service < ActiveRecord::Base
serialize :data, Hash
after_initialize :create_default_data
attr_accessible :data, :token
protected
def create_default_data
self.data ||= Hash.new
end
end
Run Code Online (Sandbox Code Playgroud)
这是一个IRB会议:
ruby-1.9.2-p136 :001 > obj = Service.create do |s|
ruby-1.9.2-p136 :002 > s.token = "abc"
ruby-1.9.2-p136 :003?> end
=> #<Service id: 22, user_id: nil, type: nil, data: {}, created_at: "2011-03-05 04:18:00", updated_at: "2011-03-05 04:18:00", token: "abc">
ruby-1.9.2-p136 :004 > obj.data
=> {}
Run Code Online (Sandbox Code Playgroud)
如您所见,data在after_initialize方法中初始化为空哈希.Rails代码表明这也是有意义的; 在create:
def create(attributes = nil, &block)
if attributes.is_a?(Array)
attributes.collect { |attr| create(attr, &block) }
else
object = new(attributes)
yield(object) if block_given?
object.save
object
end
end
Run Code Online (Sandbox Code Playgroud)
所以在它之前create调用new并赋值.以下是相关部分:objectyieldnew
def initialize(attributes = nil)
# truncated for space
result = yield self if block_given?
run_callbacks :initialize
result
end
Run Code Online (Sandbox Code Playgroud)
正如您所看到的,new无条件地在initialize回调之前调用回调,因此create甚至在您通过的块之前产生回调.当块获取对象时,该after_initialize方法已经执行.
仔细检查(1)您的Rails版本是最新的(截至目前我相信3.0.5)并且(2)没有任何设置baz而没有您意识到它.
| 归档时间: |
|
| 查看次数: |
5242 次 |
| 最近记录: |