Problem caching Model instances on a constant in Rails


#1

I am using Single-Table Inheritance (STI) on one of my models for a
Rails App and I am having problems storing model objects on a constant.
I have isolated the problem into a sample project and submitted it to
GitHub: http://github.com/fcoury/rails-sti-caching

What I am trying to do is loading a model instance (in this case a Music
model, that inherits from the Media model via STI) on an initializer (in
Rails’ /config/initializers/ directory) and keep it on a constant:

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

And I have a sample controller that does the following:

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

And a view to go with it:

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

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

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

The first time this code runs, the output on the <pre> tag is this:

  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

However, if I just reload the page, here’s what gets outputted:

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?

Does anyone know the rationale behind this error?


#2

at first looks like the old problem of rails reloading
the classes and not recognizing the objects in memory
anymore. try set “config.cache_classes” to true in your
development.rb file or run in production mode.