Reputation: 9621
With RoR ORM, how would you map this model.
Categories
-id
Products
-id
CategoriesProducts
-category_id
-product_id
So I want to perform queries like:
category.products.all
product.category.id
In rails, how do you decide which side of the relationship will be used for adding products to a category?
Will it be like:
category.add_product(product)
or
product.add_category(category)
And what if I wanted to fetch all categories with id 234,24,431,214 and products, is there a way I could do this w/o running into a n+1 query issue?
Upvotes: 2
Views: 2224
Reputation: 4113
Create a table categories_products, categories, and products, and create modal for Category and Products.
Have the relationship has_and_belongs_to_many in both the modals. This should give allow you to use methods like @category.products (to get all products, for a particular category) and @product.categories (to get all categories for that product).
Also look at these: http://guides.rubyonrails.org/association_basics.html#the-has_and_belongs_to_many-association http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html#method-i-has_and_belongs_to_many
Upvotes: 2
Reputation: 5716
Simplest way to do it, use has_and_belongs_to_many
. Make sure that when creating the CategoriesProucts table, you have the migration file create without an id:
create_table :categories_products, :id => false do |t|
Then your cateogry model should look like this:
class Category < ActiveRecord::Base
has_and_belongs_to_many :products
end
And your Product model should look like this:
class Product < ActiveRecord::Base
has_and_belongs_to_many :categories
end
Here's another method. This would also work if you wanted to have some more control for modification later. On your CategoriesProduct model:
class CategoriesProduct < ActiveRecord::Base
belongs_to :category
belongs_to :product
end
On your Categories model:
class Category < ActiveRecord::Base
has_many :categories_products
has_many :products, :through => :categories_products
end
On your product model:
class Product < ActiveRecord::Base
has_many :categories_products
has_many :categories, :through => :categories_products
end
Then you should be able to do:
Category.create(:name => "Cat1")
Category.first.products.create(:name => "Prod1")
Product.first.categories.create(:name => "Cat2")
etc...
This infograph may be helpful in visualizing the concept.
Upvotes: 9
Reputation: 22240
In terms of deciding how to get the data back again it is really up to you and what angle your coming at the data from.
For instance, in a categories_controller it will make more sense to come through categories to products, and vice versa for products.
To get all products for certain categories you can combine this:
Category.where("id IN (?)", [1,2,3,4,5,6]).includes(:products)
(or similar, I've not tested this). This will do one query for Categories, and one for the products.
Upvotes: 1