web-dev-qa-db-ja.com

Railsモデルhas_many with multiple foreign_keys

Railsで比較的新しく、名前、性別、father_id、mother_id(2つの親)を持つ単一のPersonモデルで非常に単純な家族「ツリー」をモデル化しようとしています。以下は基本的に私が欲しいものです実行しますが、has_manyで:childrenを繰り返すことはできません(最初のものが上書きされます)。

class Person < ActiveRecord::Base
  belongs_to :father, :class_name => 'Person'
  belongs_to :mother, :class_name => 'Person'
  has_many :children, :class_name => 'Person', :foreign_key => 'mother_id'
  has_many :children, :class_name => 'Person', :foreign_key => 'father_id'
end

2つの外部キーでhas_manyを使用する簡単な方法、またはオブジェクトの性別に基づいて外部キーを変更する方法はありますか?または、完全に別の/より良い方法がありますか?

ありがとう!

49
Kenzie

IRCで動作すると思われる簡単な答えが見つかりました(レーダーのおかげです):

class Person < ActiveRecord::Base
  belongs_to :father, :class_name => 'Person'
  belongs_to :mother, :class_name => 'Person'
  has_many :children_of_father, :class_name => 'Person', :foreign_key => 'father_id'
  has_many :children_of_mother, :class_name => 'Person', :foreign_key => 'mother_id'
  def children
     children_of_mother + children_of_father
  end
end
43
Kenzie

Kenzie の答えを改善するために、Person#children お気に入り:

def children
   children_of_mother.merge(children_of_father)
end

詳細は this answer を参照してください

18
mr.musicman

Personモデルで使用されるnamed_scopesはこれを行います:

class Person < ActiveRecord::Base

    def children
      Person.with_parent(id)
    end

    named_scope :with_parent, lambda{ |pid| 

       { :conditions=>["father_id = ? or mother_id=?", pid, pid]}
    }
 end
9
Zando

:has_oneを使用して、必要な関係を実現できると思います。

class Person < ActiveRecord::Base
  has_one :father, :class_name => 'Person', :foreign_key => 'father_id'
  has_one :mother, :class_name => 'Person', :foreign_key => 'mother_id'
  has_many :children, :class_name => 'Person'
end

仕事が終わったら、この回答を確認して編集します。 )

8
Gordon Wilson

この問題にはスコープを使用することを好みます。このような:

class Person < ActiveRecord::Base
  belongs_to :father, :class_name => 'Person'
  belongs_to :mother, :class_name => 'Person'
  has_many :children_of_father, :class_name => 'Person', :foreign_key => 'father_id'
  has_many :children_of_mother, :class_name => 'Person', :foreign_key => 'mother_id'

  scope :children_for, lambda {|father_id, mother_id| where('father_id = ? AND mother_id = ?', father_id, mother_id) }
end

このトリックにより、使用インスタンスなしで子供を簡単に取得できます。

Person.children_for father_id, mother_id
4
squiter

Rails(3.2)の Associations and(multiple)foreign keys)への私の答え:モデルでのそれらの記述方法とマイグレーションの記述方法 はあなたにぴったりです!

あなたのコードについては、ここに私の変更があります

class Person < ActiveRecord::Base
  belongs_to :father, :class_name => 'Person'
  belongs_to :mother, :class_name => 'Person'
  has_many :children, ->(person) { unscope(where: :person_id).where("father_id = ? OR mother_id = ?", person.id, person.id) }, class_name: 'Person'
end

だから何か質問?

3
sunsoft

記載されている一般的な質問(「複数の外部キーを持つhas_many」)の解決策ではありませんが、人は母親または父親のどちらかである可能性がありますが、両方ではない場合、gender列を追加して、と

  has_many :children_of_father, :class_name => 'Person', :foreign_key => 'father_id'
  has_many :children_of_mother, :class_name => 'Person', :foreign_key => 'mother_id'
  def children
    gender == "male" ? children_of_father : children_of_mother
  end
3
Tom Locke

同じ機能を探していましたが、配列を返したくないがActiveRecord::AssociationRelationの場合は、<<の代わりに+を使用できます。 ( ActiveRecordのドキュメントを参照

class Person < ActiveRecord::Base
  belongs_to :father, :class_name => 'Person'
  belongs_to :mother, :class_name => 'Person'

  has_many :children_of_father, :class_name => 'Person', :foreign_key => 'father_id'
  has_many :children_of_mother, :class_name => 'Person', :foreign_key => 'mother_id'

  def children
     children_of_mother << children_of_father
  end
end