Trying to have following relationship in my application.
Product can belong to many categories, sub categories and sub sub categories.
Current design:
Product:
has_many :categorizations, dependent: :destroy
has_many :categories, through: :categorizations
has_many :sub_categories, through: :categorizations
has_many :sub_sub_categories, through: :categorizations
Category:
has_many :categorizations
has_many :products, through: :categorizations
has_many :sub_categories, class_name: 'Category', foreign_key: 'parent_id'
belongs_to :parent_category, class_name: 'Category', foreign_key: 'parent_id'
Categorization:
belongs_to :category
belongs_to :sub_category, class_name: 'Category', foreign_key: 'sub_category_id'
belongs_to :sub_sub_category, class_name: 'Category', foreign_key: 'sub_sub_category_id'
belongs_to :product
products of a particular category can be listed as category.products.
How to access products of a particular sub_category and sub_sub_category?
What changes should I make??
Add this line has_many :sub_sub_categories, through: :sub_categories to the Product model.
## app/models/product.rb
has_many :sub_categories
has_many :categories, through: :sub_categories
has_many :sub_sub_categories, through: :sub_categories
If I were you, I would design like this:
Product:
has_many :categorizations
has_many :categories, through: :categorizations
Categorization:
belongs_to :product
belongs_to :category
Category:
belongs_to :parent, class_name: 'Category', optional: true
has_many :children, class_name: 'Category', foreign_key: :parent_id, dependent: :nullify
has_many :categorizations
has_many :products, through: :categorizations
Note: Add parent_id to table categories
Related
I have a Category Model which belongs to Offer Model through a third Model OfferCategory. I also have a similar association for PlumCake Model which is associated to Category model through PlumCakeCategory Model.
Category:
has_many :offer_categories, dependent: :destroy, inverse_of: :category
has_many :offers, through: :offer_categories, source: :offer
has_many :plum_cake_categories, dependent: :destroy, inverse_of: :category
has_many :plum_cakes, through: :plum_cake_categories, source: :plum_cake
Offer:
has_many :offer_categories, dependent: :destroy, inverse_of: :offer
has_many :categories, through: :offer_categories, source: :category, dependent: :destroy
OfferCategory:
belongs_to :offer
belongs_to :category
PlumCake:
has_many :plum_cake_categories, dependent: :destroy, inverse_of: :plum_cake
has_many :categories, through: :plum_cake_categories, source: :category, dependent: :destroy
PlumCakeCategory:
belongs_to :plum_cake
belongs_to :category
and a similar association for category/plumcakes as well.
Now I want to get all categoires that the selected offers and plumcakes has. The following query gives me the list of categories that the eligible_offer_ids offers has.
Category.joins(:offer_categories).where(offer_categories: { offer_id: eligible_offer_ids })
I can fire a similar query for plum_cake and get uniq categoires of these two queries.
cat1 = Category.joins(:offer_categories).where(offer_categories: { offer_id: eligible_offer_ids })
cat2 = Category.joins(:plum_cake_categories).where(plum_cake_categories: { plum_cake_id: eligible_plum_cake_ids })
(cat1 + cat2).uniq
But Is there a way I get the same result((cat1 + cat2).uniq) in a single query?
if you don't to want change your structure:
Category.left_outer_joins(:offer_categories, :plum_cake_categories).where(offer_categories: { offer_id: eligible_offer_ids }).or(Category.left_outer_joins(:offer_categories, :plum_cake_categories).where(plum_cake_categories: { plum_cake_id: eligible_plum_cake_ids })).uniq
I think if you use rails STI(single table inheritance) you can easily implement your functionality.
if your structure be somthing like following:
class Category
has_many :offer_categories, dependent: :destroy, inverse_of: :category
has_many :offers, through: :offer_categories, source: :offer
has_many :plum_cake_categories, dependent: :destroy, inverse_of: :category
has_many :plum_cakes, through: :plum_cake_categories, source: :plum_cake
has_many :sub_categories
end
class SubCategory
belongs_to :offer
belongs_to :plum_cake
belongs_to :category
end
class OfferCategory < SubCategory
validate_presence_of :offer_id
end
class PlumCakeCategory < SubCategory
validate_presence_of :plum_cake_id
end
your query will be:
Category.joins(:sub_categories).where(sub_categories: { offer_id: eligible_offer_ids }).or(Category.joins(:sub_categories).where(sub_categories: { plum_cake_id: eligible_plum_cake_ids }))
STI documentation
I'm trying to access products through promotion but can't.
In the command line: Promotion.last.promotion_rules.first.products
Returns an error of an uninitialized constant.
Here are my associations:
class Product
has_many :product_promotion_rules, class_name: 'ProductPromotionRule'
has_many :promotion_rules, through: :product_promotion_rules
end
class ProductPromotionRule
belongs_to :product
belongs_to :promotion_rule
end
class PromotionRule
has_many :product_promotion_rules, class_name: 'ProductPromotionRule', join_table: 'products_promotion_rules', foreign_key: :promotion_rule_id
has_many :products, through: :product_promotion_rules
belongs_to :promotion
end
class Promotion
has_many :promotion_rules
end
Within the Product model try:
has_many :product_promotion_rules, class_name: 'ProductPromotionRule', foreign_key: :product_id
has_many :promotion_rules, through: :product_promotion_rules, source: :promotion_rule
And within the PromotionRule model:
has_many :products, through: :product_promotion_rules, source: :product
Update: saw this, which you may want to remove/fix:
join_table: products_promotion_rules
Either change to:
join_table: product_promotion_rules
Or try removing it.
Organization and Link are associated through Node.
Organization:
has_many :nodes
has_many :links, through: :nodes, source: :where_first_links
Node:
belongs_to :organization
has_many :where_first_links, class_name: "Link",
foreign_key: "first_node_id"
has_many :where_second_links, class_name: "Link",
foreign_key: "second_node_id"
Link:
belongs_to :first_node, class_name: "Node"
belongs_to :second_node, class_name: "Node"
Question:: How can I associate Link back to Organization? I tried the line below but that does not seem to work (ArgumentError: Unknown key: :through.):
belongs_to :organization,
through: :first_node,
source: :where_first_links,
inverse_of: :links
belongs_to association not support through key
you should use has_one association
has_one :first_node_organization,
through: :first_node,
class_name: 'Organization',
source: :organization
Use has_one instead of belongs_to.
class Link < ActiveRecord::Base
belongs_to :first_node, class_name: "Node"
belongs_to :second_node, class_name: "Node"
has_one :organization, through: :first_node
end
I have four models:
User
Listing
Order
OrderGroup
User:
has_many :listings
has_many :orders
Listing:
belongs_to :seller, class_name: "User", foreign_key: :user_id
has_many :order_groups, through: :orders
has_many :orders
Order:
has_one :seller, through: :listing
belongs_to :listing
belongs_to :order_group
OrderGroup:
has_many :listings, through: :orders
has_many :orders
has_many :sellers, through: :orders
When I try to pull Order.where(seller: User.find(3)), I get an empty collection. However, when I do Order.last.seller, I get the seller's user_id.
How can I pull Order.where(seller: User.find(3))' ?
You can write query as
Order.joins(:listing).where('listings.user_id = ?', 3)
How to write this:
has_many :sales, foreign_key: :buyer_id, dependent: :destroy
has_many :purchased_books, class_name: 'Book', through: :sales, source: :book
as this:
has_many :purchases, class_name: 'Sale', foreign_key: :buyer_id, dependent: :destroy
has_many :purchased_books, class_name: 'Book', through: :sales, source: :book
It gives me the following error at the moment:
Could not find the association :sales in model User (ActiveRecord::HasManyThroughAssociationNotFoundError)
And writing it has_many :sales is grammatically incorrect when foreign_key: :buyer_id.
The :through key must reference an association that is defined.
has_many :purchases, class_name: 'Sale', foreign_key: :buyer_id, dependent: :destroy
has_many :purchased_books, class_name: 'Book', through: :purchases, source: :book