Over the last few weeks I have been playing with the idea of having a simple database backed key value store using Rails ActiveRecord. The ActiveRecord class should act like a singleton where arbitrary keys can be set with a value of any type (simple values, hashes, arrays or complex objects). I have come up with the idea of using method missing to set and retrieve the key / value pair where the value’s are saved as yaml and then cast back to the correct type when retrieved.
class Application < ActiveRecord::Base
set_table_name "application_settings"
def self.method_missing(method, *args, &block)
return self.send method, *args, &block if self.respond_to? method
method_name = method.to_s
if method_name =~ /=/
return self.set method_name.gsub("=", ""), args.first
else
return self.get method_name
end
end
private
def self.get setting
entry = Application.where(:key => setting).first
entry.nil? ? nil : YAML.load(entry.value)
end
def self.set key, value
setting = Application.where(:key => key).first || Application.new(:key => key)
setting.update_attribute(:value, value.to_yaml)
end
end
Below is the migration needed to setup the database table for your application settings class.
class CreateApplicationSettings < ActiveRecord::Migration
def up
create_table :application_settings, :id => false do |t|
t.string :key
t.text :value
t.timestamps
end
add_index :application_settings, :key, :unique => true
end
def down
drop_table :application_settings
end
end
Using the class it is possible to set a value to any arbitrary key by calling the setting name setter method just like it is a defined class attribute.
Application.some_arbitrary_setting = 12903
Application.my_hash_foo = { :foo => "bar" }
To retrieve the setting make a method call to the key name as if it were a defined class attribute.
Application.some_arbitrary_setting
=> 12903
Application.my_hash_foo
=> {:foo=>"bar"}