Active Record Identity Map
Ensures that each object gets loaded only once by keeping every loaded object in a map. Looks up objects using the map when referring to them.
More information on Identity Map pattern:
http://www.martinfowler.com/eaaCatalog/identityMap.html
Configuration
In order to enable IdentityMap, set
config.active_record.identity_map = true
in your
config/application.rb
file.
IdentityMap is disabled by default and still in development (i.e. use it with care).
Associations
Active Record Identity Map does not track associations yet. For example:
comment = @post.comments.first comment.post = nil @post.comments.include?(comment) #=> true
Ideally, the example above would return false, removing the comment object from the post association when the association is nullified. This may cause side effects, as in the situation below, if Identity Map is enabled:
Post.has_many :comments, :dependent => :destroy comment = @post.comments.first comment.post = nil comment.save Post.destroy(@post.id)
Without using Identity Map, the code above will destroy the @post object leaving the comment object intact. However, once we enable Identity Map, the post loaded by Post.destroy is exactly the same object as the object @post. As the object @post still has the comment object in @post.comments, once Identity Map is enabled, the comment object will be accidently removed.
This inconsistency is meant to be fixed in future Rails releases.
- A
- C
- E
- G
- R
- U
- W
Source: show
# File activerecord/lib/active_record/identity_map.rb, line 92 def add(record) repository[record.class.symbolized_sti_name][record.id] = record end
Source: show
# File activerecord/lib/active_record/identity_map.rb, line 104 def clear repository.clear end
Source: show
# File activerecord/lib/active_record/identity_map.rb, line 51 def enabled Thread.current[:identity_map_enabled] end
Source: show
# File activerecord/lib/active_record/identity_map.rb, line 47 def enabled=(flag) Thread.current[:identity_map_enabled] = flag end
Source: show
# File activerecord/lib/active_record/identity_map.rb, line 77 def get(klass, primary_key) record = repository[klass.symbolized_sti_name][primary_key] if record.is_a?(klass) ActiveSupport::Notifications.instrument("identity.active_record", :line => "From Identity Map (id: #{primary_key})", :name => "#{klass} Loaded", :connection_id => object_id) record else nil end end
Source: show
# File activerecord/lib/active_record/identity_map.rb, line 96 def remove(record) repository[record.class.symbolized_sti_name].delete(record.id) end
Source: show
# File activerecord/lib/active_record/identity_map.rb, line 100 def remove_by_id(symbolized_sti_name, id) repository[symbolized_sti_name].delete(id) end
Source: show
# File activerecord/lib/active_record/identity_map.rb, line 56 def repository Thread.current[:identity_map] ||= Hash.new { |h,k| h[k] = {} } end
Source: show
# File activerecord/lib/active_record/identity_map.rb, line 60 def use old, self.enabled = enabled, true yield if block_given? ensure self.enabled = old clear end
Source: show
# File activerecord/lib/active_record/identity_map.rb, line 69 def without old, self.enabled = enabled, false yield if block_given? ensure self.enabled = old end
Reinitialize an Identity Map model object from coder
.
coder
must contain the attributes necessary for initializing
an empty model object.
Source: show
# File activerecord/lib/active_record/identity_map.rb, line 112 def reinit_with(coder) @attributes_cache = {} dirty = @changed_attributes.keys @attributes.update(coder['attributes'].except(*dirty)) @changed_attributes.update(coder['attributes'].slice(*dirty)) @changed_attributes.delete_if{|k,v| v.eql? @attributes[k]} set_serialized_attributes run_callbacks :find self end