Skip to content

Commit

Permalink
Scoped settings for any ActiveRecord instance
Browse files Browse the repository at this point in the history
  • Loading branch information
Georg Ledermann committed May 18, 2009
1 parent 9b6c2ee commit 878f10c
Show file tree
Hide file tree
Showing 7 changed files with 115 additions and 22 deletions.
1 change: 1 addition & 0 deletions MIT-LICENSE
@@ -1,4 +1,5 @@
Copyright (c) 2006 Alex Wayne
Some additional features added 2009 by Georg Ledermann

Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
Expand Down
14 changes: 13 additions & 1 deletion README.rdoc
Expand Up @@ -52,5 +52,17 @@ Now even if the database is completely empty, you app will have some intelligent

Settings.some_setting # returns 'footastic'

Settings may be bound to any existing ActiveRecord object. Define this association like this:

That's all there is to it!. Enjoy!
class User < ActiveRecord::Base
has_settings
end

Then you can set/get a setting for a given user instance just by doing this:

user = User.find(123)
user.settings.foo = 'Foo of user with ID 123'
user.settings.foo # returns 'Foo of user with ID 123'


That's all there is to it! Enjoy!
4 changes: 4 additions & 0 deletions generators/settings_migration/templates/migration.rb
Expand Up @@ -3,8 +3,12 @@ def self.up
create_table :settings, :force => true do |t|
t.string :var, :null => false
t.text :value, :null => true
t.integer :object_id, :null => true
t.string :object_type, :limit => 30, :null => true
t.timestamps
end

add_index :settings, [ :object_type, :object_id, :var ], :uniq => true
end

def self.down
Expand Down
12 changes: 11 additions & 1 deletion init.rb
@@ -1 +1,11 @@
require 'settings'
require 'settings'

ActiveRecord::Base.class_eval do
def self.has_settings
class_eval do
def settings
Settings.scoped_by_object_type_and_object_id(self.class.base_class.to_s, self.id)
end
end
end
end
23 changes: 17 additions & 6 deletions lib/settings.rb
Expand Up @@ -50,8 +50,8 @@ def self.all
result.with_indifferent_access
end

#retrieve a setting value by [] notation
def self.[](var_name)
#retrieve a setting value
def self.get(var_name)
if var = object(var_name)
var.value
elsif @@defaults[var_name.to_s]
Expand All @@ -60,19 +60,30 @@ def self.[](var_name)
nil
end
end
#set a setting value by [] notation
def self.[]=(var_name, value)

#set a setting value
def self.set(var_name, value)
var_name = var_name.to_s

record = object(var_name) || Settings.new(:var => var_name)
record.value = value
record.save
value
end

#get a setting value by [] notation
def self.[](var_name)
self.get(var_name)
end

#set a setting value by [] notation
def self.[]=(var_name, value)
self.set(var_name, value)
end

#retrieve the actual Setting record
def self.object(var_name)
Settings.find_by_var(var_name.to_s)
self.scoped_by_object_type_and_object_id(nil, nil).find_by_var(var_name.to_s)
end

#get the value field, YAML decoded
Expand Down
72 changes: 58 additions & 14 deletions test/settings_test.rb
Expand Up @@ -26,7 +26,7 @@ def test_get
assert_setting 'foo', :test
assert_setting 'bar', :test2
end

def test_update
assert_assign_setting '321', :test
end
Expand All @@ -48,25 +48,69 @@ def test_serialization_of_float
assert_equal 0.02, Settings.float * 2
end

def test_object_scope
user1 = User.create :name => 'First user'
user2 = User.create :name => 'Second user'


assert_assign_setting 1, :one, user1
assert_assign_setting 2, :two, user2

assert_setting 1, :one, user1
assert_setting 2, :two, user2

assert_nil Settings.one
assert_nil Settings.two
assert_nil user1.settings.two
assert_nil user2.settings.one
end

private
def assert_setting(value, key)
def assert_setting(value, key, scope_object=nil)
key = key.to_sym
assert_equal value, eval("Settings.#{key}")
assert_equal value, Settings[key.to_sym]
assert_equal value, Settings[key.to_s]

if scope_object
assert_equal value, scope_object.instance_eval("settings.#{key}")

# Array indexing on scopes does not work. Why?
# assert_equal value, scope_object.settings[key.to_sym]
# assert_equal value, scope_object.settings[key.to_s]
#
# As a work-around, use a "get" method
assert_equal value, scope_object.settings.get(key.to_sym)
assert_equal value, scope_object.settings.get(key.to_s)
else
assert_equal value, eval("Settings.#{key}")
assert_equal value, Settings[key.to_sym]
assert_equal value, Settings[key.to_s]
end
end

def assert_assign_setting(value, key)
def assert_assign_setting(value, key, scope_object=nil)
key = key.to_sym
assert_equal value, eval("Settings.#{key} = value")
assert_setting value, key
eval("Settings.#{key} = nil")

assert_equal value, (Settings[key] = value)
assert_setting value, key
Settings[key] = nil
if scope_object
assert_equal value, scope_object.instance_eval("settings.#{key} = value")
assert_setting value, key, scope_object
scope_object.instance_eval("settings.#{key} = nil")

assert_equal value, (scope_object.settings.set(key,value))
assert_setting value, key, scope_object
scope_object.settings.set(key, nil)

assert_equal value, (scope_object.settings.set(key.to_s,value))
assert_setting value, key, scope_object
else
assert_equal value, eval("Settings.#{key} = value")
assert_setting value, key
eval("Settings.#{key} = nil")

assert_equal value, (Settings[key] = value)
assert_setting value, key
Settings[key] = nil

assert_equal value, (Settings[key.to_s] = value)
assert_setting value, key
assert_equal value, (Settings[key.to_s] = value)
assert_setting value, key
end
end
end
11 changes: 11 additions & 0 deletions test/test_helper.rb
Expand Up @@ -8,13 +8,24 @@

ActiveRecord::Base.establish_connection(:adapter => "sqlite3", :dbfile => ":memory:")

class User < ActiveRecord::Base
has_settings
end

def setup_db
ActiveRecord::Schema.define(:version => 1) do
create_table :settings do |t|
t.string :var, :null => false
t.text :value, :null => true
t.integer :object_id, :null => true
t.string :object_type, :limit => 30, :null => true
t.timestamps
end
add_index :settings, [ :object_type, :object_id, :var ], :uniq => true

create_table :users do |t|
t.string :name
end
end
end

Expand Down

0 comments on commit 878f10c

Please sign in to comment.