具有多态关联和已接受嵌套属性的factorygirl无法通过验证

时间:2016-08-05 00:54:57

标签: ruby-on-rails factory-bot rspec-rails polymorphic-associations

我有一个非常简单的多边协会设置。我试图验证令牌只存在于提供商或商店,而不是两者。当我使用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

表格

  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

1 个答案:

答案 0 :(得分:3)

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

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

我认为应该有效