Railsの定数でモデルインスタンスをキャッシュする問題
-
06-07-2019 - |
質問
Railsアプリのモデルの1つで単一テーブル継承(STI)を使用していますが、モデルオブジェクトを定数に保存するのに問題があります。問題をサンプルプロジェクトに分離し、GitHubに送信しました: http://github.com / fcoury / rails-sti-caching
私がやろうとしているのは、初期化子(Railsの/config/initializers/
ディレクトリ内)にモデルインスタンス(この場合はSTIを介してMediaモデルから継承する音楽モデル)を読み込み、定数に保持することです。
MUSIC_CACHE = Hash.new
Music.all.each { |m| MUSIC_CACHE[m.id] = m }
そして、以下を実行するサンプルコントローラーがあります:
class MusicsController < ApplicationController
def index
require 'pp'
pp MUSIC_CACHE
@debug = []
MUSIC_CACHE.each_pair do |k, v|
music = Music.find(k)
d "Object for Music.find(#{k}) => class: #{music.class} - class obj_id: #{music.class.object_id} - #{music.inspect}"
d "Object for MUSIC_CACHE[#{k}] => class: #{v.class} - class obj_id: #{v.class.object_id} - #{v.inspect}"
begin
d " - Music.is_a?(Media) => #{v.is_a?(Media)}"
d " - Try to call name => #{v.name}"
rescue
d "*** Error raised:\n#{$!}"
end
end
@musics = Music.all
end
def d(s)
puts s
@debug << s
end
end
そしてそれに伴うビュー:
<h1 id="music">Music</h1>
<ul>
<% for m in @musics %>
<li><%= m.name %> - <%= m.file %></li>
<% end %>
</ul>
<pre><%=h @debug.join("\n") %></pre>
このコードの初回実行時、<pre>
タグの出力は次のとおりです。
Object for Music.find(2) => class: Music - class obj_id: 13067420 - #<Music id: 2, name: "5th Symphony", file: "5s.mp3", type: "Music", created_at: "2009-05-06 16:31:41", updated_at: "2009-05-06 16:31:41">
Object for MUSIC_CACHE[2] => class: Music - class obj_id: 13067420 - #<Music id: 2, name: "5th Symphony", file: "5s.mp3", type: "Music", created_at: "2009-05-06 16:31:41", updated_at: "2009-05-06 16:31:41">
- Music.is_a?(Media) => true
- Try to call name => 5th Symphony
ただし、ページをリロードするだけの場合、出力される内容は次のとおりです。
Object for Music.find(2) => class: Music - class obj_id: 18452280 - #<Music id: 2, name: "5th Symphony", file: "5s.mp3", type: "Music", created_at: "2009-05-06 16:31:41", updated_at: "2009-05-06 16:31:41">
Object for MUSIC_CACHE[2] => class: Music - class obj_id: 13067420 - #<Music id: 2, name: "5th Symphony", file: "5s.mp3", type: "Music", created_at: "2009-05-06 16:31:41", updated_at: "2009-05-06 16:31:41">
- Music.is_a?(Media) => false
*** Error raised:
You have a nil object when you didn't expect it!
You might have expected an instance of Array.
The error occurred while evaluating nil.include?
このエラーの背後にある理論的根拠を誰か知っていますか?
解決
最初のアイデアは、Railsがリクエストを処理した後、すべてのモデルオブジェクトを解放(無効化)することです。したがって、2番目のリクエストではclass: Music - class obj_id: 13067420
は使用できなくなります。 ActiveRecordのソースコードを見て、モデルオブジェクトを無効にしている人を見つけることをお勧めします。
また、このRailsモデルキャッシングチュートリアルは便利です。 http:/ /railscasts.com/episodes/115-caching-in-rails-2-1
他のヒント
基本的にはできません。
開発環境では、リクエストごとにクラスがリロードされます。つまり、それらは完全に破壊され、再作成されます。元のクラスオブジェクトはなくなり、新しいものが代わりになります。
リクエスト間でオブジェクトを保持する場合、2番目のリクエストでは、オブジェクトは元のクラス(削除されたクラス)を継承します。そのクラスを指す定数は、新しいクラスオブジェクトを指すようになりました。これは、クラス定義またはそれに影響するプラグインを変更したかどうかによって、以前のものと同一である場合とそうでない場合がありますが、メモリ。古いオブジェクトは、この新しいクラスオブジェクトから継承する必要があることを認識しません。
実稼働環境でアプリケーションを実行すれば、それは機能すると思います。