Tutorial :Problem caching Model instances on a constant in Rails



Question:

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?


Solution:1

My first idea would be that Rails frees up (invalidates) all model objects after serving a request. So class: Music - class obj_id: 13067420 becomes unusable in the 2nd request. I'd suggest having a look at the ActiveRecord source code and finding out who invalidates model objects.

Also this rails model caching tutorial can be useful: http://railscasts.com/episodes/115-caching-in-rails-2-1


Solution:2

Basically, you can't to that.

In development environment, with each request, your classes are reloaded. That means they're completely destroyed and recreated. The original class object is gone, a new one takes its place.

If you keep an object across requests, in the second request the object will still inherit from the original class, the one that has been removed. The constant that pointed to that class now points to a new class object, which may or may not be identical to the previous depending on whether you changed the class definition or plugins that affect it, but it'll still be a different class object in memory, and the old object will not know it should inherit from this new class object.

I assume if you run your application in production environment, it'll work.


Note:If u also have question or solution just comment us below or mail us on toontricks1994@gmail.com
Previous
Next Post »