lib/enumerate_by.rb in enumerate_by-0.4.2 vs lib/enumerate_by.rb in enumerate_by-0.4.3

- old
+ new

@@ -55,12 +55,11 @@ # is no performance hit. # # == Associations # # When using enumerations together with +belongs_to+ associations, the - # enumerator value can be used as a shortcut for assigning the - # association. + # enumerator value can be used as a shortcut for assigning the association. # # In addition, the enumerator value is automatically used during # serialization (xml and json) of the associated record instead of the # foreign key for the association. # @@ -124,11 +123,11 @@ # For example, # # Color.find_by_enumerator('red') # => #<Color id: 1, name: "red"> # Color.find_by_enumerator('invalid') # => nil def find_by_enumerator(enumerator) - first(:conditions => {enumerator_attribute => enumerator}) + first(:conditions => {enumerator_attribute => typecast_enumerator(enumerator)}) end # Finds the record that is associated with the given enumerator. If no # record is found, then an ActiveRecord::RecordNotFound exception is # raised. @@ -138,37 +137,38 @@ # Color['red'] # => #<Color id: 1, name: "red"> # Color['invalid'] # => ActiveRecord::RecordNotFound: Couldn't find Color with name "red" # # To avoid raising an exception on invalid enumerators, use +find_by_enumerator+. def find_by_enumerator!(enumerator) - find_by_enumerator(enumerator) || raise(ActiveRecord::RecordNotFound, "Couldn't find #{name} with #{enumerator_attribute} #{enumerator.inspect}") + find_by_enumerator(enumerator) || raise(ActiveRecord::RecordNotFound, "Couldn't find #{name} with #{enumerator_attribute} #{typecast_enumerator(enumerator).inspect}") end alias_method :[], :find_by_enumerator! # Finds records with the given enumerators. # # For example, # - # Color.find_all_by_enumerator('red', 'green') # => [#<Color id: 1, name: "red">, #<Color id: 1, name: "green">] - # Color.find_all_by_enumerator('invalid') # => [] + # Color.find_all_by_enumerator(['red', 'green']) # => [#<Color id: 1, name: "red">, #<Color id: 1, name: "green">] + # Color.find_all_by_enumerator('invalid') # => [] def find_all_by_enumerator(enumerators) - all(:conditions => {enumerator_attribute => enumerators}) + all(:conditions => {enumerator_attribute => typecast_enumerator(enumerators)}) end # Finds records with the given enumerators. If no record is found for a # particular enumerator, then an ActiveRecord::RecordNotFound exception # is raised. # # For Example, # - # Color.find_all_by_enumerator!('red', 'green') # => [#<Color id: 1, name: "red">, #<Color id: 1, name: "green">] + # Color.find_all_by_enumerator!(['red', 'green']) # => [#<Color id: 1, name: "red">, #<Color id: 1, name: "green">] # Color.find_all_by_enumerator!('invalid') # => ActiveRecord::RecordNotFound: Couldn't find Color with name(s) "invalid" # # To avoid raising an exception on invalid enumerators, use +find_all_by_enumerator+. def find_all_by_enumerator!(enumerators) + enumerators = [enumerators].flatten records = find_all_by_enumerator(enumerators) - missing = [enumerators].flatten - records.map(&:enumerator) + missing = enumerators - records.map(&:enumerator) missing.empty? ? records : raise(ActiveRecord::RecordNotFound, "Couldn't find #{name} with #{enumerator_attribute}(s) #{missing.map(&:inspect).to_sentence}") end # Adds support for looking up results from the enumeration cache for # before querying the database. @@ -176,13 +176,13 @@ # This allows for enumerations to permanently cache find queries, avoiding # unnecessary lookups in the database. [:find_by_sql, :exists?, :calculate].each do |method| define_method(method) do |*args| if EnumerateBy.perform_caching && perform_enumerator_caching - enumerator_cache_store.fetch([method] + args) { super } + enumerator_cache_store.fetch([method] + args) { super(*args) } else - super + super(*args) end end end # Temporarily disables the enumeration cache (as well as the query cache) @@ -193,10 +193,24 @@ self.perform_enumerator_caching = false super ensure self.perform_enumerator_caching = old end + + private + # Typecasts the given enumerator to its actual value stored in the + # database. This will only convert symbols to strings. All other values + # will remain in the same type. + def typecast_enumerator(enumerator) + if enumerator.is_a?(Array) + enumerator.flatten! + enumerator.map! {|value| typecast_enumerator(value)} + enumerator + else + enumerator.is_a?(Symbol) ? enumerator.to_s : enumerator + end + end end module Bootstrapped # Synchronizes the given records with existing ones. This ensures that # only the correct and most up-to-date records exist in the database. @@ -293,12 +307,12 @@ # * Transactions # * Timestamps # * Dirty attributes # # Also note that records are created directly without creating instances - # of the model. As a result, all of the attributes for the record must - # be specified. + # of the model. As a result, all of the attributes for the record must be + # specified. # # This produces a significant performance increase when bootstrapping more # than several hundred records. # # See EnumerateBy::Bootstrapped#bootstrap for information about usage. @@ -349,10 +363,10 @@ module InstanceMethods # Whether or not this record is equal to the given value. If the value is # a String, then it is compared against the enumerator. Otherwise, # ActiveRecord's default equality comparator is used. def ==(arg) - arg.is_a?(String) ? self == self.class.find_by_enumerator!(arg) : super + arg.nil? || arg.is_a?(self.class) ? super : self == self.class.find_by_enumerator!(arg) end # Determines whether this enumeration is in the given list. # # For example,