Reputation: 2246
I have a Rails app with two models, call them transaction
and item
. Transactions are created during a checkout flow, and have an associated item
object, the transaction
holds the details of a sale, and item
represents the item being sold.
Models are setup like so:
class Transaction < ApplicationRecord
belongs_to :item
validates :item_id, presence: true, uniqueness: true
end
class Item < ApplicationRecord
has_one :company_transaction, class_name: 'Transaction'
end
And the factories are setup like so:
FactoryBot.define do
factory :transaction do
item { build_stubbed(:item) }
# Other transaction related attributes
end
end
FactoryBot.define do
factory :item do
# Item related attributes
end
end
Now, if I create a Transaction
object using simple transaction = build(:transaction)
I get the transaction, and it works as expected, with an Item
object also being created and accessible:
transaction.item_id => #####
transaction.item => #<Item:0x00007fcb08fab628...>
transaction.valid? => true
But, if I create an Item
object first, and pass it into the Transaction
factory, it exists, sort of, but not as it does with above. If I run something like:
item = build(:item)
transaction = build(:transaction, item: item)
I get
transaction.item_id => nil
transaction.item => #<Item:0x00007fcb08fab628...>
transaction.valid? => false
The Transaction
object is no longer valid because the item_id
field is nil
and this causes test to fail. Does anyone know what I'm doing wrong here? If I use create
on the two classes the items are properly built and saved to the database, and the proper fields are updated, but using build
this fails. I don't understand why I could get a proper, "full" association using build
and allowing the Transaction
factory to build it's own Item
object, yet if I build my own Item
object and pass it in the association is created (as evidenced by transaction.item
working) but the associated field is blank, and causing failed validation checks.
Upvotes: 1
Views: 1635
Reputation: 2246
After typing all this out, I realized that I could use build_stubbed
to create a new instance of the Item
class like item = build_stubbed(:item)
. Passing that into the Transaction
factory like transaction = build(:transaction, item: item)
is creating the properly working association, and adding a value to transaction.item_id
. What I still don't understand is why this is the case, if anyone could enlighten me I'd greatly appreciate it.
Upvotes: 3