2015-10-06 4 views
0

Предположит следующее:Rails 4: полиморфизм, однонаправленное наследование, область охвата ...?

class Customer < ActiveRecord::Base 
    has_many :orders 
end 

class Order < ActiveRecord::Base 
    belongs_to :customer 
end 

Клиенты могут быть красными клиентами и/или голубыми клиентами, но они никогда не только клиентом. Красные покупатели собственных собак, голубые клиенты носят головные уборы (заказчик должен носить шляпу или владеть собакой). Для данного заказа red_customer равен never, равный blue_customer. Поскольку я никогда не использую client_id, я хочу исключить его из своей схемы и заменить его на red_customer_id и blue_customer_id. Каждый заказ имеет red_customer_id и blue_customer_id.

Примеры ...

  • @ some_order.customer # нет, плохо, не хочу
  • @ some_order.red_customer # возвращает объект
  • пользователя @ some_order.blue_customer # возвращает объект пользователя

схемы (в настоящее время некрасиво)

create_table "orders" 
    t.string "name" 
    t.integer "user_id" # I want to get rid of this 
    t.integer "red_customer_id" 
    t.integer "blue_customer_id" 
    end 

Но если я удалю user_id, мои ассоциации сломаются. Как я могу это очистить?

ответ

0

Предполагая, что заказ может принадлежать только одному пользователю одновременно, я не рекомендую иметь 2 foreign_keys в вашей таблице. Вы можете достичь того же результата, используя Single Table Inheritance:

class Customer < ActiveRecord::Base 
    has_many :orders 
end 

class RedCustomer < Customer 
end 

class BlueCustomer < Customer 
end 

class Order < ActiveRecord::Base 
    belongs_to :red_customer, foreign_key: 'customer_id' 
    belongs_to :blue_customer, foreign_key: 'customer_id' 
end 

Таким образом, вы держите одну таблицу для клиентов и один foreign_key по заказам.

Для этой работы вам нужно столбец в type строку в таблице клиентов, также как миграция заказа, добавьте polymorphic: true к объявлению foreign_key клиента, таким образом, также будет создан столбец customer_type.

class CreateCustomers < ActiveRecord::Migration 
    def change 
    create_table :customers do |t| 
     t.string  :type 
     t.timestamps null: false 
    end 
    end 
end 

class CreateOrders < ActiveRecord::Migration 
    def change 
    create_table :orders do |t| 
     t.references :customer, polymorphic: true, index: true 

     t.timestamps null: false 
    end 
    end 
end 

Он работает, как ожидалось:

order = Order.create 
order.red_customer = BlueCustomer.create #=> raises <ActiveRecord::AssociationTypeMismatch> 
order.red_customer = RedCustomer.create #=> Ok 
order.blue_customer #=> nil 
order.red_customer #=> #<RedCustomer id: ...> 
order.blue_customer = BlueCustomer.create #=> Ok 
order.red_customer #=> nil 

Надеется, что это помогает.

+0

Спасибо за ваш вдумчивый ответ. Некоторые вопросы ... Customer.type может быть «красным», «синим» или «обоими» ...? Кроме того, для некоторых заказов клиент является красным, а по другим заказам тот же самый клиент является синим (см. Рисунок моих собак/шляп). Это означает, что тип зависит от порядка, который кажется немного запутанным. – brntsllvn

+0

О, я вижу, я не понимаю, что они могут быть обоими. Да, это немного запутанный ха-ха. Я дам ему подумать и отредактировать свой ответ. – pedros

+0

Цените свою помощь. Кто-то offline предложил использовать «как:» (в руководстве Rails для ассоциаций), но мне все еще трудно понять, как избавиться от избыточного user_id. – brntsllvn

Смежные вопросы