codecompleting
codecompleting

Reputation: 9621

Category and Product mapping in activerecord

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

Answers (3)

Wahaj Ali
Wahaj Ali

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

Batkins
Batkins

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

Neil Middleton
Neil Middleton

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

Related Questions