0

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

Simone Carletti
  • 173,507
  • 49
  • 363
  • 364
Ben
  • 5,030
  • 6
  • 53
  • 94

1 Answers1

1

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
EmFi
  • 23,435
  • 3
  • 57
  • 68
  • Thanks a lot for you quick enlightenment ! Then I see that : http://stackoverflow.com/questions/18349622/dynamic-active-record-store-accessors-based-off-a-user-form Which approach would you recommend ? Are both even something reliable ? – Ben Nov 20 '14 at 21:29
  • @Ben all of these methods are reliable if used consistently. But the best approach depends on what exactly you are trying to accomplish. Your original question doesn't say much about your motives. So it's difficult to provide advise. – EmFi Nov 20 '14 at 21:51
  • Let's say i just want to store the title in different languages instead installing this huge big thing that is globalize. It would then be p.langs[:title_fr], p.langs[:title_es], etc.. – Ben Nov 20 '14 at 21:53
  • Is this content going to be user generated? Will a user retrieving this information require more than one locale? Will there be multiple If so, I would suggest storing it all in associated Object. Something like LocalizedPost which would have all the translated strings from your post, a local and foreign key to the original post. And retrieving only the required localized data for your user's locale from the db. It would appear that this is exactly what globalize does. What is wrong with the globalize approach? – EmFi Nov 20 '14 at 22:15
  • The content would be more "editor generated", it remains blog posts, and yep, i'd like it not to be resteicted to a specific number of locales (hence my question). Globalize is pretty cool; but it doubles the tables (for those who needs tranlation). Problem is i have 4 models that requires only one field to be translated... I feel bad seeing the db grows just for this, even if it does not seems that rational – Ben Nov 20 '14 at 22:19
  • But as i am still looking for a good way to handle it; im still asking for advices – Ben Nov 20 '14 at 22:21
  • If it's just titles, then, what you've been asking should be fine. But if you're looking at post content which may be huge. Definitely go with the DB approach. Essentially it's a trade off between space and processing effort. With your proposed solution, rails will need to read and deserialize the serialized hash, which contains all of your localizations. Each locale increases the size of that hash and the serialized content that needs to be read, when in reality you only want a small subset of that data. – EmFi Nov 20 '14 at 22:49
  • Okay thanks a lotfor all those explanations ! I see the limitations right now. No content for now; i guess it can remains find for well.. 10 titles or so in the hash or so. I guees. – Ben Nov 20 '14 at 22:52
  • I would still advise the globalize route. In the event you expand your localized content, you won't need to go back and refactor everything. Also it's an established pattern that won't require you to implement/enable custom logic for each of your models. – EmFi Nov 20 '14 at 22:53
  • Yep I understand, sounds surely better. I guess it is about assuming 100% the multilang thing, or just doing a little thing in a corner – Ben Nov 20 '14 at 22:54
  • Well yeah, globalize's better (: – Ben Nov 24 '14 at 17:58