ActiveRecord Associative Array Directly Into The Database
The other day, I came across the following code in a Rails project of mine:
value = SystemSetting[:some_key_here].to_i
Hmm, I could not recoqnize SystemSetting, so I guessed it was something a colleague of mine had introduced while I was away from the project. I guessed it to be an associative array, setup in the rails environment files, to hold various application system settings. I guessed wrong! SystemSetting turned out to be a real ActiveRecord model class, which simply acted as an associative array directly into a table in the database. And thanks to ActiveRecord and the Ruby language, it could do this in a very elegant way, in only a few lines of code.
Here is the system_settings table:
Column Name | Data Type
-----------------------
id | INTEGER
name | VARCHAR
value | VARCHAR
-----------------------
And here is the clever ActiveRecord model class:
class SystemSetting < ActiveRecord::Base
def self.[](name)
find_by_name(name)
end
def self.[]=(name,value)
setting = find_by_name(name)
if setting
setting.value = value
setting.save
else
setting = self.create(:name => name, :value => value)
end
end
def to_i
value.to_i
end
def to_s
value
end
end
So what are these few ruby lines doing? For starters, it is overriding the array access methods [] and []=, in the two first methods. In the first method, the array entry read, it implements it as a find_by_name ActiveRecord call, that simply returns a SystemSetting instance, if the name matches the array index name. In the second method, the array entry assignment, it implements it as either an update of an existing row on the array index name, or as a create of a new entry, if the name is not found. Lastly, there are the to_i and to_s methods, which provides easy typed access to the value of an entry.
In my eyes, this is a damned elegant trick!
The class does not provide help for cleanup in the array. I think this could easily be done, by deleting entries by name, if nil are assigned to them.


That is indeed, very simple and elegant.
Perhaps the only improvement I could suggest is caching the records as they are returned. If you happen to access a particular setting repeatedly, you’ll end up with multiple database hits.
February 17th, 2008 at 00:13If for like this, you may like the plugin I wrote for my setting. (see http://biorails.org/svn/biorails/plugins/alces_act_as_setting/ ) Its also add the ability to use the setting name as a class level method as well as a array eg.
SystemSetting['xxx']
SystemSetting.xxx
SystemSetting.xxx = ’ss’
To use is a simple acts_as_setting directive with a link to a xml file to define names and load initial values from xml.
class SystemSetting “#{RAILS_ROOT}/config/system_settings.yml”
February 18th, 2008 at 22:44end
I wrote a slightly different version that uses activerecord and the database (no need for xml here), but that creates members on the class to make the calls much faster and save the database hits.
July 3rd, 2008 at 05:47