KatPadi's Point

ActiveRecord::Store for Settings

Using the config.yml it’s fairly easy to store app settings that we want to be able to change quickly between environments. That is cool until your boss tells you that they need to be able to change it on the app itself a.k.a. on the fly.

The initial advice that I got for this kind of “problem” is to create a separate model that will store the “settings”. That solution is described in this very nice tutorial: http://joshsymonds.com/blog/2012/05/16/quick-and-easy-user-preferences-in-rails.

Using the tutorial above, one can easily use a module that can be included in each model that needs a “settings” functionality. (Or in the tutorial’s case “preferences”). It is very pluggable and it makes use of method_missing. More about it here.

ActiveRecord::Store for Settings

Store lets you store hashes in a single column. It uses simple key/value store within your table. Before you can use it, you have to declare the database column used for the serialized store as a text.

I first learned about this nifty ActiveRecord module from my senior. It’s discussed in Rails 4 Way, The, 3rd Edition.

Anyway, so how do we use it?

Let’s say we’re going to implement something like the “General Settings” of WordPress.

1.  Create a new column for your settings.

[pastacode lang=”ruby” message=”” highlight=”” provider=”manual”]

class AddColumnSettingsToBlog < ActiveRecord::Migration
  def change
    add_column :blogs, :settings, :text
  end
end

[/pastacode]

2. Define store in your model.

The important part here is the attr_accessor. By using it, you can access your params like regular fields.

[pastacode lang=”ruby” message=”” highlight=”” provider=”manual”]

  store :settings, accessors: [:title, :tagline, :description ]

[/pastacode]

3. No more!

You can now use your settings column like a boss. When you play with your Rails console, it will look something like this: (assuming we already have values for it)

[pastacode lang=”bash” message=”” highlight=”” provider=”manual”]

2.1.2 :033 > b = Blogs.first
2.1.2 :033 > b.title
=> "Mah Blog"

2.1.2 :034 > b.settings

=> {"title"=>"Mah Blog", "tagline"=>"mah blag mah blag mah blag. check it out!", "description"=>"yea whateves"}

2.1.2 :035 > b.settings.class

=> ActiveSupport::HashWithIndifferentAccess

[/pastacode]

As it is seen, the type of our settings is HashWithIndifferentAccess. When I saw it first, I got weirded out but it turns out, it’s just a regular hash. The difference is any symbol key is converted to string. This means that params[:key] and params['key']  will give you the same result.

So, Which Is Better?

So, my understanding is, if you don’t need to share a “settings” module elsewhere, use “Store” because it’s funky and easy to implement. Otherwise, use the first solution so you’ll have no problem plugging it in your models. Also, the “settings” table in the latter could be reusable.

Leave a Reply

Your email address will not be published. Required fields are marked *