具有多态关联和接受的嵌套属性的 factorygirl 验证失败

factorygirl with polymorphic associations and accepted nested attributes fails validations

我有一个非常简单的多边形关联设置。我正在尝试验证令牌仅存在于供应商或商店,而不是两者。当我使用 pry 时,这些验证工作正常,但是,我的重构使工厂陷入困境。

问题

如果您使用令牌创建商店,即 FactoryGirl.create(:shop, :with_authentication_token) 它会爆炸,因为无法创建和保存商店,就像 FG 正在尝试处理它一样?谁能指出我建立商店工厂的正确方向?

错误

ActiveRecord::RecordInvalid: Validation failed: Owner can't be blank

现在提供者工厂可以工作,因为它是父级。

在 PRY 工作?

shop = FactoryGirl.build(:shop)
shop.authentication_token_attributes = { token: 'test', owner: shop }
shop.save

Table

  create_table "authentication_tokens", force: :cascade do |t|
    t.string   "token",      limit: 255, null: false
    t.datetime "created_at",             null: false
    t.datetime "updated_at",             null: false
    t.integer  "owner_id",   limit: 4,   null: false
    t.string   "owner_type", limit: 255, null: false
  end

工厂

FactoryGirl.define do
  factory :shop do
    provider
    ...

    trait :with_authentication_token do
      before(:create) do |shop|
        create(:authentication_token, owner: shop)
      end
      after(:build) do |shop|
        build(:authentication_token, owner: shop)
      end
    end

    trait :inactive do
      active { false }
    end
  end
end

型号

class Shop < ActiveRecord::Base
  belongs_to :provider
  has_one :authentication_token, as: :owner, dependent: :destroy

  accepts_nested_attributes_for(:authentication_token, update_only: true)

  ...

  validates :authentication_token, presence: true, if: :shop_is_owner?

  ...

  private

  def shop_is_owner?
    return false if provider.authentication_token
    true
  end
end

class Provider < ActiveRecord::Base
  ...

  has_many :shops
  has_one :authentication_token, as: :owner, dependent: :destroy

  ...

  accepts_nested_attributes_for(:authentication_token, update_only: true)

end


class AuthenticationToken < ActiveRecord::Base
  belongs_to :owner, polymorphic: true

  validates :token,
            length: { maximum: 245 },
            presence: true,
            uniqueness: true

  validates :owner, presence: true

  validate :unique_auth_token

  def shop
    return owner if owner_type == 'Shop'
  end

  def provider
    return owner if owner_type == 'Provider'
  end

  private

  def unique_auth_token
    errors.add(:base, I18n.t('activerecord.errors.models.shop.no_auth_token_sharing')) if shop && shop.provider.authentication_token
  end
end

因此在相关模型被实例化和关联之前,您无法触发对任一模型的保存

trait :with_authentication_token do
  before(:create) do |shop|
    create(:authentication_token, owner: shop)
  end
  after(:build) do |shop|
    build(:authentication_token, owner: shop)
  end
end

改为

trait :with_authentication_token do
  before(:create) do |shop|
    shop.authentication_token = build(:authentication_token, owner: shop)
  end
  after(:build) do |shop|
    shop.authentication_token = build(:authentication_token, owner: shop)
  end
end

我认为应该可行