私の現在の 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) 例を再構築する際にタイプミスやエラーが発生した可能性がありますが、それらは無視してください。私が知る必要があるのは、データベースにアクセスせずに熱心にロードされたユーザーをリロードできるかどうかだけです。
よろしくお願いします!
更新: 以下で説明するように、モデル データはプロセス実行の最後までデータベースに保存されないため、データベース内のデータは変更されていないため、リロードは機能しません。