3

私のモデルには、親、子、および子の名前付きグループがあります。グループは親に属し、子は親に属し、子は同じ親のグループに属する場合があります。

グループは削除され、後で同じ名前で別の 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>ます。条件内のselfproc は、Child オブジェクトではなく、Child クラスです。

このような関連付けを熱心にロードするにはどうすればよいですか? それとも、私のモデル構造は愚かですか? グループの複合主キーは頭に浮かびましたが、レールはデフォルトでそれをサポートしていないので、私はむしろそうしません。

4

2 に答える 2

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
于 2012-05-19T17:03:17.967 に答える
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
于 2012-05-19T16:38:08.130 に答える