2

私の現在の Rails アプリでは、5 秒ごとにデータベースにアクセスしたくない長時間実行されるバックグラウンド タスクを開始できるように、データベースから大量のデータをメモリにプルしています。

これはすべてうまく機能していますが、可能であれば削除したい洗練されていないコードがいくつかあります。

たとえば、User モデルがあり、その User モデルが連絡先の形で他の User モデルにリンクでき、それが最初の User モデルにリンクし直すことができる状況があります。これは次のようにモデル化されています (Milan Novota の以前の支援に感謝します): -

class User < ActiveRecord::Base
  has_many :contact_records, :foreign_key => :owner_id
  has_many :contacts, :through => :contact_records, :class_name => "User"
end

class ContactRecord < ActiveRecord::Base
  belongs_to :owner, :class_name => "User"
  belongs_to :user
end

だから今私は入力することができます

user_a_contacts = user_a.contact_records
=> [user_b, user_c]

ユーザーaのすべての連絡先を取得します。ここで、ユーザー a を介してユーザー b の連絡先を取得したいとしましょう (理由はわかりませんが、これは単なる例です!)

user_b_contacts = user_a_contacts.first.contact_records
=> [user_a, user_c]

これで、ユーザー a の名前を取得できます (複雑で回りくどい、現実世界では決して使用されないような方法で)

user_a_name = user_b_contacts.first.name
=> "Jamie"

ここまでは順調ですね。ここで、ユーザー a の名前を変更します

user_a.name = "Sandy"
=> "Sandy"

データベースから以前と同じようにユーザーaの名前に再度アクセスすると、取得します

user_a_name = user_b_contacts.first.name
=> "Sandy"

ただし、この値を熱心にロードしてメモリに保持すると、

user_a_name = user_b_contacts.first.name
=> "Jamie"

しかし、次のことを行うと正しい答えが得られます

user_a.name
=> "Sandy"

明らかに、eager-loading は、元のユーザーと ContactRecord オブジェクトからeager-loadされたユーザーに対して異なる User オブジェクトを作成しています。

だから(ついに!)私の質問はこれです: -

現時点では、使用してこれを回避しています

@users.each.detect{|user| user == user_b_contacts.first}

(@users は、熱心に読み込まれた User オブジェクトのリストです)。代わりに、eager-loaded User オブジェクトを更新する方法はありますか?

ご注意ください: -

a) 私は以下を使用して熱心に読み込んでいます

User.find(:all, :include => [ {:contact_records => :contacts] } ])

b) 明らかに、これは私が作業している実際のコードではありませんが、そのコードを示すためにさらに多くの説明と説明が必要であり、十分に退屈させたと思います! 私が使用している実際の例では、奇妙に見えるかもしれませんが、正しく機能するためにこの構造が必要であると信じてください! ;)

c) 例を再構築する際にタイプミスやエラーが発生した可能性がありますが、それらは無視してください。私が知る必要があるのは、データベースにアクセスせずに熱心にロードされたユーザーをリロードできるかどうかだけです。

よろしくお願いします!

更新: 以下で説明するように、モデル データはプロセス実行の最後までデータベースに保存されないため、データベース内のデータは変更されていないため、リロードは機能しません。

4

2 に答える 2

4

わかった。あなたの質問を新しい質問に要約して、その質問に答えます。私が誤解していて、これがあなたが求めているものではない場合はご容赦ください。

質問

で事前にuserアソシエーションをロードした ActiveRecord モデルの場合、データベースでアソシエーションが変更されたときにアソシエーションを更新するにはどうすればよいですか?contactsUser.first(:include => :contacts)contacts

答え

私が知っている 2 つの方法で関連付けキャッシュを無効にすることができます。まず、次のことができます。

user.reload

これにより、ユーザー モデル全体が最初から再読み込みされます。これを行うためのやや抜本的な方法は次のとおりです。

user.clear_association_cache

のすべてをリロードするわけではありませんuserが、キャッシュされた関連付けをクリアします。

いずれにせよ、次に実行するときuser.contactsにデータベースから新たにロードされます。

于 2009-04-17T11:25:52.357 に答える
0

ダニエルさん、お返事ありがとうございます。あなたは正しい質問をしていませんが、あなたは私が重要なポイントを逃したことに気づきました! 保存を行っていないため、データベース レコードは更新されません。いつでも。

私がやっていることの要点は、バックグラウンド プロセスを高速化するためにモデル データをインスタンス変数に引き出すことです。そのため、最初にロードされたデータは、プロセス実行の最後までデータベースに保存されません。

私が望んでいたのは、ある列の値が既に読み込まれている別のモデルに関連することを熱心に読み込むときに指定できる方法でした。

例えば、

User.find(:all, :include => [ {:contact_records => (:contacts as User)] } ])

または類似。

私の知る限り、Rails にはそのような構文はありませんが、間違っていることを願っています! :)

これで少しわかりやすくなることを願っています。返信ありがとうございます。

于 2009-04-17T12:47:58.960 に答える