Reputation: 399
I am trying to set up a polymorphic relationship in Rails and have been running into some difficulty. Here's my data model:
class Order
has_many :order_items
end
class OrderItem
belongs_to :order
end
class PhysicalItem < OrderItem
end
class VirtualItem < OrderItem
end
PhysicalItem and VirtualItem have enough differences in their model to warrant being split out into their own tables. So, I envision there being:
an orders table
a physical_items table
a virtual_items table
an order_items table with item_type = ["PhysicalItem" or "VirtualItem"] and item_id of the matching row in the corresponding table.
I eventually want to be able to write code like this:
order = Order.new
physical_item = PhysicalItem.new
virtual_item = VirtualItem.new
order.order_items << physical_item
order.order_items << virtual_item
puts order.order_items
# Should list out the physical item and then the virtual item.
It seems very simple in theory, but it doesn't look like there's much support for this structure in general. Anyone have any thoughts about implementing this in a postgresql database with ActiveRecord?
Upvotes: 1
Views: 342
Reputation: 1917
You could use the PostgreSQL HStore datatype in conjunction with STI. This way you gain the benefit of running a single SELECT
on one table but that table is not polluted with type specific columns.
You will then have only two tables:
For the order_items table the migration would consist of:
class CreateOrderItemsTable < ActiveRecord::Migration
def change
create_table :order_items do |t|
t.integer :order_id
t.string :type
t.hstore :data
end
end
end
Your models would then look like this:
class Order
has_many :order_items
end
class OrderItem
belongs_to :order
serialize :data, ActiveRecord::Coders::Hstore
end
class PhysicalItem < OrderItem
end
class VirtualItem < OrderItem
end
I tried using a polymorphic join table but it still required too many SQL quires just to get a list of the associations. HStore with STI is a great combination. For more information read this: http://www.devmynd.com/blog/2013-3-single-table-inheritance-hstore-lovely-combination
Upvotes: 0
Reputation: 3368
You shouldn't need polymorphic associations for this. A method in the Order
model would work just as well:
class Order < ActiveRecord::Base
has_many :physical_items
has_many :virtual_items
def order_items
physical_items + virtual_items
end
end
class PhysicalItem < ActiveRecord::Base
belongs_to :order
end
class VirtualItem < ActiveRecord::Base
belongs_to :order
end
You will also need the physical_items
and virtual_items
tables to both have order_id
columns. Then, to replicate the behavior you wanted:
order = Order.new
physical_item = order.physical_items.new
virtual_item = order.virtual_items.new
puts order.order_items
Upvotes: 1