Using Rails serialize to save hash to database

Ruby on-RailsRubySerializationActiverecord

Ruby on-Rails Problem Overview


I'm try to save a hash mapping ids to a number of attempts in my rails app. My migration to the database to accommodate this new column:

class AddMultiWrongToUser < ActiveRecord::Migration
  def self.up
    add_column :users, :multi_wrong, :string
  end

  def self.down
    remove_column :users, :multi_wrong
  end
end

In my model I have:

class User < ActiveRecord::Base 
 serialize :multi_wrong, Hash
end

But when I use the rails console to test this by doing:

user = User.create()
user.multi_wrong = {"test"=>"123"}
user.save

The output is false. What's going wrong here?

Ruby on-Rails Solutions


Solution 1 - Ruby on-Rails

The column type is wrong. You should use Text instead of String. Therefore, your migration should be:

 def self.up
   add_column :users, :multi_wrong, :text
 end

Then Rails will properly convert it into YAML for you (and perform proper serialization). Strings fields are limited in size and will only hold especially-small values.

Solution 2 - Ruby on-Rails

UPDATED:

Exact implementation will depend on your database, but PostgreSQL now has json and jsonb columns which can natively store your hash/object data and allow you to query against the JSON with ActiveRecord!

change your migration and you're done.

class Migration0001
  def change
    add_column :users, :location_data, :json, default: {}
  end
end

ORIGINAL:

For more details: rails docs && apidock

Make sure your column is :text and not :string

Migration:

$ rails g migration add_location_data_to_users location_data:text

should create:

class Migration0001
  def change
    add_column :users, :location_data, :text
  end
end

Your Class Would Look Like:

class User < ActiveRecord::Base
  serialize :location_data
end

Available Actions:

b = User.new
b.location_data = [1,2,{foot: 3, bart: "noodles"}]
b.save

More Awesome?!

utilize postgresql hstore

class AddHstore < ActiveRecord::Migration  
  def up
    enable_extension :hstore
  end

  def down
    disable_extension :hstore
  end
end 

class Migration0001
  def change
    add_column :users, :location_data, :hstore
  end
end

With hstore you can set attributes on the serialized field

class User < ActiveRecord::Base  
  # setup hstore
  store_accessor :location_data, :city, :state
end

Solution 3 - Ruby on-Rails

Rails 4 has a new feature called Store, so you can easily use it to solve your problem. You can define an accessor for it and it is recommended you declare the database column used for the serialized store as a text, so there's plenty of room. The original example:

class User < ActiveRecord::Base
  store :settings, accessors: [ :color, :homepage ], coder: JSON
end

u = User.new(color: 'black', homepage: '37signals.com')
u.color                          # Accessor stored attribute
u.settings[:country] = 'Denmark' # Any attribute, even if not specified with an accessor

# There is no difference between strings and symbols for accessing custom attributes
u.settings[:country]  # => 'Denmark'
u.settings['country'] # => 'Denmark'

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestioncmwrightView Question on Stackoverflow
Solution 1 - Ruby on-RailsBenjamin Tan Wei HaoView Answer on Stackoverflow
Solution 2 - Ruby on-RailsBlair AndersonView Answer on Stackoverflow
Solution 3 - Ruby on-RailsAboozar RajabiView Answer on Stackoverflow