3

(извините за любой плохой английский)избежать полиморфных ассоциаций в Rails

Давайте предположим, что у меня есть модели A, B, C. Каждая модель имеет один адрес.

В книге «Антипаттеры SQL: устранение ошибок программирования баз данных» (глава 7 - Полиморфные ассоциации) существует рецепт, позволяющий избежать таких ассоциаций с помощью «общей таблицы супер» (также называемой базовой таблицей или таблица предков).

полиморфна, было бы:

table addresses: 
    id: integer 
    parent_type:string # 'A', 'B' or 'C' 
    parent_id: integer 

Я знаю, что вы можете использовать таблицы пересечений, но следующее решение выглядит более полированным:

Вместо того, полиморфна связывающей A, B, C с адресом, то рецепт предлагает создать супер-таблицу (Адресация), которая имеет только поле id (суррогатный ключ или псевдо-ключ). Затем другие таблицы ссылаются на адреса. Таким образом, говорит автор, «вы можете положиться на обеспечение целостности данных вашей базы данных с помощью внешних ключей». Таким образом, было бы:

table addressing 
    id: integer 
table addresses 
    id: integer 
    addressing_id: integer (foreign_key) 
    zip: string 
table a 
    id: integer 
    addressing_id: integer (foreign_key) 
    name: string 
table b 
    id: integer 
    addressing_id: integer (foreign_key) 
    name: string 
table c 
    id: integer 
    addressing_id: integer (foreign_key) 
    name: string 

Запрос SQL будет выглядеть так:

SELECT * from a 
    JOIN address USING addressing_id 
    WHERE a.addressing_id = 1243 

ВОПРОС: как закодировать такой сценарий в Rails? Я пробовал несколько способов без успеха.

+0

Вы можете посмотреть руководство RoR об ассоциациях [1], возможно, вы могли бы найти способ сделать это с помощью опции: через, извините, но я не могу попробовать в этот момент. [1]: http://guides.rubyonrails.org/association_basics.html#the-has_one-through-association –

ответ

1

У объектов A, B и C есть один адрес? Или много адресов? Из вашего комментария ниже выглядит, что каждый объект имеет один адрес.

Если каждый объект имеет только один адрес, вы можете просто поместить внешний ключ в объекты A/B/C с идентификатором адреса. Пусть объекты дома или офиса имеют один адрес:

class House < ActiveRecord::Base 
    belongs_to :address 
end 

class Office < ActiveRecord::Base 
    belongs_to :address 
end 

Ваши office с и houses DB таблицы need to have a foreign key address_id. Таким образом вы можете получить доступ к адресу объекта с чем-то вроде house.address или office.address.

Если эти объекты могут иметь много адресов, решение зависит от объектов A/B/C. Если они связаны, вы можете использовать Single Table Inheritance - Rails supports this pattern well - но без дополнительной информации трудно сказать, какой из них лучше всего подходит.

+0

2nd. Линия вопроса: «У каждой модели есть один адрес. Можете ли вы опубликовать код, чтобы я мог его протестировать? Похоже, ваше решение требует, чтобы для вашего решения требовалось указать foreign_keys для A/B/C на адресах таблицы, отражающих ассоциацию has_one, что вызовет много nil, так как адрес связан с A или B или C исключительно –

+0

«Каждая модель имеет один адрес», поэтому вы помещаете ссылку на этот адрес в своих моделях A/B/C, у вас нет большого количества нулевых значений, поскольку каждый объект A имеет или не имеет адреса. Я обновлю свой ответ, чтобы лучше объяснить его. –

+0

Выглядит хорошо! Что относительно ссылочной целостности? Конечно, принадлежит_to: address,: dependent =>: destroy для случаев, когда вы уничтожаете дом объект. Но как насчет уничтожения адреса? –

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