【问题标题】:How do I create a factory for models that have a has_one/belongs_to relationship with validations that are usually overcome by nested attributes?如何为具有 has_one/belongs_to 关系的模型创建工厂,这些关系通常被嵌套属性克服?
【发布时间】:2011-07-22 23:51:06
【问题描述】:

我有一个拥有一个用户模型的帐户模型和一个属于帐户模型的用户模型。我认为演示所需的基本代码是:

class Account < ActiveRecord::Base
  has_one :user
  validates_presence_of :user
  accepts_nested_attributes_for :user
end

class User < ActiveRecord::Base
  belongs_to :account
  # validates_presence_of :account # this is not actually present,
                                   # but is implied by a not null requirement
                                   # in the database, so it only takes effect on
                                   # save or update, instead of on #valid?
end

当我在每个工厂中定义关联时:

Factory.define :user do |f|
  f.association :account
end

Factory.define :account do |f|
  f.association :user
end

我得到一个堆栈溢出,因为每个人都在递归地创建一个帐户/用户。

我能够解决这个问题的方法是在我的测试中模拟嵌套的实体形式:

before :each do
  account_attributes = Factory.attributes_for :account
  account_attributes[:user_attributes] = Factory.attributes_for :user
  @account = Account.new(account_attributes)
end

但是,我希望将这个逻辑保留在工厂中,因为一旦我开始添加其他模块,它就会失控:

before :each do
  account_attributes = Factory.attributes_for :account
  account_attributes[:user_attributes] = Factory.attributes_for :user
  account_attributes[:user_attributes][:profile_attributes] = Factory.attributes_for :profile
  account_attributes[:payment_profile_attributes] = Factory.attributes_for :payment_profile
  account_attributes[:subscription_attributes] = Factory.attributes_for :subscription
  @account = Account.new(account_attributes)
end

请帮忙!

【问题讨论】:

    标签: ruby-on-rails validation factory-bot


    【解决方案1】:

    我可以通过使用 factory_girl 的 after_build 回调来解决这个问题。

    Factory.define :account do |f|
      f.after_build do |account|
        account.user ||= Factory.build(:user, :account => account)
        account.payment_profile ||= Factory.build(:payment_profile, :account => account)
        account.subscription ||= Factory.build(:subscription, :account => account)
      end
    end
    
    Factory.define :user do |f|
      f.after_build do |user|
        user.account ||= Factory.build(:account, :user => user)
        user.profile ||= Factory.build(:profile, :user => user)
      end
    end
    

    这将在保存所属类之前创建关联类,因此验证通过。

    【讨论】:

    • user.profile 是从哪里来的?这是user.account吗?
    • user.profile 是一个模型,用于存储有关与帐户关联的用户的信息。因此,结构是帐户 > 用户 > 个人资料。不过,我添加了 user.account,因为我认为如果直接创建用户,这是必要的。
    【解决方案2】:

    看看factory_girl documentation。您建立这些帐户的方式似乎并没有真正利用 factory_girl。

    我一直通过在测试之前创建我需要的对象来处理关联。我将根据您上面引用的模型对此进行尝试:

    before :each do
      @account = Factory(:account, :user_id => Factory(:user).id, :profile_id => Factory(:profile).id)
    end
    

    现在@account 将提供@account.user@account.profile。如果您需要定义这些,@profile = @account.profile 效果很好。

    【讨论】:

    • 我遇到的问题是用户属于帐户而不是相反,因此 Account#user_id 不存在,而 User#account_id 是需要设置的属性。但是,如果没有关联用户的帐户,我无法保存帐户以获取 ID。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多