Fresh from the perils of not knowing that a place belongs_to a country, we generated a data structure that consisted of places, other places, and countries. This took a while to compute so, naturally, to speed things up during development iterations we wanted to cache it. Equally naturally, we didn’t want to make use of something as classy and as lauded (and already written) as acts_as_cached. No, we rolled our own.
And got an error:
ArgumentError: undefined class/module Country
It comes down to the following.
If you grab some nested models,
places = Place.find( :all, :include => [:country])
and then store the data in a file,
File.open( stored_filename, ‘w+’ ) do |f|
Marshal.dump( places, f )
end
and then, having restarted the process, retrieved the cached data,
f = File.new( stored_filename, ‘r’ )
places = Marshal.load( f )
f.close()
you get “ArgumentError: undefined class/module Country“.
It seems Ruby won’t deserialise (aka unmarshal) (aka Marshal.load) a class it has not loaded yet. The Place class was ok, because all this was happening inside place.rb. But instances of the Country class which come from the initial Place.find, using :include to preload the child rows, are stored along with the Place instances. When the Marshal.load happens in a new process, there has been no Place.find, and no auto-loading of the Country class, and the error is thrown because Ruby barfs on the presence of instances of an undefined class.
The quick and unsatisfactory fix for now was to prefix the cacheing code with a dummy reference to the Country class, e.g.
Country.class
f = File.new( stored_filename, ‘r’ )
places = Marshal.load( f )
f.close()
Presumably there is a better way.
In terms of fixing the ‘bug’ in Ruby, perhaps it is not easy for Marshal to establish where not-yet-loaded classes are defined.
this feed
1 Comment
May 1, 2007 at 7:27 pm
Check the acts_as_cached code. There’s a fix for this in there. The autoload_missing_constants method in http://require.errtheblog.com/plugins/browser/cache_fu/lib/acts_as_cached/cache_methods.rb