Question

J'utilise l'héritage sur une seule table (STI) sur l'un de mes modèles pour une application Rails et j'ai des problèmes pour stocker les objets de modèle sur une constante. J'ai isolé le problème dans un exemple de projet et l'ai soumis à GitHub: http://github.com / fcoury / rails-sti-caching

Ce que j'essaie de faire est de charger une instance de modèle (dans ce cas, un modèle Music qui hérite du modèle Media via STI) sur un initialiseur (dans le répertoire /config/initializers/ de Rails) et de la maintenir constante:

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

Et j’ai un exemple de contrôleur qui effectue les opérations suivantes:

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

Et une vue qui va avec:

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

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

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

La première fois que ce code est exécuté, le résultat de la balise <pre> est le suivant:

  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

Cependant, si je ne fais que recharger la page, voici ce qui sera affiché:

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?

Quelqu'un connaît-il la raison de cette erreur?

Était-ce utile?

La solution

Ma première idée serait que Rails libère (invalide) tous les objets du modèle après avoir traité une demande. Ainsi, class: Music - class obj_id: 13067420 devient inutilisable dans la 2e demande. Je suggérerais de jeter un coup d'œil au code source ActiveRecord et de déterminer qui invalide les objets du modèle.

Ce didacticiel de mise en cache de modèles de rails peut également être utile: http: / /railscasts.com/episodes/115-caching-in-rails-2-1

Autres conseils

En gros, vous ne pouvez pas y arriver.

Dans l'environnement de développement, à chaque demande, vos classes sont rechargées. Cela signifie qu'ils sont complètement détruits et recréés. L'objet de classe d'origine a disparu, un nouvel objet prend sa place.

Si vous conservez un objet dans les requêtes, il héritera de la deuxième requête de la classe d'origine, celle qui a été supprimée. La constante pointant vers cette classe pointe maintenant vers un nouvel objet de classe, identique ou non identique selon que vous avez modifié la définition de la classe ou les plug-ins qui l'affectent, mais il s'agira toujours d'un objet de classe différent dans mémoire, et l'ancien objet ne saura pas qu'il devrait hériter de ce nouvel objet de classe.

Je suppose que si vous exécutez votre application dans un environnement de production, cela fonctionnera.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top