ActiveRecord - Simple Key Value Store


Programming in Ruby tutorials and examples

ActiveRecord - Simple Key Value Store

MaxCDN Content Delivery Network

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"}