Skip to content

Instantly share code, notes, and snippets.

@rywall
Created March 14, 2012 19:59
Show Gist options
  • Save rywall/2039089 to your computer and use it in GitHub Desktop.
Save rywall/2039089 to your computer and use it in GitHub Desktop.
Identity Map Bug Fix
gem 'rails', :git => 'git://github.com/rails/rails.git', :ref => 'c1f397f82c7b3f352500832a399b5dbdc500b9c8'# change as required
require 'active_record'
require 'logger'
# Show ActiveRecord log output
ActiveRecord::Base.logger = Logger.new(STDOUT)
# Print out what version we're running
puts "Active Record #{ActiveRecord::VERSION::STRING}"
# Connect to an in-memory sqlite3 database (more on this in a moment)
ActiveRecord::Base.establish_connection(
:adapter => 'sqlite3',
:database => ':memory:'
)
# Create the minimal database schema necessary to reproduce the bug
ActiveRecord::Schema.define do
create_table :posts, :force => true do |t|
end
create_table :comments, :force => true do |t|
t.integer :post_id
end
end
# Create the minimal set of models to reproduce the bug
class Post < ActiveRecord::Base
has_many :comments, :dependent => :destroy
end
class Comment < ActiveRecord::Base
belongs_to :post
after_save :clear_dirty_associations_from_im
# After a record is saved (if IdentityMap is enabled), check its reflections for any belongs_to associations
# that have a foreign key that was changed. These associated models have their entire association cache cleared.
def clear_dirty_associations_from_im
if ActiveRecord::IdentityMap.enabled?
reflections.values.each do |reflection|
if reflection.belongs_to?
klasses = if reflection.options[:polymorphic]
Array(changes[reflection.foreign_type]).compact.collect(&:constantize)
else
Array.new(2, reflection.klass)
end
ids = changes[reflection.foreign_key] || []
ActiveRecord::IdentityMap.get(klasses[0], ids[0]).try(:clear_association_cache) if klasses[0] && ids[0]
ActiveRecord::IdentityMap.get(klasses[1], ids[1]).try(:clear_association_cache) if klasses[1] && ids[1]
end
end
end
end
end
# Create some test data
#
# If you're demonstrating an exception, then this is probably not necessary,
# but if your bug is to do with the wrong data being returned from the database,
# then you'll probably need some test data to show that.
Comment.create(:post => Post.create!)
# Demonstrate the bug fix
ActiveRecord::IdentityMap.use do
post = Post.first
comment = post.comments[0]
comment.post = nil
comment.save
Post.destroy(post.id)
end
Comment.first != nil
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment