0

私は2つのモデルを持っていUserますStash.

ユーザーには多くのスタッシュと default_stash があります。Stash には 1 人の所有者 (ユーザー) がいます。

ユーザーを作成する前に、Stash を作成し、その Stash を self.default_stash に割り当てます。Rails - ベスト プラクティス: 依存する has_one リレーションを作成する方法の指示に従って、Stash リレーションを作成しましたが、beens_to リレーションを同時に「作成」することはできません。

ユーザー.rb

has_many :stashes, foreign_key: :owner_id
belongs_to :default_stash, class_name: 'Stash', foreign_key: :owner_id

before_create :build_default_stash
def build_default_stash
  self.default_stash = stashes.build
  true
end

Stash.rb

belongs_to :owner, class_name: 'User'

この時点で Stash は見つかりますがuser.stashes、before_create ブロックで ID を返さないためuser.default_stash、nil のままです。stashes.build

私が必要とすることは、User.rbに以下を追加することで達成できます

after_create :force_assign_default_stash
def force_assign_default_stash
  update_attribute(:default_stash, stashes.first)
end

ただしbefore_create、検証などのために、可能であればすべてをブロック内に保持することをお勧めします。

4

1 に答える 1

1

あなたの説明は機能するはずですが、関連するレコードをメモリ内に構築し、それらがすべて接続された状態で適切に保存されることを期待している場合、ActiveRecord はそれらをどのように定義するかについて特に注意が必要です。

しかし、あなたbefore_create.

通常の問題は、どの関係が互いに逆であるかについて AR のヒントを与える必要があることです。has_manyメソッドとbelongs_toメソッドにはオプションがあり:inverse_ofます。あなたの場合の問題は、関係の片側 ( ) が実際には反対側 ( and )Stash#ownerの 2 つの逆であるということです。User#stashesUser#default_stashinverse_ofStash#owner

解決策は、Stash に a を追加しhas_oneて ( のように呼びますowner_as_default)、バランスを取ることです。次にinverse_of、すべての定義に追加して、それぞれが反対側の逆を識別することができます。最終結果は次のとおりです。

class User < ActiveRecord::Base
  has_many   :stashes,       foreign_key: :owner_id, inverse_of: :owner
  belongs_to :default_stash, class_name: "Stash",    inverse_of: :owner_as_default

  ...
end

class Stash < ActiveRecord::Base
  belongs_to :owner,            class_name: "User", inverse_of: :stashes
  has_one    :owner_as_default, class_name: "User",
    foreign_key: :default_stash_id, inverse_of: :default_stash
end

(また、属している場所に外部キーは必要ありません。)

そこから、before_create書いたとおりに動作するはずです。

はい、これは多くの冗長な定義のようです。ActiveRecord は外部キーなどからすべてを把握できませんか? 私は常に、一方が逆であることを意識させることで、いくつかの壁を壊しているように感じます. おそらく、Rails の将来のバージョンでは、これは解決されるでしょう。

于 2012-06-11T00:23:42.723 に答える