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
497 def preference_changes(group = nil)
498   preferences_changed(group).inject({}) do |changes, preference|
499     changes[preference] = preference_change(preference, group)
500     changes
501   end
502 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
320 def preferences(group = nil)
321   preferences = preferences_group(group)
322 
323   unless preferences_group_loaded?(group)
324     group_id, group_type = Preference.split_group(group)
325     find_preferences(:group_id => group_id, :group_type => group_type).each do |preference|
326       # fixed: ignore entries in database that are not present in the definition
327       preferences[preference.name] = preference.value unless (preferences.include?(preference.name) || !preference_definitions[preference.name])
328     end
329 
330     # Add defaults
331     preference_definitions.each do |name, definition|
332       preferences[name] = definition.default_value(group_type) unless preferences.include?(name)
333     end
334   end
335 
336   preferences.inject({}) do |typed_preferences, (name, value)|
337     typed_preferences[name] = value.nil? ? value : preference_definitions[name].type_cast(value)
338     typed_preferences
339   end
340 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
475 def preferences_changed(group = nil)
476   preferences_changed_group(group).keys
477 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
456 def preferences_changed?(group = nil)
457   !preferences_changed_group(group).empty?
458 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
385 def preferred(name, group = nil)
386   name = name.to_s
387   assert_valid_preference(name)
388 
389   if preferences_group(group).include?(name)
390     # Value for this group/name has been written, but not saved yet:
391     # grab from the pending values
392     value = preferences_group(group)[name]
393   else
394     # Grab the first preference; if it doesn't exist, use the default value
395     group_id, group_type = Preference.split_group(group)
396     preference = find_preferences(:name => name, :group_id => group_id, :group_type => group_type).first unless preferences_group_loaded?(group)
397 
398     value = preference ? preference.value : preference_definitions[name].default_value(group_type)
399     preferences_group(group)[name] = value
400   end
401 
402   definition = preference_definitions[name]
403   value = definition.type_cast(value) unless value.nil?
404   value
405 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
360 def preferred?(name, group = nil)
361   name = name.to_s
362   assert_valid_preference(name)
363 
364   value = preferred(name, group)
365   preference_definitions[name].query(value)
366 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
422 def write_preference(name, value, group = nil)
423   name = name.to_s
424   assert_valid_preference(name)
425 
426   preferences_changed = preferences_changed_group(group)
427   if preferences_changed.include?(name)
428     old = preferences_changed[name]
429     preferences_changed.delete(name) unless preference_value_changed?(name, old, value)
430   else
431     old = clone_preference_value(name, group)
432     preferences_changed[name] = old if preference_value_changed?(name, old, value)
433   end
434 
435   value = convert_number_column_value(value) if preference_definitions[name].number?
436   preferences_group(group)[name] = preference_definitions[name].type_cast(value)
437 
438   value
439 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
518 def assert_valid_preference(name)
519   raise(ArgumentError, "Unknown preference: #{name}") unless preference_definitions.include?(name)
520 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
536 def clone_preference_value(name, group)
537   value = preferred(name, group)
538   value.duplicable? ? value.clone : value
539 rescue TypeError, NoMethodError
540   value
541 end
convert_number_column_value(value) click to toggle source

Was removed from Rails 4, so inlne it here

    # File lib/preferences.rb
638 def convert_number_column_value(value)
639   case value
640   when FalseClass
641     0
642   when TrueClass
643     1
644   when String
645     value.presence
646   else
647     value
648   end
649 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
621 def find_preferences(attributes)
622   if stored_preferences.loaded?
623     stored_preferences.select do |preference|
624       attributes.all? do |attribute, value|
625         if value.is_a?(Array)
626           value.include?(preference[attribute])
627         else
628           preference[attribute] == value
629         end
630       end
631     end
632   else
633     stored_preferences.where(attributes)
634   end
635 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
557 def preference_change(name, group)
558   [preferences_changed_group(group)[name], preferred(name, group)] if preference_changed?(name, group)
559 end
preference_changed?(name, group) click to toggle source

Determines whether a preference changed in the given group

    # File lib/preferences.rb
551 def preference_changed?(name, group)
552   preferences_changed_group(group).include?(name)
553 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
580 def preference_value_changed?(name, old, value)
581   definition = preference_definitions[name]
582   if definition.type == :integer && (old.nil? || old == 0)
583     # For nullable numeric columns, NULL gets stored in database for blank (i.e. '') values.
584     # Hence we don't record it as a change if the value changes from nil to ''.
585     # If an old value of 0 is set to '' we want this to get changed to nil as otherwise it'll
586     # be typecast back to 0 (''.to_i => 0)
587     value = nil if value.blank?
588   else
589     value = definition.type_cast(value)
590   end
591 
592   old != value
593 end
preference_was(name, group) click to toggle source

Gets the last saved value for the given preference

    # File lib/preferences.rb
562 def preference_was(name, group)
563   preference_changed?(name, group) ? preferences_changed_group(group)[name] : preferred(name, group)
564 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
568 def preference_will_change!(name, group)
569   preferences_changed_group(group)[name] = clone_preference_value(name, group)
570 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
545 def preferences_changed_group(group)
546   @preferences_changed ||= {}
547   @preferences_changed[group.is_a?(Symbol) ? group.to_s : group] ||= {}
548 end
preferences_group(group) click to toggle source

Gets the set of preferences identified by the given group

    # File lib/preferences.rb
523 def preferences_group(group)
524   @preferences ||= {}
525   @preferences[group.is_a?(Symbol) ? group.to_s : group] ||= {}
526 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
530 def preferences_group_loaded?(group)
531   preference_definitions.length == preferences_group(group).length
532 end
reset_preference!(name, group) click to toggle source

Reverts any unsaved changes to the given preference

    # File lib/preferences.rb
573 def reset_preference!(name, group)
574   write_preference(name, preferences_changed_group(group)[name], group) if preference_changed?(name, group)
575 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
597 def update_preferences
598   if @preferences_changed
599     @preferences_changed.each do |group, preferences|
600       group_id, group_type = Preference.split_group(group)
601 
602       preferences.keys.each do |name|
603         # Find an existing preference or build a new one
604         attributes = {:name => name, :group_id => group_id, :group_type => group_type}
605         unless (preference = find_preferences(attributes).first)
606           preference = stored_preferences.build
607           attributes.each_pair { |attribute, value| preference[attribute] = value }
608         end
609         preference.value = preferred(name, group)
610         preference.save!
611       end
612     end
613 
614     @preferences_changed.clear
615   end
616 end