Rails: нетерпеливо загружает own_to с: условиями, относящимися к self

В моей модели есть родители, дети и именные группы детей. Группы принадлежат родителям, дети принадлежат родителям, а дети могут принадлежать к группе одного и того же родителя.

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

class Parent < ActiveRecord::Base
  has_many :groups
  has_many :children
end

class Group < ActiveRecord::Base
  belongs_to :parent

  has_many :children,
    :foreign_key => :group_name,
    :primary_key => :name,
    :conditions => proc { "children.parent_id = #{self.parent_id}" }
end

class Child < ActiveRecord::Base
  belongs_to :parent

  belongs_to :group,
    :foreign_key => :group_name,
    :primary_key => :name,
    :conditions => proc { "groups.parent_id = #{self.parent_id}" }
end

Это прекрасно работает, пока я не пытаюсь с энтузиазмом загружать группы детей. Child.where(...).includes(:group) дает undefined method parent_id' for #<Class:0x00000002dcc290>. self в условиях proc - это класс Child, а не объект Child.

Как мне загрузить такую ​​ассоциацию? Или моя модельная структура просто глупая? Составные первичные ключи для групп приходили в голову, но я бы не стал этого делать, поскольку rails не поддерживает это по умолчанию.


person mpartel    schedule 19.05.2012    source источник


Ответы (2)


Я закончил кодирование вручную примерно того, что делает Rails при активной загрузке:

class Child
  def self.eager_load_groups(children)
    keys = children.map {|c|
      "(#{connection.quote(c.parent_id)}, #{connection.quote(c.group_name)})"
    }
    keys.uniq!
    return if keys.empty?

    groups = Group.where('(parent_id, name) IN (' + keys.join(',') + ')')
    groups_by_key = Hash[groups.map {|g| [[g.parent_id, g.name], g] }]

    for c in children
      c.group = groups_by_key[[c.parent_id, c.group_name]]
    end
  end
end
person mpartel    schedule 19.05.2012

Похоже, что опция: finder_sql будет работать для отношения has_many. К сожалению, это не вариант для отношения own_to.

class Group < ActiveRecord::Base
  belongs_to :parent

  has_many :children,
    :foreign_key => :group_name,
    :primary_key => :name,
    :finder_sql => proc { "select distinct children.id from children where children.parent_id = #{self.parent_id}" }
end
person Adam    schedule 19.05.2012
comment
Не работает, извините :( Rails (eager-) загружает группы с отдельным 'SELECT ... FROM groups WHERE name IN (...) AND what-is-in-: conditions'. Запрос не обратитесь к таблице детей. - person mpartel; 19.05.2012
comment
Хммм, ладно, похоже, опция: finder_sql сделает то, что вы хотите. Я собираюсь обновить свой ответ соответственно. - person Adam; 19.05.2012
comment
Тоже не работает. Own_to в Child не использует finder_sql, и, согласно документам, вы не можете использовать: finder_sql с own_to. - person mpartel; 20.05.2012