I have a many-to-many relationship defined by a join model:
class Product < ActiveRecord::Base
has_many :bundlings
has_many :bundles, :through => :bundlings
…
end
class Bundling < ActiveRecord::Base
belongs_to :product
belongs_to :bundle
…
end
class Bundle < ActiveRecord::Base
has_many :bundlings
has_many :products, :through => :bundlings
…
end
Additionally, Bundle validates that it contains at least two products.
Then I tried to create a new Bundle like this:
fixtures :products
…
bundle = Bundle.new(…) # can’t save bundle yet since
# I haven’t yet added two products
bundle.products << products(:product_one)
bundle.products << products(:product_two)
bundle.save!
The “<<” operation raises an*
*ActiveRecord::HasManyThroughCantAssociateNewRecords
exception, saying that both bundle and the product need to have an ID to
use
“<<” on a through association. However, in order to obtain an ID, I
need to
save bundle, but bundle cannot be saved (i.e. pass validation) unless
I
have added two products to it through “<<” – Catch 22.
I have a many-to-many relationship defined by a join model:
…
Additionally, Bundle validates that it contains at least two products.
Then I tried to create a new Bundle like this:
fixtures :products
…
bundle = Bundle.new(…) # can’t save bundle yet since
# I haven’t yet added two products
bundle.products << products(:product_one)
bundle.products << products(:product_two)
bundle.save!
The “<<” operation raises an*
*ActiveRecord::HasManyThroughCantAssociateNewRecords
exception, saying that both bundle and the product need to have an ID to
use
“<<” on a through association. However, in order to obtain an ID, I
need to
save bundle, but bundle cannot be saved (i.e. pass validation) unless
I
have added two products to it through “<<” – Catch 22.
You can use a very simple state machine to control that the validation
only runs when it’s ready. You’d create a bundle as unprepared, add the
products, then save it as prepared.
Create a unprepared bundled. Mark the unprepared status in one of
its DB
columns.
Save the unprepared bundle to DB to generate an ID for it
Add the products to the saved bundle.
When the second product is added, unmark the unprepared status in the
DB
column.
This seems like a good solution, even though it would bypass the
validation
mechanism of ActiveRecord, and has a little bit more maintenance of
states…
Create a unprepared bundled. Mark the unprepared status in one of
its DB
columns.
Save the unprepared bundle to DB to generate an ID for it
Add the products to the saved bundle.
When the second product is added, unmark the unprepared status in the
DB
column.
This seems like a good solution, even though it would bypass the
validation
mechanism of ActiveRecord, and has a little bit more maintenance of
states…
Yes, that’s what I mean. You don’t have to bypass validation though.
You can include the condition of being prepared in the validation.
Something like this: