module Preferences::MacroMethods
Public Instance Methods
Defines a new preference for all records in the model. By default, preferences are assumed to have a boolean data type, so all values will be typecasted to true/false based on ActiveRecord rules.
Configuration options:
-
:default
- The default value for the preference. Default is nil. -
:group_defaults
- Defines the default values to use for various groups. This should map group_name -> defaults. For ActiveRecord groups, use the class name.
Examples¶ ↑
The example below shows the various ways to define a preference for a particular model.
class User < ActiveRecord::Base preference :notifications, :default => false preference :color, :string, :default => 'red', :group_defaults => {:car => 'black'} preference :favorite_number, :integer preference :data, :any # Allows any data type to be stored end
All preferences are also inherited by subclasses.
Associations¶ ↑
After the first preference is defined, the following associations are created for the model:
-
stored_preferences
- A collection of all the custom preferences specified for a record. This will not include default preferences unless they have been explicitly set.
Named scopes¶ ↑
In addition to the above associations, the following named scopes get generated for the model:
-
with_preferences
- Finds all records with a given set of preferences -
without_preferences
- Finds all records without a given set of preferences
In addition to utilizing preferences stored in the database, each of the above scopes also take into account the defaults that have been defined for each preference.
Example:
User.with_preferences(:notifications => true) User.with_preferences(:notifications => true, :color => 'blue') # Searching with group preferences car = Car.find(:first) User.with_preferences(car => {:color => 'blue'}) User.with_preferences(:notifications => true, car => {:color => 'blue'})
Generated accessors¶ ↑
In addition to calling prefers?
and preferred
on a record, you can also use the shortcut accessor methods that are generated when a preference is defined. For example,
class User < ActiveRecord::Base preference :notifications end
…generates the following methods:
-
prefers_notifications?
- Whether a value has been specified, i.e.record.prefers?(:notifications)
-
prefers_notifications
- The actual value stored, i.e.record.prefers(:notifications)
-
prefers_notifications=(value)
- Sets a new value, i.e.record.write_preference(:notifications, value)
-
prefers_notifications_changed?
- Whether the preference has unsaved changes -
prefers_notifications_was
- The last saved value for the preference -
prefers_notifications_change
- A list of [original_value, new_value] if the preference has changed -
prefers_notifications_will_change!
- Forces the preference to get updated -
reset_prefers_notifications!
- Reverts any unsaved changes to the preference
…and the equivalent preferred
methods:
-
preferred_notifications?
-
preferred_notifications
-
preferred_notifications=(value)
-
preferred_notifications_changed?
-
preferred_notifications_was
-
preferred_notifications_change
-
preferred_notifications_will_change!
-
reset_preferred_notifications!
Notice that there are two tenses used depending on the context of the preference. Conventionally, prefers_notifications?
is better for accessing boolean preferences, while preferred_color
is better for accessing non-boolean preferences.
Example:
user = User.find(:first) user.prefers_notifications? # => false user.prefers_notifications # => false user.preferred_color? # => true user.preferred_color # => 'red' user.preferred_color = 'blue' # => 'blue' user.prefers_notifications = true car = Car.find(:first) user.preferred_color = 'red', car # => 'red' user.preferred_color(car) # => 'red' user.preferred_color?(car) # => true user.save! # => true
# File lib/preferences.rb, line 154 def preference(name, *args) unless included_modules.include?(InstanceMethods) class_attribute :preference_definitions self.preference_definitions = {} has_many :stored_preferences, :as => :owner, :class_name => 'Preference' after_save :update_preferences before_destroy :destroy_preferences # Named scopes scope :with_preferences, lambda {|preferences| build_preference_scope(preferences)} scope :without_preferences, lambda {|preferences| build_preference_scope(preferences, true)} extend Preferences::ClassMethods include Preferences::InstanceMethods end # Create the definition name = name.to_s definition = PreferenceDefinition.new(name, *args) self.preference_definitions[name] = definition # Create short-hand accessor methods, making sure that the name # is method-safe in terms of what characters are allowed name = name.gsub(/[^A-Za-z0-9_-]/, '').underscore # Query lookup define_method("preferred_#{name}?") do |*group| preferred?(name, group.first) end alias_method "prefers_#{name}?", "preferred_#{name}?" # Reader define_method("preferred_#{name}") do |*group| preferred(name, group.first) end alias_method "prefers_#{name}", "preferred_#{name}" # Writer define_method("preferred_#{name}=") do |*args| write_preference(*args.flatten.unshift(name)) end alias_method "prefers_#{name}=", "preferred_#{name}=" # Changes define_method("preferred_#{name}_changed?") do |*group| preference_changed?(name, group.first) end alias_method "prefers_#{name}_changed?", "preferred_#{name}_changed?" define_method("preferred_#{name}_was") do |*group| preference_was(name, group.first) end alias_method "prefers_#{name}_was", "preferred_#{name}_was" define_method("preferred_#{name}_change") do |*group| preference_change(name, group.first) end alias_method "prefers_#{name}_change", "preferred_#{name}_change" define_method("preferred_#{name}_will_change!") do |*group| preference_will_change!(name, group.first) end alias_method "prefers_#{name}_will_change!", "preferred_#{name}_will_change!" define_method("reset_preferred_#{name}!") do |*group| reset_preference!(name, group.first) end alias_method "reset_prefers_#{name}!", "reset_preferred_#{name}!" definition end