Caching, ActiveRecord, and disappearing methods

I was very surprised to see that my model is missing some of its attributes after first request in development mode.

The error occurred while evaluating nil.include?

With the backtrace ending with:

/var/lib/gems/1.8/gems/activerecord-2.3.2/lib/active_record/attribute_methods.rb:142:in 'create_time_zone_conversion_attribute?'

Such a magic… ;-) Here is the recipe. Place in your controller:

def index
  @posts = Rails.cache.fetch(:all_posts) { Post.all }
end

Go to your view page and press refresh.

The reason is that ActiveRecord stores some information in so called class inheritable attributes. These are stored as your model class variable (Post in that case). Let’s see…

>> before_refresh = Post
>> before_refresh.object_id
=> 70091079977500
>> before_refresh.inheritable_attributes
=> {:skip_time_zone_conversion_for_attributes=>[], :record_timestamps=>true, :reject_new_nested_attributes_procs=>{}, :default_scoping=>[], :scopes=>{:scoped=>#<Proc:0x00007f7eb4450c10@/var/lib/gems/1.8/gems/activerecord-2.3.2/lib/active_record/named_scope.rb:87>}}
>> before_refresh.inheritable_attributes.object_id
=> 70091079977380

>> reload!

>> Post.object_id
=> 70091079300300 # different!
>> before_refresh.inheritable_attributes
=> {} # different!
>> before_refresh.inheritable_attributes.object_id
=> 70091099674080 # different! but similar ;-)

It looks like ActiveRecord clears inheritable_attributes before reload… But why? I do not know… I am still learning ;-)

Anyway, here are some other reasons why you should not cache your models but described with the problem of requiring models.

If you still want to cache your models (why not?), here is the tip for disabling caching in your development mode (not so easy). You can set memcached as caching store and give it invalid port number. Queries will be missed all the time without any exception raised while writing to cache.

Edit:
Michał Kwiatkowski found better solution.

Posted by Kacper Bielecki Mon, 29 Jun 2009 16:28:00 GMT