rails 4.1 / active record data_store hash not being initialized/serialized

373 views Asked by At

Getting around this data store thing that rails provide, I have something that troubles me

Let's say I have a simple post model, with a title, and that for some reason I'd like to store somehow dynamics attributes in another field, call "post_garbage"

In the post model, I have the simple serializer :

class Post < ActiveRecord::Base
  serialize :post_garbage
end

As I said, and besides what the rails doc explains, no named accessors are set on this post_garbage field

Playing in the console :

p = Post.first
p.post_garbage["the_stuff"] = "something"
p.save

I get an error, obviously. "the_stuff" is unknown. Stopping right here, you'd like to dump this data_store thing, safer and easier to create a new field to get the job done (I don't get the utility of it if you have to set an accessor on a data_store field).

* But *

If first an empty hash is saved in this post_garbage field :

p = Post.first
p.post_garbage = {}
p.save

The following becomes possible :

p = Post.first
p.post_garbage["whatever_i_have_in_mind"] = "some value"
p.save

Right after that :

p.post_garbage["it_then_get_dynamic"] = "and that's pretty cool"
p.save

It gets schemaless with no need to specify accessors; kind of provide the expected thing. So I wonder : many would expect a schemaless thing with the datastore, but it is not said to be used like this by the doc. But it works, with what looks like a bad trick. Wonders…

In the opposite, what's the use of the serialize :post_garbage, if, when empty, it does not returns an empty hash ?

I'd really appreciate some experienced feedback on this one as I feel like I miss something

Thanks a lot

1

There are 1 answers

11
EmFi On BEST ANSWER

This might have to do with the fact that upon object initialization there is no value in p.post_garbage.

p.post_garbage["the_stuff"] = "something"

Is trying to implicitly treat post_garbage as a hash. Which would end up being similar to

unset_variable = nil
unset_variable['hash_key'] = 'hash_value'

Using the serialize method for an attribute tells Rails it should expect to condense an Object into a key value map and store it in the database as text. But that doesn't necessarily mean your object is instantiated with this as a hash. It could be any object in particular. But that object needs to be assigned to your attribute before it can be serialized. Serialize may work out the magic to store and reconstitute it on load, but it will not make any assumptions about the form of that object if uninitialized. So without any indication of what object post_garbage is Ruby will not expect it to be a hash.

As for why does it not return an empty has when empty? There is a difference between an empty object and a missing object. (ie: {} vs nil). They are not the same thing, often a missing object is treated like an empty object. But there is value in that distinction, which I expect Rails preserves when loading a serialized attribute.

Perhaps you should try initializing it on create with something like this?

class Post < ActiveRecord::Base
  serialize :post_garbage
  after_initialize :default_values

  private
    def default_values
      self.post_garbage ||= {}
    end
end