Mat*_*ani 21 ruby-on-rails-3 factory-bot
我有一个如此定义的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
Run Code Online (Sandbox Code Playgroud)
在我的工厂里.我有:
Factory.define :family do |f|
f.association :user, :factory => :user
end
Run Code Online (Sandbox Code Playgroud)
在我的family_spec.rb中,我有
let(:family) { Factory(:family) }
Run Code Online (Sandbox Code Playgroud)
但这失败了:
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)>'
Run Code Online (Sandbox Code Playgroud)
使用调试器我可以看到,当调用after_initialize时,self.user为nil.为什么会这样?如果我用创建或新的方式打电话给家人一切正常.
谢谢你的帮助.
Mat*_*ani 24
这是我从乔·费里斯那里得到的答案:
factory_girl不会将参数传递给构造函数.它在您的模型上使用#user =,并在没有任何参数的情况下实例化它.
而这一个来自Ben Hughes:
为了详细说明Joe所说的内容,在对象初始化时立即调用after_initialize方法,并且确实没有设置用户的时间.
例如,虽然这将工作:
family = Family.create!(:user => @user) # or @user.families.create ...
Run Code Online (Sandbox Code Playgroud)
这不会(这是factory_girl在幕后做的事情):
family = Family.new
family.user = @user
family.save!
Run Code Online (Sandbox Code Playgroud)
一般来说,你想要使用after_initialize时要小心谨慎,因为记住这是在每个对象初始化时调用的.对1,000个对象进行Family.all调用将导致被调用1,000次.
听起来像在这种情况下你可能更好地使用before_validation而不是after_initialize.
以下语法也适用于rspec中的测试:
let (:family) { Family.create(:user => @user) }
Run Code Online (Sandbox Code Playgroud)
Gui*_*iGS 18
由于after_initialize在实例化新对象后触发,并且factory_girl new默认情况下通过不带任何参数调用来构建实例,因此必须使用initialize_with覆盖默认构建.
FactoryGirl.define do
factory :family do
initialize_with { new(user: build(:user)) }
end
end
Run Code Online (Sandbox Code Playgroud)