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,