1

Я пытаюсь установить полиморфные отношения в Rails и столкнулся с некоторыми трудностями. Вот моя модель данных:has_many polymorphism/inheritance in Rails

class Order 
    has_many :order_items 
end 

class OrderItem 
    belongs_to :order 
end 

class PhysicalItem < OrderItem 
end 

class VirtualItem < OrderItem 
end 

PhysicalItem и VirtualItem имеют достаточно различий в их модели, чтобы оправдать быть выделена в свои собственные таблицы. Таким образом, я себе там быть:

таблица заказов

стол physical_items

virtual_items стол

таблица order_items с ITEM_TYPE = [ "PhysicalItem" или "VirtualItem"] и item_id из соответствующая строка в соответствующей таблице.

В конце концов я хочу, чтобы иметь возможность писать код так:

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. 

Это кажется очень простым в теории, но это не выглядит как есть много поддержки для этой структуры в целом. У кого-нибудь есть идеи по реализации этого в базе данных postgresql с помощью ActiveRecord?

+0

Когда 'PhysicalItem' и' VirtualItem' наследуются от продукта, я не вижу модель продукта в вашем списке? Где он вписывается во все это? – jvperrin

+0

Думаю, мне не нужна модель продукта - единственная вещь, которую я получаю от нее, - это возможность запрашивать order.products, а затем извлекать кучу смешанных физических объектов и VirtualItems. –

+0

Кроме того, я отредактировал свой вопрос, чтобы отразить мои обновленные имена объектов - извините за недоразумение раньше. –

ответ

1

Для этого вам не нужны полиморфные ассоциации. Способ в Order модели будет работать точно так же:

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 

Вы также будете нуждаться в physical_items и virtual_items таблицы, оба имеют order_id столбцы. Затем, чтобы повторить поведение, которое вы хотели:

order = Order.new 
physical_item = order.physical_items.new 
virtual_item = order.virtual_items.new 

puts order.order_items 
+0

Конечно, но скажем, кто-то добавил 30 своих предметов в корзину. Я хочу выбрать первые 10 элементов, которые они добавили, - я не мог этого сделать без запроса всех элементов, сортировки конечного списка по метке created_at, а затем выброса других моделей. Это будет очень медленная операция. –

0

Вы можете использовать тип данных PostgreSQL HStore в сочетании с ИППП. Таким образом, вы получаете выгоду от запуска одного SELECT на одной таблице, но эта таблица не загрязняется столбцами типа.

Вам будет иметь только две таблицы:

  • заказов таблицы
  • order_items таблицы

Для таблицы order_items миграция будет состоять из:

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 

ваших моделей будет выглядеть следующим образом:

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 

Я попытался использовать полиморфную таблицу соединений, но для получения списка ассоциаций потребовалось слишком много запросов SQL. HStore с STI - отличная комбинация. Для получения дополнительной информации прочтите следующее: http://www.devmynd.com/blog/2013-3-single-table-inheritance-hstore-lovely-combination