Skip to content
Create a gist now

Instantly share code, notes, and snippets.

@samqiu / forked from jimeh/
Created Dec 13, 2011

A simple key/value store model for Rails using the database and memcache

Rails Setting model

This is a semi-quick key/value store I put together for a quick way to store temporary data related to what's in my database, in a reliable way. For example, I'm using it to keep track of where a hourly and a daily crontask that processes statistics left off, so it can resume only processing and summarizing new data on the next run.

Code quality most likely is not great, but it works. And I will update this gist as I update my project.

How It Works

The settings table has two columns, a key and a value column. The value column is serialized, so you can technically store almost anything in there. Memcache is also used as a caching layer to minimize database calls.

Example usage

# fetching a value
>> Setting.hello
=> nil

# setting a value, writes it to memcache, and saves or updates a database
# record is the form of {:key => "hello", :value => serialize(["world"])}
>> Setting.hello = ["world"]
=> ["hello"]

# fetching the value again, which will only read from memcache
>> Setting.hello
=> ["hello"]

# force fetch from database and update memcache
>> Setting.hello!
=> ["hello"]

# remove the hello key from memcache and the database
>> Setting.hello = nil
=> nil

# default memcache expire_in option is 6.hours, you can change it...
>> Setting.__cache_expires_in = 1.hour
=> 3600 seconds
class CreateSettings < ActiveRecord::Migration
def self.up
create_table :settings, :options => "ENGINE=InnoDB DEFAULT CHARSET=utf8" do |t|
t.string :key
t.text :value
add_index :settings, :key, :unique => true
def self.down
drop_table :settings
class Setting < ActiveRecord::Base
serialize :value
class << self
attr_accessor :__cache
attr_accessor :__cache_expires_in
def self.method_missing(method, *args)
# init memcache if needed
@__cache = if @__cache.nil?
@__cache_expires_in = 6.hours if @__cache_expires_in.nil?
method = method.to_s
# set mode
if method[-1,1] == "="
if args.size > 0
# key/value setup
method = method.chop
method = method.chop if method[-1,1] == "!"
value = {:value => args[0]}
@__cache.write(method, value, :expires_in => @__cache_expires_in)
setting = self.find(:first, :conditions => {:key => method})
if value[:value].nil?
setting.destroy if setting
@__cache.write(method, nil, :expires_in => 0.seconds)
setting = if !setting
setting.key = method.to_s if setting.key.blank?
setting.value = value
return value[:value]
# get mode
# skip memcache?
if method[-1,1] == "!"
method = method.chop
skip_cache = true
if skip_cache.nil? && (result =
return result[:value]
result = self.find(:first, :conditions => {:key => method})
if result
@__cache.write(method, result.value, :expires_in => @__cache_expires_in)
return result.value[:value]
return nil
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.