module Preferences::InstanceMethods

Public Instance Methods

preference_changes(group = nil) click to toggle source

A map of the preferences that have changed in the current object.

Examples

user = User.find(:first)
user.preferred(:color)                      # => nil
user.preference_changes                     # => {}

user.write_preference(:color, 'red')
user.preference_changes                     # => {"color" => [nil, "red"]}
user.save
user.preference_changes                     # => {}

# Groups
user.preferred(:color, :car)                # => nil
user.preference_changes(:car)               # => {}
user.write_preference(:color, 'red', :car)
user.preference_changes(:car)               # => {"color" => [nil, "red"]}
# File lib/preferences.rb, line 483
def preference_changes(group = nil)
  preferences_changed(group).inject({}) do |changes, preference|
    changes[preference] = preference_change(preference, group)
    changes
  end
end
preferences(group = nil) click to toggle source

Finds all preferences, including defaults, for the current record. If looking up custom group preferences, then this will include all default preferences within that particular group as well.

Examples

A user with no stored values:

user = User.find(:first)
user.preferences
=> {"language"=>"English", "color"=>nil}

A user with stored values for a particular group:

user.preferred_color = 'red', :cars
user.preferences(:cars)
=> {"language=>"English", "color"=>"red"}
# File lib/preferences.rb, line 307
def preferences(group = nil)
  preferences = preferences_group(group)

  unless preferences_group_loaded?(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 unless preferences.include?(preference.name)
    end

    # Add defaults
    preference_definitions.each do |name, definition|
      preferences[name] = definition.default_value(group_type) unless preferences.include?(name)
    end
  end

  preferences.inject({}) do |typed_preferences, (name, value)|
    typed_preferences[name] = value.nil? ? value : preference_definitions[name].type_cast(value)
    typed_preferences
  end
end
preferences_changed(group = nil) click to toggle source

A list of the preferences that have unsaved changes.

Examples

user = User.find(:first)
user.preferences_changed                    # => []
user.write_preference(:color, 'red')
user.preferences_changed                    # => ["color"]
user.save
user.preferences_changed                    # => []

# Groups
user.preferences_changed(:car)              # => []
user.write_preference(:color, 'red', :car)
user.preferences_changed(:car)              # => ["color"]
# File lib/preferences.rb, line 461
def preferences_changed(group = nil)
  preferences_changed_group(group).keys
end
preferences_changed?(group = nil) click to toggle source

Whether any attributes have unsaved changes.

Examples

user = User.find(:first)
user.preferences_changed?                   # => false
user.write_preference(:color, 'red')
user.preferences_changed?                   # => true
user.save
user.preferences_changed?                   # => false

# Groups
user.preferences_changed?(:car)             # => false
user.write_preference(:color, 'red', :car)
user.preferences_changed(:car)              # => true
# File lib/preferences.rb, line 442
def preferences_changed?(group = nil)
  !preferences_changed_group(group).empty?
end
preferred(name, group = nil) click to toggle source

Gets the actual value stored for the given preference, or the default value if nothing is present.

Examples

class User < ActiveRecord::Base
  preference :color, :string, :default => 'red'
end

user = User.create
user.preferred(:color)            # => "red"
user.preferred(:color, 'cars')    # => "red"
user.preferred(:color, Car.first) # => "red"

user.write_preference(:color, 'blue')
user.preferred(:color)            # => "blue"
# File lib/preferences.rb, line 371
def preferred(name, group = nil)
  name = name.to_s
  assert_valid_preference(name)

  if preferences_group(group).include?(name)
    # Value for this group/name has been written, but not saved yet:
    # grab from the pending values
    value = preferences_group(group)[name]
  else
    # Grab the first preference; if it doesn't exist, use the default value
    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(group_type)
    preferences_group(group)[name] = value
  end

  definition = preference_definitions[name]
  value = definition.type_cast(value) unless value.nil?
  value
end
Also aliased as: prefers
preferred?(name, group = nil) click to toggle source

Queries whether or not a value is present for the given preference. This is dependent on how the value is type-casted.

Examples

class User < ActiveRecord::Base
  preference :color, :string, :default => 'red'
end

user = User.create
user.preferred(:color)              # => "red"
user.preferred?(:color)             # => true
user.preferred?(:color, 'cars')     # => true
user.preferred?(:color, Car.first)  # => true

user.write_preference(:color, nil)
user.preferred(:color)              # => nil
user.preferred?(:color)             # => false
# File lib/preferences.rb, line 346
def preferred?(name, group = nil)
  name = name.to_s
  assert_valid_preference(name)

  value = preferred(name, group)
  preference_definitions[name].query(value)
end
Also aliased as: prefers?
prefers(name, group = nil)
Alias for: preferred
prefers?(name, group = nil)
Alias for: preferred?
write_preference(name, value, group = nil) click to toggle source

Sets a new value for the given preference. The actual Preference record is not created until this record is saved. In this way, preferences act exactly the same as attributes. They can be written to and validated against, but won’t actually be written to the database until the record is saved.

Examples

user = User.find(:first)
user.write_preference(:color, 'red')              # => "red"
user.save!

user.write_preference(:color, 'blue', Car.first)  # => "blue"
user.save!
# File lib/preferences.rb, line 408
def write_preference(name, value, group = nil)
  name = name.to_s
  assert_valid_preference(name)

  preferences_changed = preferences_changed_group(group)
  if preferences_changed.include?(name)
    old = preferences_changed[name]
    preferences_changed.delete(name) unless preference_value_changed?(name, old, value)
  else
    old = clone_preference_value(name, group)
    preferences_changed[name] = old if preference_value_changed?(name, old, value)
  end

  value = value.to_i if preference_definitions[name].number?
  preferences_group(group)[name] = value

  value
end

Private Instance Methods

assert_valid_preference(name) click to toggle source

Asserts that the given name is a valid preference in this model. If it is not, then an ArgumentError exception is raised.

# File lib/preferences.rb, line 503
def assert_valid_preference(name)
  raise(ArgumentError, "Unknown preference: #{name}") unless preference_definitions.include?(name)
end
clone_preference_value(name, group) click to toggle source

Generates a clone of the current value stored for the preference with the given name / group

# File lib/preferences.rb, line 521
def clone_preference_value(name, group)
  value = preferred(name, group)
  value.duplicable? ? value.clone : value
rescue TypeError, NoMethodError
  value
end
destroy_preferences() click to toggle source

Destroys preferences before the owning object is destroyed.

# File lib/preferences.rb, line 618
def destroy_preferences
  stored_preferences.destroy_all
end
find_preferences(attributes) click to toggle source

Finds all stored preferences with the given attributes. This will do a smart lookup by looking at the in-memory collection if it was eager- loaded.

# File lib/preferences.rb, line 608
def find_preferences(attributes)
  if stored_preferences.loaded?
    stored_preferences.select do |preference|
      attributes.all? {|attribute, value| preference[attribute] == value}
    end
  else
    stored_preferences.where(attributes)
  end
end
preference_change(name, group) click to toggle source

Builds an array of [original_value, new_value] for the given preference. If the perference did not change, this will return nil.

# File lib/preferences.rb, line 542
def preference_change(name, group)
  [preferences_changed_group(group)[name], preferred(name, group)] if preference_changed?(name, group)
end
preference_changed?(name, group) click to toggle source

Determines whether a preference changed in the given group

# File lib/preferences.rb, line 536
def preference_changed?(name, group)
  preferences_changed_group(group).include?(name)
end
preference_value_changed?(name, old, value) click to toggle source

Determines whether the old value is different from the new value for the given preference. This will use the typecasted value to determine equality.

# File lib/preferences.rb, line 565
def preference_value_changed?(name, old, value)
  definition = preference_definitions[name]
  if definition.type == :integer && (old.nil? || old == 0)
    # For nullable numeric columns, NULL gets stored in database for blank (i.e. '') values.
    # Hence we don't record it as a change if the value changes from nil to ''.
    # If an old value of 0 is set to '' we want this to get changed to nil as otherwise it'll
    # be typecast back to 0 (''.to_i => 0)
    value = nil if value.blank?
  else
    value = definition.type_cast(value)
  end

  old != value
end
preference_was(name, group) click to toggle source

Gets the last saved value for the given preference

# File lib/preferences.rb, line 547
def preference_was(name, group)
  preference_changed?(name, group) ? preferences_changed_group(group)[name] : preferred(name, group)
end
preference_will_change!(name, group) click to toggle source

Forces the given preference to be saved regardless of whether the value is actually diferent

# File lib/preferences.rb, line 553
def preference_will_change!(name, group)
  preferences_changed_group(group)[name] = clone_preference_value(name, group)
end
preferences_changed_group(group) click to toggle source

Keeps track of all preferences that have been changed so that they can be properly updated in the database. Maps group -> preference -> value.

# File lib/preferences.rb, line 530
def preferences_changed_group(group)
  @preferences_changed ||= {}
  @preferences_changed[group.is_a?(Symbol) ? group.to_s : group] ||= {}
end
preferences_group(group) click to toggle source

Gets the set of preferences identified by the given group

# File lib/preferences.rb, line 508
def preferences_group(group)
  @preferences ||= {}
  @preferences[group.is_a?(Symbol) ? group.to_s : group] ||= {}
end
preferences_group_loaded?(group) click to toggle source

Determines whether the given group of preferences has already been loaded from the database

# File lib/preferences.rb, line 515
def preferences_group_loaded?(group)
  preference_definitions.length == preferences_group(group).length
end
reset_preference!(name, group) click to toggle source

Reverts any unsaved changes to the given preference

# File lib/preferences.rb, line 558
def reset_preference!(name, group)
  write_preference(name, preferences_changed_group(group)[name], group) if preference_changed?(name, group)
end
update_preferences() click to toggle source

Updates any preferences that have been changed/added since the record was last saved

# File lib/preferences.rb, line 582
def update_preferences
  if @preferences_changed
    @preferences_changed.each do |group, preferences|
      group_id, group_type = Preference.split_group(group)

      preferences.keys.each do |name|
        # Find an existing preference or build a new one
        attributes = {:name => name, :group_id => group_id, :group_type => group_type}

        unless (preference = find_preferences(attributes).first)
          preference = stored_preferences.build
          attributes.each_pair { |attribute, value| preference[attribute] = value }
        end

        preference.value = preferred(name, group)
        preference.save!
      end
    end

    @preferences_changed.clear
  end
end