Reputation: 105
Concerning a Product model that houses multiple Part items;
...for example;
Product (Car)
Part (Engine) x1
part (Wheel) x4
part (Chassis) x1
I'm trying to wrap my head around setting this up and some help would be appreciated. In my Product model I'm assuming I set up an:
has_many :parts
When I do this though I can only assign one part to each product and I can't specify a numerical value? How would you approach this problem?
Upvotes: 0
Views: 162
Reputation: 102443
To create a many to many assocation between Product and Part you need a join table:
class Product < ApplicationRecord
has_many :product_parts
has_many :parts, through: :product_parts
end
class Part < ApplicationRecord
has_many :product_parts
has_many :products, through: :product_parts
end
class ProductPart < ApplicationRecord
belongs_to :product
belongs_to :part
end
Here product_parts
serves as the join table. You could for example attach four wheels to a car by:
car = Product.create(name: 'Car')
wheel = Part.create(name: 'Wheel')
4.times { car.parts << wheel }
car.parts.count # => 4
car.parts
# => #<ActiveRecord::Associations::CollectionProxy [#<Part id: 1, name: "Wheel", created_at: "2018-12-06 15:12:18", updated_at: "2018-12-06 15:12:18">, #<Part id: 1, name: "Wheel", created_at: "2018-12-06 15:12:18", updated_at: "2018-12-06 15:12:18">, #<Part id: 1, name: "Wheel", created_at: "2018-12-06 15:12:18", updated_at: "2018-12-06 15:12:18">, #<Part id: 1, name: "Wheel", created_at: "2018-12-06 15:12:18", updated_at: "2018-12-06 15:12:18">]>
This would create 4 rows in the product_parts
table. Another way to solve this would be by adding a quantity column to the product_parts
table.
car.product_parts.create(part: wheel, quantity: 4)
Adding "metadata" to the join model is only possible when its created explicitly. Note that this won't actually alter the count and length of the association like in the previous example.
car.parts.count # => 1
car.parts
# => #<ActiveRecord::Associations::CollectionProxy [#<Part id: 1, name: "Wheel", created_at: "2018-12-06 15:12:18", updated_at: "2018-12-06 15:12:18">]>
Rather you have to use the join table records to get the quantity:
<table>
<thead>
<tr>
<th>Name</th>
<th>Quantity</th>
</tr>
</thead>
<tbody>
<% @product.product_parts.each do |pp| %>
<tr>
<td><%= pp.part.name %></td>
<td><%= pp.quanty %></td>
</tr>
<% end %>
</tbody>
</table>
Upvotes: 1
Reputation: 6455
In your case, a car has many parts and a part belongs to one car. This can be setup as follows:
class Car < ApplicationRecord
has_many :parts
end
class Part < ApplicationRecord
belongs_to :car
end
This assumes that the Part model has a column called car_id, which is used to specify which car the part belongs to. You'll then be able to do:
car.parts
part.car
EDIT:
Say we have 5 parts:
part1 = Part.find(1)
part2 = Part.find(2)
part3 = Part.find(3)
part4 = Part.find(4)
part5 = Part.find(5)
And one product:
product1 = Product.find(1)
If I want to assign the parts to belong to the product, I would do:
part1.product_id = product1.id
part1.save
I can do that to all 5 parts, which will assign them all to the parent product.
If you want to see which parts belong to the product, you can do:
product1.parts
which will return
[part1, part2, part3, part4, part5]
As well as
part1.product
Which will return product1
Upvotes: 2