1
0
Fork 0
mirror of https://github.com/paper-trail-gem/paper_trail.git synced 2022-11-09 11:33:19 -05:00

Fix for Rails 3.1+ IdentityMap, now with ugly test.

This commit is contained in:
Burke Libbey 2011-05-12 11:54:39 -05:00
parent 163fcd5e25
commit 5df9949ff4
2 changed files with 66 additions and 41 deletions

View file

@ -19,6 +19,16 @@ class Version < ActiveRecord::Base
where(['created_at > ?', timestamp]).order("created_at ASC, #{self.primary_key} ASC")
}
# In Rails 3.1+, calling reify on a previous version confuses the
# IdentityMap, if enabled. This prevents insertion into the map.
def with_identity_map_disabled(&block)
if defined?(ActiveRecord::IdentityMap)
ActiveRecord::IdentityMap.without(&block)
else
block.call
end
end
# Restore the item from this version.
#
# This will automatically restore all :has_one associations as they were "at the time",
@ -31,49 +41,51 @@ class Version < ActiveRecord::Base
# set to a float to change the lookback time (check whether your db supports
# sub-second datetimes if you want them).
def reify(options = {})
options.reverse_merge! :has_one => 3
unless object.nil?
attrs = YAML::load object
# Normally a polymorphic belongs_to relationship allows us
# to get the object we belong to by calling, in this case,
# +item+. However this returns nil if +item+ has been
# destroyed, and we need to be able to retrieve destroyed
# objects.
#
# In this situation we constantize the +item_type+ to get hold of
# the class...except when the stored object's attributes
# include a +type+ key. If this is the case, the object
# we belong to is using single table inheritance and the
# +item_type+ will be the base class, not the actual subclass.
# If +type+ is present but empty, the class is the base class.
if item
model = item
else
inheritance_column_name = item_type.constantize.inheritance_column
class_name = attrs[inheritance_column_name].blank? ? item_type : attrs[inheritance_column_name]
klass = class_name.constantize
model = klass.new
end
attrs.each do |k, v|
begin
model.send :write_attribute, k.to_sym , v
rescue NoMethodError
logger.warn "Attribute #{k} does not exist on #{item_type} (Version id: #{id})."
with_identity_map_disabled do
options.reverse_merge! :has_one => 3
unless object.nil?
attrs = YAML::load object
# Normally a polymorphic belongs_to relationship allows us
# to get the object we belong to by calling, in this case,
# +item+. However this returns nil if +item+ has been
# destroyed, and we need to be able to retrieve destroyed
# objects.
#
# In this situation we constantize the +item_type+ to get hold of
# the class...except when the stored object's attributes
# include a +type+ key. If this is the case, the object
# we belong to is using single table inheritance and the
# +item_type+ will be the base class, not the actual subclass.
# If +type+ is present but empty, the class is the base class.
if item
model = item
else
inheritance_column_name = item_type.constantize.inheritance_column
class_name = attrs[inheritance_column_name].blank? ? item_type : attrs[inheritance_column_name]
klass = class_name.constantize
model = klass.new
end
attrs.each do |k, v|
begin
model.send :write_attribute, k.to_sym , v
rescue NoMethodError
logger.warn "Attribute #{k} does not exist on #{item_type} (Version id: #{id})."
end
end
model.version = self
unless options[:has_one] == false
reify_has_ones model, options[:has_one]
end
model
end
model.version = self
unless options[:has_one] == false
reify_has_ones model, options[:has_one]
end
model
end
end
end
# Returns who put the item into the state stored in this version.

View file

@ -96,7 +96,20 @@ class HasPaperTrailModelTest < ActiveSupport::TestCase
should 'have versions that are not live' do
assert @widget.versions.map(&:reify).compact.all? { |w| !w.live? }
end
should 'not clobber the IdentityMap when reifying' do
module ::ActiveRecord
class IdentityMap
def self.without(&block)
@unclobbered = true
block.call
end
end
end
@widget.versions.last.reify
assert ActiveRecord::IdentityMap.instance_variable_get("@unclobbered")
end
context 'and has one associated object' do
setup do