views:

94

answers:

2

Looking for some guidance on the best way to implement this scenario:

I have an items table (of products) and want to support the ability to cross-sell / up-sell / complement items. So there is an item-to-item(s) relationship here. In this join table I need to include additional attributes beyond the keys such as the sales_relation between the items (e.g., cross, up, complement, substitute, etc).

How do I go about setting up the Model associations?

A: 

Something like this:

has_many :other_item, :class_name => "Item", :through => :item_to_item

The table item_to_item would go like this

| item_id | other_item_id | complement | substitute | etc...

You'll have to write a custom attribute accessor which makes sure that item_id is always < other_item_id to avoid issues with the duplicates.

Feel free to ask more if you don't quite understand what I mean here.

glebm
Yes, cld you be so kind as to explain?
keruilin
+2  A: 

By the sounds of it, this join table represents a whole new model. I'm not sure exactly what your requirements are, but I'll play out one potential solution. For now, let's call the join model a SalesRelationship.

I'm going to call the item/product objects "products", since to me it's a little less generic.

The migration for this would look something like:

class CreateSalesRelationship < ActiveRecord::Migration
  def self.up
    create_table :sales_relationship |t|
      t.string :product_id
      t.string :other_product_id
      t.string :type
      t.timestamps
    end
  end

  def self.down
    drop_table :sales_relationship
  end
end

You can include any other attributes necessary in that migration as well. Next, create a SalesRelationship model:

class SalesRelationship < ActiveRecord::Base
  belongs_to :product
  belongs_to :other_product, :class_name => "Product
end

Then, create subclasses for the different types of relationship:

class CrossSell < SalesRelationship
end

class UpSell < SalesRelationship
end

class Complement < SalesRelationship
end

class Substitute < SalesRelationship
end

Then set up the relationships on the Product model:

class Product < ActiveRecord::Base
  has_many :sales_relationships, :dependent => :destroy
  has_many :cross_sells
  has_many :up_sells
  has_many :complements
  has_many :substitutes

  has_many :cross_sale_products, :through => :cross_sells, :source => :other_product
  has_many :up_sale_products, :through => :up_sells, :source => :other_product
  has_many :complementary_products, :through => :complements, :source => :other_product
  has_many :substitute_products, :through => :substitutes, :source => :other_product
end

Now you should be able to create and add related products all you want.

@product1.substitute_products << @product2
new_product = @product2.complementary_products.build

For extra credit, you could write a simple validation on the SalesRelationship model that ensures a product is never related to itself. That may or may not be necessary, depending on your requirements.

chrisdinn