Я подозреваю, что ваша проблема может стать намного проще, если вы наложите дополнительную структуру на свои модели. Тот факт, что вы называете свою модель TaleRelation, заставляет меня думать, что большинство из этих вещей должно быть напрямую связано с рассказом, которое можно было бы сделать с отношением has_and_belongs_to_many, тогда можно было бы связать другие вещи through: :tale. Но я думаю, что мы также можем решить вопрос, как было сказано.
Во-первых, вы хотите посмотреть на polymorphic associations. В коде, который вы указали выше, первым шагом будет использование belongs_to :relatable, polymorphic: true
в TaleRelation и has_many :tale_relations, as: :relatable
в других моделях. Это требует, чтобы таблица tale_relations имела два столбца relatable_id и relatable_type, для чего вы пытаетесь сделать это и for_id.
Однако, я думаю, вы действительно хотите сделать этот шаг дальше, а также избавиться от рассказов, символов, значений и т. Д. Столбцов. Мы можем сделать это, используя две полиморфные отношения, а не только одну.
Во-первых, структура таблицы (4 колонки):
create_table :tale_relations do |t|
t.integer :relater_id
t.string :relater_type
t.integer :relatee_id
t.string :relatee_type
end
И модель
class TaleRelation < ActiveRecord::Base
belongs_to :relater, polymorphic: true
belongs_to :relatee, polymorphic: true
after_create :create_inverse_relationship
after_destroy :destroy_inverse_relationship
def create_inverse_relationship
self.class.find_or_create_by(inverse_attributes)
end
def destroy_inverse_relationship
self.class.find_by(inverse_attributes).try(:destroy)
end
def inverse_attributes
{
relater_id: relatee_id,
relater_type: relatee_type,
relatee_id: relater_id,
relatee_type: relater_type
}
end
end
Что я делаю с обратными вызовами это каждый раз, когда вы создаете или уничтожить TaleRelation с микросхемой данный relater и relatee, он создает или уничтожает соответствующий обратный. Поэтому, если данная Сказка связана с Символом, из этого следует, что Символ также связан с Сказкой. Если вам не нужна эта симметрия, просто выньте эти обратные вызовы.
Сейчас, к примеру, в Сказке:
class Tale < ActiveRecord::Base
has_many :tale_relations, as: :relater, dependent: :destroy
has_many :characters, through: :tale_relations, source: :relatee, source_type: "Character"
has_many :values, through: :tale_relations, source: :relatee, source_type: "Value"
# and so on
end
И подобные вещи в ценности и характера и так далее. Теперь Tale has_many: символы, не требующие сохранения своих идентификаторов в виде разделенной запятой строки или массива, поскольку похоже, что вы делали это выше в своей таблице. Обязательно не включайте какие-либо самореферентные инструкции has_many (т. Е. Не помещайте has_many :characters
в символ)
Таким образом, мы определяем связь с TaleRelation через полиморфные relater_id и relater_type, поэтому мы можем иметь все эти отношения без всех столбцов , И через эти отношения мы можем собрать (полиморфно!) Все отношения правильного класса. Это дает мне:
2.2.2 > t = Tale.create(name: "T")
=> #<Tale id: 1, name: "T">
2.2.2 > c = Character.create(name: "C")
=> #<Character id: 1, name: "C">
2.2.2 > d = Character.create(name: "D")
=> #<Character id: 2, name: "D">
2.2.2 > v = Value.create(name: "V")
=> #<Value id: 1, name: "V">
2.2.2 > t.characters << c
=> #<ActiveRecord::Associations::CollectionProxy [#<Character id: 1, name: "C">]>
2.2.2 > v.characters << c
=> #<ActiveRecord::Associations::CollectionProxy [#<Character id: 1, name: "C">]>
2.2.2 > v.characters << d
=> #<ActiveRecord::Associations::CollectionProxy [#<Character id: 1, name: "C">, #<Character id: 2, name: "D">]>
2.2.2 > d.values
=> #<ActiveRecord::Associations::CollectionProxy [#<Value id: 1, name: "V">]>
2.2.2 > t.characters.first.values
=> #<ActiveRecord::Associations::CollectionProxy [#<Value id: 1, name: "V">]>
Обратите внимание, что это НЕ распространяет отношения второго порядка. I.e.,
2.2.2 > t.values
=> #<ActiveRecord::Associations::CollectionProxy []>
, хотя t имеет символ со значением. Как только вы начнете это делать, довольно скоро у вас будет все, что связано со всем остальным.