From 878f10c57d1776804ff0bab8924141c7d506d260 Mon Sep 17 00:00:00 2001 From: Georg Ledermann Date: Mon, 18 May 2009 16:53:38 +0200 Subject: [PATCH] Scoped settings for any ActiveRecord instance --- MIT-LICENSE | 1 + README.rdoc | 14 +++- .../settings_migration/templates/migration.rb | 4 ++ init.rb | 12 +++- lib/settings.rb | 23 ++++-- test/settings_test.rb | 72 +++++++++++++++---- test/test_helper.rb | 11 +++ 7 files changed, 115 insertions(+), 22 deletions(-) diff --git a/MIT-LICENSE b/MIT-LICENSE index 2e6b14df..14f1ebed 100644 --- a/MIT-LICENSE +++ b/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 diff --git a/README.rdoc b/README.rdoc index fc61dad7..6c36b037 100644 --- a/README.rdoc +++ b/README.rdoc @@ -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! \ No newline at end of file + 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! diff --git a/generators/settings_migration/templates/migration.rb b/generators/settings_migration/templates/migration.rb index 31d4b360..955ded85 100644 --- a/generators/settings_migration/templates/migration.rb +++ b/generators/settings_migration/templates/migration.rb @@ -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 diff --git a/init.rb b/init.rb index b24bc403..cf043760 100644 --- a/init.rb +++ b/init.rb @@ -1 +1,11 @@ -require 'settings' \ No newline at end of file +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 \ No newline at end of file diff --git a/lib/settings.rb b/lib/settings.rb index 843740e3..ceaec100 100644 --- a/lib/settings.rb +++ b/lib/settings.rb @@ -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] @@ -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 diff --git a/test/settings_test.rb b/test/settings_test.rb index 05fc2031..9e4f0217 100644 --- a/test/settings_test.rb +++ b/test/settings_test.rb @@ -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 @@ -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 \ No newline at end of file diff --git a/test/test_helper.rb b/test/test_helper.rb index 21f13f80..759d6218 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -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