Skip to content
Browse files

Add support for per-group default preferences

Fix unsaved boolean preferences getting overridden by defaults if value is false
  • Loading branch information...
1 parent c33f658 commit 1b2341c78dd683981d1c6156c49fc54f0a4e6dbe @obrie obrie committed
View
3 CHANGELOG.rdoc
@@ -1,5 +1,8 @@
== master
+* Add support for per-group default preferences
+* Fix unsaved boolean preferences getting overridden by defaults if value is false
+
== 0.4.0 / 2010-03-07
* Add {preference}_changed?, {preference}_was, {preference}_changed, {preference}_will_change!, and reset_{preference}!
View
30 lib/preferences.rb
@@ -51,6 +51,9 @@ module MacroMethods
#
# Configuration options:
# * <tt>:default</tt> - The default value for the preference. Default is nil.
+ # * <tt>:group_defaults</tt> - Defines the default values to use for various
+ # groups. This should map group_name -> defaults. For ActiveRecord groups,
+ # use the class name.
#
# == Examples
#
@@ -59,7 +62,7 @@ module MacroMethods
#
# class User < ActiveRecord::Base
# preference :notifications, :default => false
- # preference :color, :string, :default => 'red'
+ # preference :color, :string, :default => 'red', :group_defaults => {:car => 'black'}
# preference :favorite_number, :integer
# preference :data, :any # Allows any data type to be stored
# end
@@ -152,9 +155,6 @@ def preference(name, *args)
class_inheritable_hash :preference_definitions
self.preference_definitions = {}
- class_inheritable_hash :default_preferences
- self.default_preferences = {}
-
has_many :stored_preferences, :as => :owner, :class_name => 'Preference'
after_save :update_preferences
@@ -171,7 +171,6 @@ def preference(name, *args)
name = name.to_s
definition = PreferenceDefinition.new(name, *args)
self.preference_definitions[name] = definition
- self.default_preferences[name] = definition.default_value
# Create short-hand accessor methods, making sure that the name
# is method-safe in terms of what characters are allowed
@@ -249,11 +248,12 @@ def build_preference_scope(preferences, inverse = false)
end
preferences.each do |(group, preference), value|
+ group_id, group_type = Preference.split_group(group)
preference = preference.to_s
- value = preference_definitions[preference.to_s].type_cast(value)
- is_default = default_preferences[preference.to_s] == value
+ definition = preference_definitions[preference.to_s]
+ value = definition.type_cast(value)
+ is_default = definition.default_value(group_type) == value
- group_id, group_type = Preference.split_group(group)
table = "preferences_#{group_id}_#{group_type}_#{preference}"
# Since each preference is a different record, they need their own
@@ -303,19 +303,21 @@ def self.included(base) #:nodoc:
# user.preferences(:cars)
# => {"language=>"English", "color"=>"red"}
def preferences(group = nil)
+ preferences = preferences_group(group)
+
unless preferences_group_loaded?(group)
- preferences = preferences_group(group)
-
group_id, group_type = Preference.split_group(group)
find_preferences(:group_id => group_id, :group_type => group_type).each do |preference|
- preferences[preference.name] ||= preference.value
+ preferences[preference.name] = preference.value unless preferences.include?(preference.name)
end
# Add defaults
- preferences.reverse_merge!(self.class.default_preferences.dup)
+ preference_definitions.each do |name, definition|
+ preferences[name] = definition.default_value(group_type) unless preferences.include?(name)
+ end
end
- preferences_group(group).dup
+ preferences.dup
end
# Queries whether or not a value is present for the given preference.
@@ -374,7 +376,7 @@ def preferred(name, group = nil)
group_id, group_type = Preference.split_group(group)
preference = find_preferences(:name => name, :group_id => group_id, :group_type => group_type).first unless preferences_group_loaded?(group)
- value = preference ? preference.value : preference_definitions[name].default_value
+ value = preference ? preference.value : preference_definitions[name].default_value(group_type)
preferences_group(group)[name] = value
end
View
11 lib/preferences/preference_definition.rb
@@ -6,12 +6,17 @@ class PreferenceDefinition
def initialize(name, *args) #:nodoc:
options = args.extract_options!
- options.assert_valid_keys(:default)
+ options.assert_valid_keys(:default, :group_defaults)
@type = args.first ? args.first.to_sym : :boolean
# Create a column that will be responsible for typecasting
@column = ActiveRecord::ConnectionAdapters::Column.new(name.to_s, options[:default], @type == :any ? nil : @type.to_s)
+
+ @group_defaults = (options[:group_defaults] || {}).inject({}) do |defaults, (group, default)|
+ defaults[group.is_a?(Symbol) ? group.to_s : group] = type_cast(default)
+ defaults
+ end
end
# The name of the preference
@@ -21,8 +26,8 @@ def name
# The default value to use for the preference in case none have been
# previously defined
- def default_value
- @column.default
+ def default_value(group = nil)
+ @group_defaults.include?(group) ? @group_defaults[group] : @column.default
end
# Determines whether column backing this preference stores numberic values
View
77 test/functional/preferences_test.rb
@@ -6,7 +6,6 @@ def default_test
def teardown
User.preference_definitions.clear
- User.default_preferences.clear
end
end
@@ -15,10 +14,6 @@ def test_should_not_create_preference_definitions
assert !Car.respond_to?(:preference_definitions)
end
- def test_should_not_create_default_preferences
- assert !Car.respond_to?(:default_preferences)
- end
-
def test_should_not_create_stored_preferences_association
assert !Car.new.respond_to?(:stored_preferences)
end
@@ -39,10 +34,6 @@ def test_should_create_preference_definitions
assert User.respond_to?(:preference_definitions)
end
- def test_should_create_default_preferences
- assert User.respond_to?(:default_preferences)
- end
-
def test_should_create_preference_scopes
assert User.respond_to?(:with_preferences)
assert User.respond_to?(:without_preferences)
@@ -136,10 +127,6 @@ def test_should_create_prefers_reset
def test_should_include_new_definitions_in_preference_definitions
assert_equal e = {'notifications' => @definition}, User.preference_definitions
end
-
- def test_should_include_default_value_in_default_preferences
- assert_equal e = {'notifications' => nil}, User.default_preferences
- end
end
class PreferencesByDefaultTest < ModelPreferenceTest
@@ -156,10 +143,6 @@ def test_should_not_have_default_value
assert_nil @definition.default_value
end
- def test_should_include_in_default_preferences
- assert_equal e = {'notifications' => nil}, User.default_preferences
- end
-
def test_should_only_have_default_preferences
assert_equal e = {'notifications' => nil}, @user.preferences
end
@@ -203,10 +186,6 @@ def test_should_not_have_default_value
assert_nil @definition.default_value
end
- def test_should_include_in_default_preferences
- assert_equal e = {'vehicle_id' => nil}, User.default_preferences
- end
-
def test_should_only_have_default_preferences
assert_equal e = {'vehicle_id' => nil}, @user.preferences
end
@@ -226,10 +205,6 @@ def test_should_have_default_value
assert_equal 'red', @definition.default_value
end
- def test_should_include_in_default_preferences
- assert_equal e = {'color' => 'red'}, User.default_preferences
- end
-
def test_should_only_have_default_preferences
assert_equal e = {'color' => 'red'}, @user.preferences
end
@@ -242,10 +217,6 @@ def setup
@user = new_user
end
- def test_should_include_all_in_default_preferences
- assert_equal e = {'notifications' => true, 'color' => 'red'}, User.default_preferences
- end
-
def test_should_only_have_default_preferences
assert_equal e = {'notifications' => true, 'color' => 'red'}, @user.preferences
end
@@ -277,6 +248,11 @@ def test_use_default_value_if_not_stored
assert_equal true, @user.preferred(:notifications)
end
+ def test_should_use_group_default_value_if_not_stored
+ User.preference :language, :string, :default => 'English', :group_defaults => {:chat => 'Latin'}
+ assert_equal 'English', @user.preferred(:language)
+ end
+
def test_should_use_stored_value_if_stored
create_preference(:owner => @user, :name => 'notifications', :value => false)
assert_equal false, @user.preferred(:notifications)
@@ -320,10 +296,15 @@ def setup
@user = create_user
end
- def test_use_default_value_if_not_stored
+ def test_should_use_default_value_if_not_stored
assert_equal true, @user.preferred(:notifications, :chat)
end
+ def test_should_use_group_default_value_if_not_stored
+ User.preference :language, :string, :default => 'English', :group_defaults => {:chat => 'Latin'}
+ assert_equal 'Latin', @user.preferred(:language, :chat)
+ end
+
def test_should_use_stored_value_if_stored
create_preference(:owner => @user, :group_type => 'chat', :name => 'notifications', :value => false)
assert_equal false, @user.preferred(:notifications, :chat)
@@ -956,7 +937,7 @@ def test_should_not_reset_default_group
class PreferencesLookupTest < ModelPreferenceTest
def setup
User.preference :notifications, :boolean, :default => true
- User.preference :language, :string, :default => 'English'
+ User.preference :language, :string, :default => 'English', :group_defaults => {:chat => 'Latin'}
@user = create_user
end
@@ -982,9 +963,9 @@ def test_should_merge_stored_preferences_with_unsaved_changes
end
def test_should_use_unsaved_changes_over_stored_preferences
- create_preference(:owner => @user, :name => 'notifications', :value => false)
- @user.write_preference(:notifications, true)
- assert_equal e = {'notifications' => true, 'language' => 'English'}, @user.preferences
+ create_preference(:owner => @user, :name => 'notifications', :value => true)
+ @user.write_preference(:notifications, false)
+ assert_equal e = {'notifications' => false, 'language' => 'English'}, @user.preferences
end
def test_should_cache_results
@@ -1013,29 +994,29 @@ def test_should_use_preferences_for_prefs
class PreferencesGroupLookupTest < ModelPreferenceTest
def setup
User.preference :notifications, :boolean, :default => true
- User.preference :language, :string, :default => 'English'
+ User.preference :language, :string, :default => 'English', :group_defaults => {:chat => 'Latin'}
@user = create_user
end
def test_should_only_have_defaults_if_nothing_customized
- assert_equal e = {'notifications' => true, 'language' => 'English'}, @user.preferences(:chat)
+ assert_equal e = {'notifications' => true, 'language' => 'Latin'}, @user.preferences(:chat)
end
def test_should_merge_defaults_with_unsaved_changes
@user.write_preference(:notifications, false, :chat)
- assert_equal e = {'notifications' => false, 'language' => 'English'}, @user.preferences(:chat)
+ assert_equal e = {'notifications' => false, 'language' => 'Latin'}, @user.preferences(:chat)
end
def test_should_merge_defaults_with_saved_changes
create_preference(:owner => @user, :group_type => 'chat', :name => 'notifications', :value => false)
- assert_equal e = {'notifications' => false, 'language' => 'English'}, @user.preferences(:chat)
+ assert_equal e = {'notifications' => false, 'language' => 'Latin'}, @user.preferences(:chat)
end
def test_should_merge_stored_preferences_with_unsaved_changes
create_preference(:owner => @user, :group_type => 'chat', :name => 'notifications', :value => false)
- @user.write_preference(:language, 'Latin', :chat)
- assert_equal e = {'notifications' => false, 'language' => 'Latin'}, @user.preferences(:chat)
+ @user.write_preference(:language, 'Spanish', :chat)
+ assert_equal e = {'notifications' => false, 'language' => 'Spanish'}, @user.preferences(:chat)
end
def test_should_cache_results
@@ -1252,6 +1233,14 @@ def test_should_find_with_default_group_preference
assert_equal [@user], User.with_preferences(:chat => {:language => 'English'})
end
+ def test_should_find_with_customized_default_group_preference
+ User.preference :country, :string, :default => 'US', :group_defaults => {:chat => 'UK'}
+ @customized_user.preferred_country = 'US', :chat
+ @customized_user.save!
+
+ assert_equal [@user], User.with_preferences(:chat => {:country => 'UK'})
+ end
+
def test_should_find_with_multiple_default_group_preferences
assert_equal [@user], User.with_preferences(:chat => {:notifications => nil, :language => 'English'})
end
@@ -1328,6 +1317,14 @@ def test_should_find_with_default_group_preference
assert_equal [@user], User.without_preferences(:chat => {:language => 'Latin'})
end
+ def test_should_find_with_customized_default_group_preference
+ User.preference :country, :string, :default => 'US', :group_defaults => {:chat => 'UK'}
+ @customized_user.preferred_country = 'US', :chat
+ @customized_user.save!
+
+ assert_equal [@user], User.without_preferences(:chat => {:country => 'US'})
+ end
+
def test_should_find_with_multiple_default_group_preferences
assert_equal [@user], User.without_preferences(:chat => {:language => 'Latin', :notifications => false})
end
View
18 test/unit/preference_definition_test.rb
@@ -42,6 +42,24 @@ def test_should_type_cast_default_values
end
end
+class PreferenceDefinitionWithGroupDefaultsTest < ActiveSupport::TestCase
+ def setup
+ @definition = Preferences::PreferenceDefinition.new(:notifications, :boolean, :default => 1, :group_defaults => {:chat => 0})
+ end
+
+ def test_should_use_default_for_default_group
+ assert_equal true, @definition.default_value
+ end
+
+ def test_should_use_default_for_unknown_group
+ assert_equal true, @definition.default_value('email')
+ end
+
+ def test_should_use_group_default_for_known_group
+ assert_equal false, @definition.default_value('chat')
+ end
+end
+
class PreferenceDefinitionWithStringifiedTypeTest < ActiveSupport::TestCase
def setup
@definition = Preferences::PreferenceDefinition.new(:notifications, 'any')
View
2 test/unit/preference_test.rb
@@ -157,7 +157,6 @@ def test_should_not_have_a_group_association
def teardown
User.preference_definitions.delete('notifications')
- User.default_preferences.delete('notifications')
end
end
@@ -210,7 +209,6 @@ def test_should_type_cast_boolean_values
def teardown
User.preference_definitions.delete('notifications')
- User.default_preferences.delete('notifications')
end
end

0 comments on commit 1b2341c

Please sign in to comment.
Something went wrong with that request. Please try again.