Проблема кеширования Экземпляры модели на константе в Rails

StackOverflow https://stackoverflow.com/questions/830700

Вопрос

Я использую Single-Table Inheritance (STI) в одной из моих моделей для приложения Rails, и у меня возникают проблемы с сохранением объектов модели на константе. Я выделил проблему в пример проекта и отправил ее на GitHub: http://github.com / fcoury / рельсы-STI-кэширование

Я пытаюсь загрузить экземпляр модели (в данном случае модель Music, которая наследуется от модели Media через STI) в инициализатор (в каталоге Rails /config/initializers/) и сохранить его постоянным:

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 освобождает (делает недействительными) все объекты модели после обработки запроса. Так что class: Music - class obj_id: 13067420 становится непригодным для второго запроса. Я бы посоветовал взглянуть на исходный код ActiveRecord и выяснить, кто делает недействительными объекты модели.

Также может пригодиться это руководство по кэшированию модели рельсов: http: / /railscasts.com/episodes/115-caching-in-rails-2-1

Другие советы

В принципе, вы не можете этого сделать.

В среде разработки при каждом запросе ваши классы перезагружаются. Это означает, что они полностью разрушены и воссозданы. Оригинальный объект класса исчез, новый занимает его место.

Если вы сохраняете объект в разных запросах, во втором запросе объект все равно будет наследоваться от исходного класса, который был удален. Константа, указывающая на этот класс, теперь указывает на новый объект класса, который может быть или не быть идентичным предыдущему в зависимости от того, изменили ли вы определение класса или плагины, которые на него влияют, но это все равно будет другой объект класса в памяти, и старый объект не будет знать, что он должен наследовать от этого нового объекта класса.

Я предполагаю, что если вы запустите приложение в производственной среде, оно будет работать.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top