I have a pretty straight forward poly association setup. I am trying to validate tokens only exist on providers or shops, not both. These validations work correctly when I use pry, however, my refactor has borked the factories.
Problem
If you create the shop with a token i.e. FactoryGirl.create(:shop, :with_authentication_token) it blows up because the shop can not get created and saved like FG is trying to process it? Can anyone point me in the right direction to setup the shop factory?
Error
ActiveRecord::RecordInvalid: Validation failed: Owner can't be blank
Right now the provider factory works because it is the parent.
Working in 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
Factories
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
Models
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
so you can't trigger a save on either model before the related model is instantiated and related
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
change to
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
i think that should work