One way Has-Many-Through
-
27-09-2019 - |
Question
I have a Category, a Subcategory and a Product model.
I have:
Category has_many Subcategories
Subcategory has_many Products
Subcategory belongs_to Category
Product belongs_to Subcategory
Is there a way to have something like
Category has_many Projects through Subcategories
?
The 'normal' rails way wouldn't work because "subcategory" doesn't belongs to product so product does not have a subcategory_id field. Instead, I need the query to be something like
SELECT * FROM products WHERE id IN category.subcategory_ids
Is there a way to do that?
Thanks,
Nicolás Hock Isaza
Solution
If you do this the 'normal' Ruby on Rails way, the database you described would look something like this. If your database isn't structured like this, I suggest reading more about how associations are done for in Ruby on Rails because this is the right way (and you should be using t.references :category
in your migration since it was designed to make it easy to not mess your references up).
+----------------+ +----------------+ +----------------+
| categories | | subcategories | | products |
+----------------+ +----------------+ +----------------+
| id | | id | | id |
| ... | | category_id | | subcategory_id |
| | | ... | | ... |
+----------------+ +----------------+ +----------------+
With this as your database structure, the has_many :products, :through => subcategories
works for the Category
model.
class Category < ActiveRecord::Base
has_many :subcategories
has_many :products, :through => :subcategories
end
Subcategory.rb
class Subcategory < ActiveRecord::Base
belongs_to :category
has_many :products
end
Product.rb
class Product < ActiveRecord::Base
belongs_to :subcategory
has_one :category, :through => :subcategory # don't need this, but it does work
end
ruby script\console
>> c = Category.create
=> #<Category id: 1, ...>
>> c.subcategories.create
=> #<Subcategory id: 1, category_id: 1, ...>
>> p = s.products.create
=> #<Product id: 1, subcategory_id: 1, ...>
>> c.products
=> [#<Product id: 1, subcategory_id: 1, ...>]
>> p.category # if you have the has_one assocation
=> #<Category id: 1, ...>