Factory_girl、关联和 after_initialize 的问题
我有一个这样定义的 Family 类:
class Family < ActiveRecord::Base
after_initialize :initialize_family
belongs_to :user
validates :user,
:presence => true
validates :name,
:presence => true,
:length => { :maximum => 30 },
:format => { :with => /\A[a-zA-Z0-9\-_\s\']+\z/i}
def initialize_family
if self.name.blank? && self.user
self.name = "#{self.user.profile_full_name}'s Family"
end
end
end
在我的 Factory.rb 中,我有:
Factory.define :family do |f|
f.association :user, :factory => :user
end
在我的 family_spec.rb 中,我有
let(:family) { Factory(:family) }
但这失败了:
1) Family is valid with valid attributes
Failure/Error: let(:family) { Factory(:family) }
ActiveRecord::RecordInvalid:
Validation failed: Name can't be blank, Name is invalid, Languages can't be blank, Languages is too short (minimum is 1 characters)
# ./spec/models/family_spec.rb:8:in `block (2 levels) in <top (required)>'
# ./spec/models/family_spec.rb:10:in `block (2 levels) in <top (required)>'
使用调试器,我可以看到当 after_initialize 被调用时 self.user 为零。为什么会发生这种情况? 如果我用 create 或 new 给家人打电话,一切都会正常。
感谢您的任何帮助。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
发布评论
评论(3)
时光清浅 2024-11-12 06:33:11
由于 after_initialize
是在实例化新对象后触发的,并且factory_girl默认是通过调用new
而不带任何参数来构建实例的,因此您必须使用""="" }="" com="" thoughtbot="" factory_girl="" blob="" v4.5.0="" getting_started.md#custom-construction"="">initialize_with
覆盖默认构建。
FactoryGirl.define do
factory :family do
initialize_with { new(user: build(:user)) }
end
end
不喜欢何必死缠烂打 2024-11-12 06:33:11
我相信这是因为关联是惰性的,因此在“after_initialize”中还没有用户。
http://rdoc.info/github/thoughtbot/factory_girl/v1 .3.3/file/README.rdoc
也许你可以直接从另一个工厂调用一个工厂,但我没有尝试这个,例如
f.user Factory(:user)
~没有更多了~
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
这是我从 Joe Ferris 那里得到的答案:
factory_girl 不会将参数传递给构造函数。它使用#user= on
您的模型,并在没有任何参数的情况下实例化它。
Ben Hughes 的这个:
为了详细说明 Joe 所说的内容,调用了 after_initialize 方法
对象初始化后立即执行,而此时用户确实还没有
已设置。
例如,虽然这会起作用:
但这不会(这就是factory_girl在幕后做的事情):
一般来说,你要非常小心地使用after_initialize,因为
请记住,这是在每个对象初始化时调用的。一家人的呼唤
on 1,000 个对象将导致调用 1,000 次。
听起来在这种情况下你最好使用
before_validation 而不是 after_initialize。
以下语法也适用于 rspec 中的测试:
This is the answer I got from Joe Ferris:
factory_girl doesn't pass arguments to the constructor. It uses #user= on
your model, and instantiates it without any arguments.
and this one from Ben Hughes:
To elaborate on what Joe is saying, after_initialize methods are called
immediately upon object initialization, and that time indeed user has not
been set.
So for example while this will work:
This will not (which is what factory_girl is doing under the hood):
Just in general you want to be real careful using after_initialize, as
remember this is called on every object initialization. A Family.all call
on 1,000 objects will cause that to get called 1,000 times.
Sounds like in this instance you might be better of using a
before_validation instead of after_initialize.
The following syntax also works for testing in rspec: