lib/enumerate_by.rb in enumerate_by-0.4.3 vs lib/enumerate_by.rb in enumerate_by-0.4.4
- old
+ new
@@ -15,11 +15,15 @@
def self.extended(base) #:nodoc:
base.class_eval do
# Tracks which associations are backed by an enumeration
# {"foreign key" => "association name"}
class_inheritable_accessor :enumeration_associations
- self.enumeration_associations = {}
+
+ # Fix existing models not getting the default value
+ ([self] + subclasses).each do |model|
+ model.enumeration_associations = {}
+ end
end
end
# Indicates that this class is an enumeration.
#
@@ -176,11 +180,11 @@
# 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(*args) }
+ shallow_clone(enumerator_cache_store.fetch([method] + args) { super(*args) })
else
super(*args)
end
end
end
@@ -207,10 +211,20 @@
enumerator
else
enumerator.is_a?(Symbol) ? enumerator.to_s : enumerator
end
end
+
+ # Generates a copy of the given record(s), keeping intact the original id
+ def shallow_clone(result)
+ case result
+ when Array
+ result.map {|item| shallow_clone(item)}
+ when ActiveRecord::Base
+ result.class.send(:instantiate, result.instance_variable_get(:@attributes))
+ 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.
@@ -263,33 +277,35 @@
# existing records in the database. However, the +html+ attribute will
# only be synchronized if the attribute is nil in the database.
# Otherwise, any changes to that column remain there.
def bootstrap(*records)
uncached do
+ primary_key = self.primary_key.to_sym
+
# Remove records that are no longer being used
records.flatten!
- ids = records.map {|record| record[:id]}.compact
- delete_all(ids.any? ? ['id NOT IN (?)', ids] : nil)
+ ids = records.map {|record| record[primary_key]}.compact
+ delete_all(ids.any? ? ["#{primary_key} NOT IN (?)", ids] : nil)
# Find remaining existing records (to be updated)
- existing = all.inject({}) {|existing, record| existing[record.id] = record; existing}
+ existing = all.inject({}) {|existing, record| existing[record.send(primary_key)] = record; existing}
records.map! do |attributes|
attributes.symbolize_keys!
defaults = attributes.delete(:defaults)
# Update with new attributes
record =
- if record = existing[attributes[:id]]
+ if record = existing[attributes[primary_key]]
attributes.merge!(defaults.delete_if {|attribute, value| record.send("#{attribute}?")}) if defaults
record.attributes = attributes
record
else
attributes.merge!(defaults) if defaults
new(attributes)
end
- record.id = attributes[:id]
+ record.send("#{primary_key}=", attributes[primary_key])
# Force failed saves to stop execution
record.save!
record
end
@@ -315,30 +331,32 @@
# This produces a significant performance increase when bootstrapping more
# than several hundred records.
#
# See EnumerateBy::Bootstrapped#bootstrap for information about usage.
def fast_bootstrap(*records)
+ primary_key = self.primary_key.to_sym
+
# Remove records that are no longer being used
records.flatten!
- ids = records.map {|record| record[:id]}.compact
- delete_all(ids.any? ? ['id NOT IN (?)', ids] : nil)
+ ids = records.map {|record| record[primary_key]}.compact
+ delete_all(ids.any? ? ["#{primary_key} NOT IN (?)", ids] : nil)
# Find remaining existing records (to be updated)
quoted_table_name = self.quoted_table_name
- existing = connection.select_all("SELECT * FROM #{quoted_table_name}").inject({}) {|existing, record| existing[record['id'].to_i] = record; existing}
+ existing = connection.select_all("SELECT * FROM #{quoted_table_name}").inject({}) {|existing, record| existing[record[primary_key.to_s].to_i] = record; existing}
records.each do |attributes|
attributes.stringify_keys!
if defaults = attributes.delete('defaults')
defaults.stringify_keys!
end
- id = attributes['id']
+ id = attributes[primary_key.to_s]
if existing_attributes = existing[id]
# Record exists: Update attributes
- attributes.delete('id')
+ attributes.delete(primary_key.to_s)
attributes.merge!(defaults.delete_if {|attribute, value| !existing_attributes[attribute].nil?}) if defaults
- update_all(attributes, :id => id)
+ update_all(attributes, primary_key => id)
else
# Record doesn't exist: create new one
attributes.merge!(defaults) if defaults
column_names = []
values = []