ruby on rails-具有多态关联和可接受嵌套属性的factorygirl无法通过验证



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

因此,在相关模型实例化和相关之前,您不能在任何一个模型上触发保存

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

我认为这应该工作

最新更新