Ассоциации Rails + наследование

У меня возникли проблемы с решением, как смоделировать следующее с ассоциациями рельсов.

UML будет выглядеть примерно так:

----------------
|   CRITERIA   |
----------------
       |
       |*
----------------
|   CONTROLS   | <___
----------------     \
      ^               \
      |                \
-------------------    -------------------
|   SCALE CONTROL |    |  TEXT CONTROL   |      .....
-------------------    -------------------

-Различные элементы управления имеют совершенно разные атрибуты, поэтому STI кажется плохим выбором.
-Пользователь может указать любое количество элементов управления по критериям.

Я хотел бы сделать что-то вроде следующего:

Criteria
has_many :controls

ScaleControl  
belongs_to :criteria, as: control

TextControl
belongs_to :criteria, as: control

И иметь возможность запрашивать по строкам:

criteria.controls  
# displays all controls (text, scale, etc.) 

criteria.controls.each { ... }

То, что я рассмотрел до сих пор:
- Эпизоды RailsCasts о полиморфных ассоциациях, и кажется, что это не очень хороший вариант использования.
- Десятки сообщений об ассоциациях рельсов здесь, но не смогли найти ничего непосредственно относящегося к делу. .
-Документация по Rails.

Существуют ли какие-либо общие шаблоны для реализации чего-то подобного в Rails?


person jtgi    schedule 29.04.2013    source источник
comment
Релевантно: stackoverflow.com/questions/5022802/   -  person Reactormonk    schedule 29.04.2013


Ответы (1)


Ваша полиморфная настройка хороша, но здесь Rails не может вам помочь. У вас есть два варианта. Напишите сами методы:

class Criteria

  def controls
    scale_controls + text_controls
  end

  def scale_controls
    ScaleControl.where(criteria_id: id)
  end

  def text_controls
    TextControl.where(criteria_id: id)
  end
end

Или вы можете реализовать обратную полиморфную таблицу соединений. Звучит страшно, но это не так уж и плохо.

class CriteriaControl < ActiveRecord::Base
  belongs_to :criteria
  belongs_to :control, polymorphic: true # so it must include both a control_id and control_type in its table schema
end

Теперь оба элемента управления has_one :criteria_control и has_one :criteria, :through => :criteria_control.

Критерии затем has_many :criteria_controls, и вы можете определить метод управления как таковой:

def controls
  criteria_controls.map(&:control)
end

Но реальный вопрос заключается в том, «почему Rails не может написать это?»

Когда Rails строит ассоциации, это просто абстракции базового SQL. Здесь Rails не может собрать все controls, потому что не знает, в каких таблицах искать. Сначала он выполняет SELECT * FROM criteria_controls WHERE criteria_id = 231231. Затем он может использовать control_type и control_id для поиска отдельных элементов управления в соответствующих таблицах.

person Chris    schedule 04.05.2013