Factory_girl,关联和after_initialize问题

时间:2011-05-06 19:32:07

标签: 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

在我的工厂里。我有:

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为nil。为什么会这样? 如果我用创造或新的方式给家人打电话,一切正常。

感谢您的帮助。

3 个答案:

答案 0 :(得分:24)

这是我从乔·费里斯那里得到的答案:

factory_girl不会将参数传递给构造函数。它使用#user = on 你的模型,并在没有任何参数的情况下实例化它。

和本休斯的这个:

详细说明Joe所说的内容,调用after_initialize方法 在对象初始化时立即,那个时间确实用户没有 已经确定。

例如,虽然这样可行:

family = Family.create!(:user => @user) # or @user.families.create ...

这不会(这是factory_girl在幕后做的事情):

family = Family.new
family.user = @user
family.save!

总的来说,你想要使用after_initialize真正小心,因为 记住这是在每个对象初始化上调用的。一个Family.all电话 在1000个对象上将导致被调用1000次。

在这种情况下,您可能更善于使用 before_validation而不是after_initialize。

以下语法也适用于在rspec中进行测试:

let (:family) { Family.create(:user => @user) }

答案 1 :(得分:16)

由于在实例化新对象后触发after_initialize并且默认情况下,factory_girl通过调用new而不使用任何参数来构建实例,因此必须使用initialize_with覆盖默认构建。

FactoryGirl.define do
  factory :family do
    initialize_with { new(user: build(:user)) }
  end
end

答案 2 :(得分:0)

我认为这是因为关联是懒惰的,因此在“after_initialize”之后还没有用户。

http://rdoc.info/github/thoughtbot/factory_girl/v1.3.3/file/README.rdoc

也许你可以直接从另一家工厂打电话,但我没试过,例如。

f.user Factory(:user)