Как разделить две разные ассоциации с одним и тем же объектом?

У меня есть отношения «принадлежит» и «имеет_многие».

Дочерний элемент принадлежит родителю Родитель имеет_много дочерних элементов.

Однако у меня также есть другой способ, которым Parent может иметь дочерний элемент, и это через join_table, который я использую для создания группировки родительского типа.

Вот мое ужасное предположение о том, как это сделать:

# child.rb

belongs_to :parent
belongs_to :parent_group, :dependent => :destroy
delegate :parent, :to => :parent_group

# parent.rb

has_many :children
has_many :children, through: :parent_groups

Обратите внимание: на самом деле я не использую эти соглашения об именах. Они были просто изменены, чтобы сохранить анонимность моей работы.

Тогда мои миграции выглядят так:

class CreateParentGroup < ActiveRecord::Migration
  def self.up
    create_table :parent_groups do |t|
      t.integer :parent_id
      t.timestamps
    end
    add_column :child, :parent_group_id, :integer
  end

Итак, моя цель состоит в том, чтобы сделать так, чтобы при вводе Parent.find(n).children он возвращал дочерние объекты, которые либо через родительскую_группу, либо любые дочерние элементы, непосредственно связанные с ней.

И наоборот, если бы я выбрал Child.find(n).parent, он выбрал бы своего родителя, независимо от того, был ли он через родительскую группу или нет.

И тогда, наконец, я смогу выбирать parent_groups и выбирать коллекции родителей.

Есть идеи?


person Trip    schedule 15.08.2012    source источник


Ответы (1)


Прежде всего, если вы говорите о таблице соединений, то я думаю, что ваша настройка схемы для этой таблицы не совсем верна. Это должно быть так:

class CreateParentGroup < ActiveRecord::Migration
  def self.up
    create_table :parent_groups do |t|
      t.integer :parent_id
      t.integer :child_id
      t.timestamps
    end
  end
end

Итак, теперь ваша таблица parent_groups способна вместить много детей для многих родителей.

Что касается настройки ваших ассоциаций в ваших моделях: вы не можете/не должны называть две разные ассоциации одним и тем же именем. Следовательно, вы не можете делать has_many :children и has_many :children, :through => :parent_groups одновременно в одной модели. Потому что, если вы обращаетесь к дочерним элементам с помощью Parent.find(n).children, Rails не знает, какую ассоциацию использовать.

Я бы сделал что-то вроде этого:

class Parent < AR
  has_many :regular_children, :class_name => 'Child'
  has_many :group_children, :class_name => 'Child', :through => :parent_groups

  # implement a method that combines them both
  def children
    regular_children + group_children
  end
end

class Child < AR
  belongs_to :parent
  belongs_to :parent_group, :dependent => :destroy

  # forget the delegate, otherwise your invoke of Child.find(n).parent always
  # gets delegated to parent_group which is/can be wrong due to data
end

Я думаю, что это более правильный путь...

person Vapire    schedule 15.08.2012
comment
Потрясающий! Большое спасибо Вапир! - person Trip; 15.08.2012