When you need to store structured data (like Ruby hashes) in a single database column with ActiveRecord, a simple way is to use PostgreSQL's jsonb
columns. ActiveRecord will automatically serialize and deserialize your Hash to and from JSON, and you can index JSON paths for fast reads.
As an alternative,
ActiveRecord::Store
Show archive.org snapshot
offers a way to store hashes in a single database column. This card will show you how to migrate those hashes in an ActiveRecord::Migration
by example:
Let's assume you have got a model User
with settings stored as YAML in a single column:
class User < ActiveRecord::Base
typed_store :settings, coder: YAML do |s|
s.string :lang
s.integer :show_number_of_posts
end
end
Note: in this example we used a
typed_store
Show archive.org snapshot
, which basically is a store with type constraints.
Now you notice that the setting lang
was not named well and you'd rather have language
. So let's rename the settings key:
class RenameLanguageKeyInUser < ActiveRecord::Migration
class User < ActiveRecord::Base
def rename_settings_key!(from, to)
from, to = from.to_s, to.to_s
old_settings = YAML.load(self.settings)
new_settings = old_settings.dup
if new_settings.has_key?(from)
new_settings[to] = new_settings.delete(from)
self.update_attributes!(settings: YAML.dump(new_settings))
puts "Migrated User settings from #{old_settings.to_s} to #{new_settings.to_s}"
else
puts "Did not migrate User settings, '#{from}' was not a settings key"
end
end
end
def up
User.find_each { |user| user.rename_settings_key!(:lang, :language) }
end
def down
User.find_each { |user| user.rename_settings_key!(:language, :lang) }
end
end
Here are some key pointers of this migration:
- you should never use your actual application models in migrations as those might change over time. That's why we embed the model into the migration
- use the specified
coder
to deserialize/serialize your store - manipulate the data in between
- the output is optional of course but might be helpful when you first test the migration and rollback