gpt4 book ai didi

ruby-on-rails-3 - 当使用 block 调用 create 时,Rails 3 after_initialize 未运行

转载 作者:行者123 更新时间:2023-12-03 00:53:31 26 4
gpt4 key购买 nike

我正在尝试使用 after_initialize 为对象设置一些默认值。我遇到的问题是,无论如何创建对象,我都希望调用它。

我的类(class):

class Foo < ActiveRecord::Base

serialize :data

after_initialize :init

def init
self.data ||= {}
self.bar ||= "bar"
self.baz ||= "baz"
end

end

如果我调用 Foo.new 一切正常, Foo.new(:bar => "things")Foo.create(:baz => 'stuff') 。但是,当我使用 create 的 block 时after_initialize回调未运行。

obj = Foo.create do |f|
f.bar = "words"
f.data = { :attr_1 => 1, :attr_2 => 2 }
end

这只会产生 obj.baz => nil而不是"baz"其他属性设置正确。

我是否遗漏了回调执行方式的某些内容,以及使用 block 调用 create 和不使用 block 调用 create 的区别,或者默认值是否被 block 破坏了?

更新

发现问题。

事实证明,调用create with block 和 without 略有不同。当您调用create时没有 block ,只需传入参数的哈希值,出于您调用 Foo.new({<hash of argument>}).save 的所有意图和目的,以及after_initialize正如您所期望的那样,回调会在保存之前执行。

当您调用create时有了 block ,就会发生一些不同的事情。事件的顺序是Foo.new使用您传入的任何参数进行调用,然后 after_initialize被调用,然后该 block 被运行。因此,如果您将 block (就像我一样)与散列参数互换使用,只是为了使内容更具可读性,您可能会因为您的 after_initialize 而受到影响。在实际设置您要设置的所有参数之前运行。

我被咬了,因为我在 after_initialize 中做了一些额外的工作。根据传递的值设置一些额外的必需属性。由于 after_initialize 时实际上没有设置任何内容。接到电话,没有任何设置正确,并且我的验证失败。

我最终不得不调用 init 电话。曾经after_initialize一次before_validation 。不是最干净的,但它解决了问题。

感谢布兰登为我指明了正确的方向。

最佳答案

我无法重现这个。我碰巧有一个方便的应用程序,其中包含以下(简化的)类:

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

这是 IRB session :

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
=> {}

如您所见,dataafter_initialize 方法中初始化为空哈希。 Rails 代码表明这也是有道理的;在创建中:

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

因此,create 调用new 并在yield 之前将值分配给object。这是new中的相关部分:

def initialize(attributes = nil)
# truncated for space
result = yield self if block_given?
run_callbacks :initialize
result
end

如您所见,new 在返回之前无条件调用 initialize 回调,因此在 create 之前甚至会屈服于您传递的 block 。 当您的 block 获取对象时,after_initialize 方法已经执行

仔细检查 (1) 您的 Rails 版本是否是最新的(我认为目前为 3.0.5),并且 (2) 在您没有意识到的情况下,没有任何内容设置 baz

关于ruby-on-rails-3 - 当使用 block 调用 create 时,Rails 3 after_initialize 未运行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5201439/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com