在我的模型中,有父母,孩子和有名儿童群体。群体属于父母,子女属于父母,子女可能属于同一父母群体。
可以删除组,然后使用相同名称但不同的ID重新创建组。子项按名称引用其组,而不是id,因此如果重新创建组,它将属于同一组。多个父母可能存在同名的组,因此我们需要区分它们。
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>
。条件proc中的self
是Child类,而不是Child对象。
如何加载这样的关联?或者我的模型结构是愚蠢的?这些组的复合主键已经考虑过了,但我宁愿不这样做,因为rails默认情况下不支持它。
答案 0 :(得分:0)
看起来:finder_sql选项适用于has_many关系。不幸的是,它不是belongs_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
答案 1 :(得分:0)
我最终手动编写了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