0

以下の2つのモデルがあります。それらは次のように説明できます。

レポートには report_detail (開始/終了月を決定する) があります。多くのレポートは同じレポート詳細を持つことができますが、2 つのレポート詳細が同じであることはできません。

class Report < ActiveRecord::Base
  # attr: name :: String
  # attr: report_detail_id :: Integer
  belongs_to :report_detail
  accepts_nested_attributes_for :report_detail
end

class ReportDetail < ActiveRecord::Base
  # attr: duration :: Integer
  # attr: starting_month :: Integer
  # attr: offset :: Integer
end

[:duration, :starting_month, :offset] の ReportDetail のインデックスに一意の制約があります。

私が達成しようとしているのはこれです: 新しいレポートに、一意の組み合わせ属性 (:duration、:starting_month、:offset) を持つ ReportDetail がある場合、新しい ReportDetail を作成し、通常どおり保存します。レポートに ReportDetail があり、既存の ReportDetail が同じ属性を持つ場合、レポートの詳細をこの ReportDetail に関連付け、レポートを保存します。

report_detail=a を使用してセッターにエイリアスを設定することでこれを機能させましたReportDetail.find_or_create_by...が、醜いです (また、detail 属性を使用して新しいレポートをインスタンス化するだけで不要な ReportDetail エントリが作成され、何らかの理由で を使用して保存を適切に機能させることができませんでした.find_or_initialize_by...)。またbefore_save、ReportDetail で、何か他のものと一致する場合は、他のものに設定しようとしましたself。どうやらあなたはそのように自分自身を設定することはできません。

これについて最善の方法について何か考えはありますか?

私の現在のセッターがエイリアスで上書きするためのこの要点を参照してください

4

1 に答える 1

1

今日この問題を実行したところ、私の解決策はobject_attributes=accepts_nested_attributes_forによって提供されるメソッドに基づいていました。これにより、標準の関連付けセッターメソッドをオーバーライドする代わりに、混乱が少なくなると思います。この解決策を見つけるために Rails ソースに少し飛び込みました。ここにgithub リンクがあります。コード:

class Report < ActiveRecord::Base
  # attr: name :: String
  # attr: report_detail_id :: Integer
  belongs_to :report_detail
  accepts_nested_attributes_for :report_detail

  def report_detail_attributes=(attributes)
    report_detail = ReportDetail.find_or_create_by_duration_and_display_duration_and_starting_month_and_period_offset(attrs[:duration],attrs[:display_duration],attrs[:starting_month],attrs[:period_offset])
    attributes[:id]=report_detail.id
    assign_nested_attributes_for_one_to_one_association(:report_detail, attributes)
  end
end

ID を指定すると、何らかの説明が更新と見なされるため、新しいオブジェクトは作成されなくなります。また、このアプローチにはプラスのクエリが必要であることも知っていますが、今のところより良い解決策を見つけることができません。

また、レポートとレポートの詳細の間に has_one の関連付けがあるようです。この場合は、次を試してみてください。

   class Report < ActiveRecord::Base
      # attr: name :: String
      # attr: report_detail_id :: Integer
      has_one :report_detail
      accepts_nested_attributes_for :report_detail, :update_only=>true
    end

ドキュメントによると、これはうまくいくはずです。rails3 のドキュメントから:

:update_only

既存のレコードのみを更新できるように指定できます。新しいレコードは、既存のレコードがない場合にのみ作成できます。このオプションは、1 対 1 の関連付けでのみ機能し、コレクションの関連付けでは無視されます。このオプションはデフォルトでオフになっています。

于 2010-09-20T14:40:10.893 に答える