Skip to content

Instantly share code, notes, and snippets.

@alexvbush
Last active August 29, 2015 14:04
Show Gist options
  • Save alexvbush/0596c451f2e5cc0ddd62 to your computer and use it in GitHub Desktop.
Save alexvbush/0596c451f2e5cc0ddd62 to your computer and use it in GitHub Desktop.
Global Settings for storing app configuration(with caching)
class BooleanValue < Value
end
class CreateSettings < ActiveRecord::Migration
def change
create_table :settings do |t|
t.string :name
t.timestamps
end
create_table :value_associations do |t|
t.integer :setting_id
t.integer :value_id
t.string :value_type
end
create_table :string_values do |t|
t.string :value
t.timestamps
end
create_table :integer_values do |t|
t.integer :value
t.timestamps
end
create_table :float_values do |t|
t.float :value
t.timestamps
end
create_table :boolean_values do |t|
t.boolean :value
t.timestamps
end
end
end
class FloatValue < Value
end
class IntegerValue < Value
end
require 'spec_helper'
describe Setting do
subject { Setting.new }
[:name, :value].each do |propery|
it { should respond_to propery }
end
it { should validate_uniqueness_of :name }
describe Setting, 'class methods' do
subject { Setting }
[:write, :read, :remove, :remove_all].each do |m|
it { should respond_to m }
end
end
end
class Setting < ActiveRecord::Base
has_one :value_association, :dependent => :destroy
validates :name, uniqueness: true, presence: true
after_commit :flush_cache
def self.write(name, value)
setting = find_or_initialize_by_name(name)
setting.update_attribute(:value, value)
end
def self.read(name)
Rails.cache.fetch([name]) { find_by_name!(name).value.value }
end
def self.remove(name)
find_by_name!(name).destroy
end
def self.remove_all
destroy_all
end
def value
value_association.value
end
def value=(new_value)
if self.value_association
self.value_association.destroy
flush_cache
end
self.value_association = ValueAssociation.new(value: Value.new_value(new_value))
end
private
def flush_cache
Rails.cache.delete([name])
end
end
shared_examples_for 'value' do
it { should respond_to :value }
it { should have_one :setting }
it { should have_one :value_association }
end
class StringValue < Value
end
class Value < ActiveRecord::Base
self.abstract_class = true
has_one :value_association, as: :value
has_one :setting, through: :value_association
attr_accessible :value
def self.new_value(value)
case value
when String then StringValue.new(value: value)
when Integer then IntegerValue.new(value: value)
when Float then FloatValue.new(value: value)
when TrueClass, FalseClass then BooleanValue.new(value: value)
else
raise TypeError, "Cannot find type for #{value}"
end
end
end
class ValueAssociation < ActiveRecord::Base
belongs_to :setting
belongs_to :value, :polymorphic => true, :dependent => :destroy
attr_accessible :setting, :value
end
require 'spec_helper'
describe StringValue do
subject { StringValue.new }
it_behaves_like 'value'
end
describe IntegerValue do
subject { IntegerValue.new }
it_behaves_like 'value'
end
describe FloatValue do
subject { FloatValue.new }
it_behaves_like 'value'
end
describe BooleanValue do
subject { BooleanValue.new }
it_behaves_like 'value'
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment