Ruby on Rails | Screencasts | Download | Documentation | Weblog | Community | Source

Ticket #7537 (new defect)

Opened 1 year ago

Last modified 1 year ago

serialize :field doesn't like you to serialize instances of autoloaded classes

Reported by: pdcawley Assigned to: core
Priority: normal Milestone: 2.x
Component: ActiveRecord Version: edge
Severity: normal Keywords:
Cc:

Description

I have a custom class that I'm using as the value of a serialized field and, because I want to continue to develop said class, it gets reloaded with every request in development.

However, when I try to fetch an object from the database and access the serialized field, instead of getting an instance of CustomClass back, I get an instance of YAML::Object. It seems that the YAML deserializer is checking to see if CustomClass exists and if it doesn't is falls back to making a YAML::Object rather than triggering Rails' autoload magic. I'm working around it by doing:

class CustomClass
  def self.force_load
  end
end

class MyModel < ActiveRecord::Base
  serialize :some_attr

  def some_attr
    CustomClass.force_reload
    self[:some_attr] ||= CustomClass.new
  end
end

But it's not exactly pretty. I don't want to go using composed_of because my custom class doesn't really make sense as a value object. It seems to me that YAML needs patching to force Rails to try and load the appropriate library before giving up and making a YAML::Object.

Change History

(follow-up: ↓ 2 ) 02/16/07 22:56:10 changed by jkit

I was able to reproduce the described behavior, and found a different way to get around it: I added require 'thing' in environment.rb. That should force rails to load it up front. Despite that work-around, I'm still looking into making the auto-loading handle this properly.

(in reply to: ↑ 1 ) 02/16/07 23:18:01 changed by jkit

I realized I wasn't very clear in my previous post. I added require 'thing' in environment.rb in order to preload the model in app/models/thing.rb. The serialized object I saved to the db was an instance of Thing. In the original example, require 'custom_class' would probably do the trick.

Replying to jkit:

I was able to reproduce the described behavior, and found a different way to get around it: I added require 'thing' in environment.rb. That should force rails to load it up front. Despite that work-around, I'm still looking into making the auto-loading handle this properly.

05/08/07 09:31:41 changed by nurmiranta

Here is a fix to make autoloading work. Add this to environment.rb:

YAML.add_domain_type("ActiveRecord,2007", "") do |type, val|
  klass = type.split(':').last.constantize
  YAML.object_maker(klass, val)
end

class ActiveRecord::Base
  def to_yaml_type
    "!ActiveRecord,2007/#{self.class}"
  end
end

05/08/07 09:49:21 changed by nurmiranta

Addition, might be good to add,

class ActiveRecord::Base
  def to_yaml_properties
    ['@attributes']
  end
end

so that it only stores the attributes.