Skip to content

Instantly share code, notes, and snippets.

@seapy
Created August 24, 2014 08:04
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save seapy/1b129c9aa140f16803ce to your computer and use it in GitHub Desktop.
Save seapy/1b129c9aa140f16803ce to your computer and use it in GitHub Desktop.

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
end
add_index :settings, :key, :unique => true
end
def self.down
drop_table :settings
end
end
class Setting < ActiveRecord::Base
serialize :value
class << self
attr_accessor :__cache
attr_accessor :__cache_expires_in
end
def self.method_missing(method, *args)
# init memcache if needed
@__cache = ActiveSupport::Cache::MemCacheStore.new 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)
else
setting = self.new if !setting
setting.key = method.to_s if setting.key.blank?
setting.value = value
if setting.save
return value[:value]
end
end
end
# get mode
else
# skip memcache?
if method[-1,1] == "!"
method = method.chop
skip_cache = true
end
if skip_cache.nil? && (result = @__cache.read(method.to_s))
return result[:value]
else
result = self.find(:first, :conditions => {:key => method})
if result
@__cache.write(method, result.value, :expires_in => @__cache_expires_in)
return result.value[:value]
end
end
end
return nil
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment