Simple ActiveRecord serialise problem

24 views
Skip to first unread message

Andy Jeffries

unread,
Oct 6, 2011, 6:02:58 AM10/6/11
to rubyonra...@googlegroups.com
When I create a table with the following SQL:

# create table foos (id SERIAL, content VARCHAR(255));

And define a class as follows:

class Foo < ActiveRecord::Base
serialize :content, JSON
end

Creating a new instance of the class gives an error:

> f = Foo.new
NoMethodError: undefined method `read' for nil:NilClass
from /Users/andy/.rvm/gems/ruby-1.9.2-p290/gems/activesupport-3.1.0/lib/active_support/whiny_nil.rb:48:in `method_missing'
from /Users/andy/Code/FakePlatform/vendor/gems/Darwin/gems/json-1.4.6/lib/json/common.rb:286:in `load'
from /Users/andy/.rvm/gems/ruby-1.9.2-p290/gems/activerecord-3.1.0/lib/active_record/base.rb:1938:in `block in set_serialized_attributes'

Does anyone have any ideas how to fix this?

It should work (it's such a simple case).

Cheers,


Andy

Frederick Cheung

unread,
Oct 6, 2011, 8:30:11 AM10/6/11
to Ruby on Rails: Talk


On Oct 6, 11:02 am, Andy Jeffries <a...@andyjeffries.co.uk> wrote:
> When I create a table with the following SQL:
>
> # create table foos (id SERIAL, content VARCHAR(255));
>
> And define a class as follows:
>
> class Foo < ActiveRecord::Base
>   serialize :content, JSON
> end

the second argument to serialise is used to say that you always want
the serialised object to be of a certain class (e.g. Hash, an
application specific class etc.). I'm not sure what you meant by
passing JSON as that argument but I suspect that it isn't doing what
you think it is.

Fred

>
> Creating a new instance of the class gives an error:
>
> > f = Foo.new
>
> NoMethodError: undefined method `read' for nil:NilClass
> from /Users/andy/.rvm/gems/ruby-1.9.2-p290/gems/activesupport-3.1.0/lib/active_s upport/whiny_nil.rb:48:in `method_missing'
>  from /Users/andy/Code/FakePlatform/vendor/gems/Darwin/gems/json-1.4.6/lib/json/c ommon.rb:286:in `load'
>  from /Users/andy/.rvm/gems/ruby-1.9.2-p290/gems/activerecord-3.1.0/lib/active_re cord/base.rb:1938:in `block in set_serialized_attributes'

Andy Jeffries

unread,
Oct 6, 2011, 9:13:22 AM10/6/11
to rubyonra...@googlegroups.com
the second argument to serialise is used to say that you always want
the serialised object to be of a certain class (e.g. Hash, an
application specific class etc.). I'm not sure what you meant by
passing JSON as that argument but I suspect that it isn't doing what
you think it is.
I was basing it on this article (as well as a stack overflow answer) that you can provide a custom serializer in Rails 3.1:


JSON provides a dump and load method on the class so it should be acceptable as the serializer.

Is this article incorrect or my understanding of it?

Cheers,


Andy

Andy Jeffries

unread,
Oct 6, 2011, 9:33:05 AM10/6/11
to rubyonra...@googlegroups.com
I was basing it on this article (as well as a stack overflow answer) that you can provide a custom serializer in Rails 3.1:


JSON provides a dump and load method on the class so it should be acceptable as the serializer.

Is this article incorrect or my understanding of it?
Having just had a read of ActiveRecord::Base, I still can't see how I go wrong…

Base#serialize (line 557 of base.rb in ActiveRecord 3.1.0)

if the object supplied as the second argument responds to :load and :dump (which JSON does), then it uses that object, if not it wraps it in a YAMLColumn and sets the entry in serialized_attributes to that object.  Then in:

Base#arel_attributes_values (line 1963 of base.rb in ActiveRecord 3.1.0)

if there is an entry in serialized_attributes for a given attribute name (with a value put in to the coder variable) it calls coder.dump with the attribute value.

So, I can't understand why JSON wouldn't work as a second parameter...

Cheers,


Andy

Tim Shaffer

unread,
Oct 6, 2011, 9:44:04 AM10/6/11
to rubyonra...@googlegroups.com
You're using the syntax of serialize properly.

The problem looks like it's in the JSON.load method not properly handling a nil value:

def load(source, proc = nil)
  if source.respond_to? :to_str
    source = source.to_str
  elsif source.respond_to? :to_io
    source = source.to_io.read
  else
    source = source.read
  end
  result = parse(source, :max_nesting => false, :allow_nan => true)
  recurse_proc(result, &proc) if proc
  result
end    

Basically it gets to the line "source = source.read" and throws up because source is nil and nil doesn't have a read method.

Andy Jeffries

unread,
Oct 6, 2011, 9:45:03 AM10/6/11
to rubyonra...@googlegroups.com
I've also just tried upgrading JSON to 1.6.0 (as that's the version that seems to be installed if I do gem install json), same problem.

Cheers,


Andy
Reply all
Reply to author
Forward
0 new messages