0

aと aをFamily含むクラスがあります。家族モデルの観点からは、どちらの親が母親でどちらが父親であるかを知ることが重要ですが、母親と父親はすべて同じ属性 (データベース列など) を持っています。理想的には、モデル ファイルを次のようにしたいと考えています。mother_idfather_idResidents

class Resident < ActiveRecord::Base
  has_one :family, :dependent => :nullify, :foreign_key => :father_id
  has_one :family, :dependent => :nullify, :foreign_key => :mother_id
  attr_accessible :email, :cell, :first_name, :last_name
end

class Family < ActiveRecord::Base
  belongs_to :father, :class_name => 'Resident', :foreign_key => 'father_id'
  belongs_to :mother, :class_name => 'Resident', :foreign_key => 'mother_id'
  attr_accessible :address, :city, :state, :number_of_children
end

これはうまくいきません。 my_family.mothermy_family.father動作するので、Rails は double に満足しているようbelongs_toです。ただし、は、2 番目が 1 番目をオーバーライドしてmy_dad.family == nilいることを示しています。has_oneそうしないと、resident_id が Mother_id 列と Father_id 列の両方に表示されるとどうなるでしょうか。(モデルレベルの検証を追加して、決して起こらないようにする予定ですが、has_one検証メソッドとは話しません。)さらに、どういうmy_dad.family = Family.new意味ですか?ActiveRecord は、またはに挿入my_dad.idするかどうかをどのように選択しますか?Family.mother_idFamily.father_id

この Stackoverflow questionから、別の名前を使用するというアイデアを得ました。つまり、has_one行を次のように変更します。

has_one :wife_and_kids, :class_name => 'Family', :dependent => :nullify, :foreign_key => :father_id
has_one :husband_and_kids, :class_name => 'Family', :dependent => :nullify, :foreign_key => :mother_id

私の質問は次のとおりです。

1) より良い方法はありますか? おそらく別のDBスキーマですか?

2) データベース レベルの検証でモデル レベルの検証を補完して、列と列my_dad.idの両方に表示されないようにすることは可能ですか?mother_idfather_id

husband_and_kids3) /よりも良い名前を考えられますwife_and_kidsか? (確かにプログラミングの質問ではありません...)

編集: 家族のゲッターを追加することが私に起こりました:

def family
  @family ||= self.wife_and_kids || self.husband_and_kids
end
after_save :reset_family
def reset_family
  @family = nil
end

[husband|wife]_and_kidsこれにより、セッターがないためあいまいさを生み出すことなく、構文的にきれいになります (私は本当に のファンではなかったので)。

4

1 に答える 1

0

あなたが直面している主な問題は、「条件付き」の外部キーがあることです。つまり、居住者の :family を解決するために使用される外部キーは、居住者が男性か女性か (母親か父親) によって異なります。私の意見では、これに対処する最善の方法は、STI (Single-Table Inheritance) を使用して 2 つのケースを区別することです。

class Resident < ActiveRecord::Base
    attr_accessible :email, :cell, :first_name, :last_name
end

class Mother < Resident
    has_one :family, :dependent => :nullify, :foreign_key => :mother_id
end

class Father < Resident
    has_one :family, :dependent => :nullify, :foreign_key => :father_id
end

Resident テーブルは引き続き使用できますが、文字列型の :type フィールドを移行し、ケースに応じて値 "Mother" または "Father" を格納する必要があります。また、これらの各クラス定義を、models/ 内の独自のファイルに配置します。

編集:これにより、2番目と3番目の質問で提案された問題も解決されると思います。

編集2:

現在のスキーマを考えると、テーブルにチェック制約を作成する必要がありfamiliesます。1 つには、アクティブ レコードはこれを直接サポートしていないため、生の SQL を実行して制約を追加する必要があります。理論的には、「家族」の「mother_id」列で値が追加または変更されるたびに、「居住者」の「タイプ」列が「母親。" この制約を (理論的に) 追加する SQL は次のとおりです。

ALTER TABLE families
ADD CONSTRAINT must_be_mother CHECK ((SELECT type FROM residents WHERE residents.id = families.mother_id) = 'Mother')

問題は、これCHECKにはサブクエリが含まれていることです。私の知る限り、チェックのサブクエリは多くのデータベースで許可されていません。(詳細については、この質問を参照してください)。

ここで本当にデータベース レベルの検証を実装したい場合は、「居住者」を「母親」と「父親」に分けてスキーマを変更する必要があります。

于 2012-09-23T04:06:51.963 に答える