1

Rails アプリのモデルの 1 つで単一テーブル継承 (STI) を使用していますが、モデル オブジェクトを定数に格納する際に問題があります。問題をサンプル プロジェクトに分離し、GitHub に送信しました: http://github.com/fcoury/rails-sti-caching

私がやろうとしているのは、イニシャライザ (Rails の/config/initializers/ディレクトリ内) にモデル インスタンス (この場合は Music モデル、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?

このエラーの背後にある理論的根拠を知っている人はいますか?

4

2 に答える 2

2

私の最初のアイデアは、Rails がリクエストを処理した後にすべてのモデル オブジェクトを解放 (無効化) するというものです。そのclass: Music - class obj_id: 13067420ため、2 番目の要求では使用できなくなります。ActiveRecord のソース コードを見て、誰がモデル オブジェクトを無効にしているかを調べることをお勧めします。

また、この Rails モデルのキャッシング チュートリアルも役立ちます: http://railscasts.com/episodes/115-caching-in-rails-2-1

于 2009-05-06T17:52:43.113 に答える
0

基本的に、それはできません。

開発環境では、リクエストごとにクラスがリロードされます。つまり、それらは完全に破壊され、再作成されます。元のクラス オブジェクトはなくなり、代わりに新しいオブジェクトが使用されます。

リクエスト間でオブジェクトを保持する場合、2 番目のリクエストでは、オブジェクトは削除された元のクラスから引き続き継承されます。そのクラスを指していた定数は、新しいクラス オブジェクトを指すようになりました。これは、クラス定義またはそれに影響を与えるプラグインを変更したかどうかに応じて、以前のものと同一である場合と同一ではない場合がありますが、それは依然として別のクラス オブジェクトです。古いオブジェクトは、この新しいクラス オブジェクトから継承する必要があることを知りません。

アプリケーションを本番環境で実行すると、うまくいくと思います。

于 2009-05-07T01:30:16.523 に答える