Pergunta

Eu estou usando Single-Table Inheritance (STI) em um dos meus modelos para um Rails App e eu estou tendo problemas armazenar objetos de modelo em uma constante. Eu ter isolado o problema em um projeto de exemplo e apresentou-o GitHub: http://github.com / fcoury / rails-sti-caching

O que estou tentando fazer é carregar uma instância do modelo (neste caso, um modelo de Música, que herda o modelo de mídia via STI) em um inicializador (no diretório /config/initializers/ Rails) e mantê-lo em uma constante:

MUSIC_CACHE = Hash.new
Music.all.each { |m| MUSIC_CACHE[m.id] = m }

E eu tenho um controlador de amostra que faz o seguinte:

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

e uma vista para ir com ele:

<h1 id="music">Music</h1>

<ul>
  <% for m in @musics %>
  <li><%= m.name %> - <%= m.file %></li>
  <% end %>
</ul>

<pre><%=h @debug.join("\n") %></pre>

A primeira vez que esse código é executado, a saída na etiqueta <pre> é esta:

  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

No entanto, se eu apenas recarregar a página, aqui está o que é emitido:

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?

Alguém sabe a razão por trás deste erro?

Foi útil?

Solução

A minha primeira ideia seria que Rails libera (invalida) todo o modelo objetos depois de cumprir um pedido. Então class: Music - class obj_id: 13067420 torna-se inutilizável no 2º pedido. Eu sugiro ter um olhar para o código-fonte ActiveRecord e descobrir o que invalida objetos de modelo.

Além disso, este modelo trilhos caching tutorial pode ser útil: http: / /railscasts.com/episodes/115-caching-in-rails-2-1

Outras dicas

Basicamente, você não pode com isso.

No ambiente de desenvolvimento, com cada solicitação, suas aulas são recarregados. Isso significa que eles estão completamente destruídas e recriadas. O objeto classe original está desaparecido, um novo toma o seu lugar.

Se você manter um objeto em pedidos, na segunda solicitação o objeto ainda vai herdar da classe original, aquele que foi removido. A constante que apontava para essa classe agora aponta para uma nova classe de objeto, que pode ou não ser idêntico ao anterior, dependendo se você mudou a definição de classe ou plugins que o afetam, mas ainda vai ser um objeto de classe diferente em memória, e o objeto antigo não vai saber que ele deve herdar a partir deste novo objeto da classe.

Eu suponho se você executar o aplicativo no ambiente de produção, ele vai trabalhar.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top