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 155 def preference(name, *args) 156 unless included_modules.include?(InstanceMethods) 157 class_attribute :preference_definitions 158 self.preference_definitions = {} 159 160 has_many :stored_preferences, :as => :owner, :class_name => 'Preference', :dependent => :delete_all 161 162 after_save :update_preferences 163 164 # Named scopes 165 scope :with_preferences, lambda {|preferences| build_preference_scope(preferences)} 166 scope :without_preferences, lambda {|preferences| build_preference_scope(preferences, true)} 167 168 extend Preferences::ClassMethods 169 include Preferences::InstanceMethods 170 end 171 172 # Create the definition 173 name = name.to_s 174 definition = PreferenceDefinition.new(name, *args) 175 self.preference_definitions[name] = definition 176 177 # Create short-hand accessor methods, making sure that the name 178 # is method-safe in terms of what characters are allowed 179 name = name.gsub(/[^A-Za-z0-9_-]/, '').underscore 180 181 # Query lookup 182 define_method("preferred_#{name}?") do |*group| 183 preferred?(name, group.first) 184 end 185 alias_method "prefers_#{name}?", "preferred_#{name}?" 186 187 # Reader 188 define_method("preferred_#{name}") do |*group| 189 preferred(name, group.first) 190 end 191 alias_method "prefers_#{name}", "preferred_#{name}" 192 193 # Writer 194 define_method("preferred_#{name}=") do |*args| 195 write_preference(*args.flatten.unshift(name)) 196 end 197 alias_method "prefers_#{name}=", "preferred_#{name}=" 198 199 # Changes 200 define_method("preferred_#{name}_changed?") do |*group| 201 preference_changed?(name, group.first) 202 end 203 alias_method "prefers_#{name}_changed?", "preferred_#{name}_changed?" 204 205 define_method("preferred_#{name}_was") do |*group| 206 preference_was(name, group.first) 207 end 208 alias_method "prefers_#{name}_was", "preferred_#{name}_was" 209 210 define_method("preferred_#{name}_change") do |*group| 211 preference_change(name, group.first) 212 end 213 alias_method "prefers_#{name}_change", "preferred_#{name}_change" 214 215 define_method("preferred_#{name}_will_change!") do |*group| 216 preference_will_change!(name, group.first) 217 end 218 alias_method "prefers_#{name}_will_change!", "preferred_#{name}_will_change!" 219 220 define_method("reset_preferred_#{name}!") do |*group| 221 reset_preference!(name, group.first) 222 end 223 alias_method "reset_prefers_#{name}!", "reset_preferred_#{name}!" 224 225 definition 226 end