Phil Freeman
Phil Freeman

Reputation: 256

Ruby on Rails ActiveRecord: Using join to create parent/child relationship in same model

I'm trying to create a parent/child relationship association in rails, and I'm not quite sure how to do it.

I have two tables, products, and products_products. These two tables allow me to have products and sub products.

products
-----------
id  |  title  |  ...

products_products
-----------------
id  |  product_id  |  parent_product_id  | ...

What I want to be able to do is get all the child products of a product.

So I have:

class Product < ActiveRecord::Base
    ...
    has_many :products_products
    has_many :child_products, through: :products_products, source: :product
    has_many :parent_products, through: :products_products, source: :parent_product
    ...
end

class ProductsProduct < ActiveRecord::Base
    ....
    belongs_to :product
    belongs_to :parent_product, class_name: "Product", foreign_key: "parent_product_id"
    ....
end

The parent_products association works, but I'm not sure how to get the child_products.

The SQL would be:

SELECT "products".*
FROM "products"
INNER JOIN "products_products" ON "products"."id" = "products_products"."product_id"
WHERE "products_products"."parent_product_id" = <myProductd>

The goal would be to be able to say myProduct.child_products to get a list of child products.

Upvotes: 1

Views: 1566

Answers (1)

Surya
Surya

Reputation: 16002

What you need is a Self-Referential Association.

Change app/models/product.rb to:

class Product < ActiveRecord::Base
  has_many :product_mappings
  has_many :child_products, :through => :product_mappings
  has_many :inverse_product_mappings, :class_name => "ProductMapping", :foreign_key => "child_product_id"
  has_many :inverse_child_products, :through => :inverse_product_mappings, :source => :product
end

and app/model/product_mapping.rb:

class ProductMapping < ActiveRecord::Base
  # has product_id, child_product_id
  belongs_to :product
  belongs_to :child_product, :class_name => "Product"
end

Go ahead, try it:

product = Product.find 1
product.child_products

For more information there's a great screencast on Self-Referential Association by Ryan bates.

Upvotes: 2

Related Questions