Home > database >  Rails has_many :through plus collection_select
Rails has_many :through plus collection_select

Time:12-02

I was following the Ruby on Rails Guides Active Record Aossications plus some other threads on here, but not sure I'm setting it up right:

Products have many variety image sets (like for color, flavor, style) A product variety has only one image set (size--> color shirt)

So I think the associations should actually be:

Products
--has_many :product_varieties
--has_many :variety_image_sets, through: :product_varieties

Product Varieties
--belongs_to :product
--has_one :variety_image_set

Variety Image Sets
--belongs_to :product_variety

I got this setup idea from the Rails Guides example of documents, sections and paragraphs, but unfortunately it only works if I use has_many :variety_image_sets for Product Varieties.

my classes are as follows:

class Product < ApplicationRecord
  belongs_to :product_category
  has_many :product_varieties
  has_many :variety_image_sets, through: :product_varieties
end

class ProductVariety < ApplicationRecord
  belongs_to :product
  has_many :variety_image_sets
end

class VarietyImageSet < ApplicationRecord
  belongs_to :product_variety
end

For the Variety Image Set model, I have a product_variety:references in the migration.

I am able to create a Variety Image Set for each individual Product Variety, but I want it to be able to reuse the sets I a product (example, a a black shirt can have several sizes).

Now, moving on to the Collection Select: Once we have at least one Variety Image Set defined, can use a collection select when creating a new product variety.

This one works:

= form_with(model: [@product, product_variety]) do |form|
    = form.collection_select(:variety_image_set_ids, VarietyImageSet.all, :id, :label,  { prompt: true }, {multiple: false})

In my controller's product_variety_params:

def product_variety_params
  params.require(:product_variety).permit(:size, :unit_amount, :current_inventory, :variety_image_set_ids)
end

If I try to change VarietyImageSet.all to variety.variety_image_sets, the select menu goes empty. Also, one Product variety already has one defined, and when I try to assign that one to a different variety, that other variety "steals" it from the first one, instead of both being assigned that variety image set.

Please advise. Thanks

UPDATE Per the suggestion in the first answer, I've updated the associations. I now create the Variety Image Sets as a nested resource of Product instead of under Product Variety. This works.

Now, I click on edit for the Product Variety and want to assign a Pariety Image Set to it using the collection_select:

= form.collection_select(:variety_image_sets_id, VarietyImageSet.all, :id, :label, { prompt: true }, {multiple: false}) with updated params: def product_variety_params params.require(:product_variety).permit(:size, :unit_amount, :current_inventory, :variety_image_sets_id) end

But, I get the error that "Variety Image Set Must Exist".

finally, VarietyImageSet.all will give me all of them, I want to filter them to just those belonging to the product. @product.variety_image_sets returns undefined method "variety_image_sets" though.

= form_with(model: [@product, product_variety]) do |form|

ScreenShot of form with error

CodePudding user response:

You should use ProductVariety as the middle table with the following association:

class Product < ApplicationRecord
  belongs_to :product_category
  has_many :product_varieties
  has_many :variety_image_sets, through: :product_varieties
end

class ProductVariety < ApplicationRecord
  belongs_to :product
  belongs_to :variety_image_sets
end

class VarietyImageSet < ApplicationRecord
  has_many :product_variety
end

Now the Product table will have all your products. VarietyImageSet will have all varieties for products and the ProductVariety table will store which product have which variety.

  • Related