Sunday, December 13, 2009

Storing single values in Rails with ActiveRecord

Sometimes you want to store a bunch of single values that are not related to anything, and of course they are not constant values, it is better to put it in a constant or in a yaml config file if they are constant values.

This is what i usually do, maybe there is a better solution out there, but this one is very simple.
It's kind of make an active record object to work like a Hash, or key-value store.

Create the migration(name it the way you like it):



class CreateSingleValues < ActiveRecord::Migration
def self.up
create_table :single_values do |t|
t.string :key
t.string :value
end
end

def self.down
drop_table :single_values
end
end



And this is the code:



class SingleValue < ActiveRecord::Base

def self.[](key)
val = self.find_by_key(key.to_s)
val.value if val
end

def self.[]=(key, value)
val = self.find_by_key(key.to_s)
if val
value.nil? ? val.delete : val.update_attribute(:value, value)
else
self.create(:key => key.to_s, :value => value) unless value.nil?
end
end

end




I add the [] operator methods to the active record class.

this way I can store values like this:
SingleValue[:foo] = "bar" or SingleValue["foo"] = "bar"

and then retrieve it with:
SingleValue[:foo] or SingleValue["foo"]

It returns nil if the key is not found, and delete the record if you assign a nil value.
For example SingleValue[:foo] = nil will delete SingleValue[:foo] if it exists.
Also you can do substitution on the key like SingleValue["foo_#{bar}"] if you are going to get the key at runtime.

You may find convenient to add an index on the key column for quicker searches if you are storing many values.

Note that you can only store single string values(or numbers that will be returned as strings).
If you want to store complete objects you can serialize them into the value column with ActiveRecord "serialize" method,
you may have to change the column type to 'text' , the implementation will be the same I think, try it!

Bye!