具有多态关联和接受的嵌套属性的 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
我认为应该可行
我有一个非常简单的多边形关联设置。我正在尝试验证令牌仅存在于供应商或商店,而不是两者。当我使用 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
我认为应该可行