IdentityCache的fetch方法来自哪里
检查include了IdentityCache后的AR得到的fetch方法来自哪里
[2] pry(main)> Human.include IdentityCache
=> Human (call 'Human.connection' to establish a connection)
[5] pry(main)> Human.method(:fetch).source_location
=> ["/home/z/.rbenv/versions/2.4.0/lib/ruby/gems/2.4.0/gems/identity_cache-0.5.1/lib/identity_cache/query_api.rb", 44]
但在identity_cache-0.5.1/lib/identity_cache.rb中,发现这里也有一个fetch方法,那为什么AR的fetch方法不是这个而是identity_cache-0.5.1/lib/identity_cache/query_api.rb那个?
module IdentityCache
extend ActiveSupport::Concern
include ArTransactionChanges
include IdentityCache::BelongsToCaching
include IdentityCache::CacheKeyGeneration
include IdentityCache::ConfigurationDSL
include IdentityCache::QueryAPI
include IdentityCache::CacheInvalidation
include IdentityCache::ShouldUseCache
include IdentityCache::ParentModelExpiration
class << self
def fetch(key)
if should_use_cache?
unmap_cached_nil_for(cache.fetch(key) { map_cached_nil_for yield })
else
yield
end
end
原因在于,定义在module M中的类方法是无法通过include让class C/module N继承到的,因为module M的类方法其实是该module M的单例类的实例方法,而include只是让某个class C/module N的实例查找实例方法时能到被include的module M中查找,调用class C/module N类方法时,完全不会查找到module M的单例类
而identity_cache-0.5.1/lib/identity_cache/query_api.rb的fetch方法之所以能去到AR那里,是因为IdentityCache和IdentityCache::QueryAPI都是ActiveSupport::Concern,而IdentityCache.include IdentityCache::QueryAPI,因此IdentityCache::QueryAPI的fetch被带到AR上了
module IdentityCache
module QueryAPI
extend ActiveSupport::Concern
module ClassMethods
def fetch(id, options={})
fetch_by_id(id, options) or raise(ActiveRecord::RecordNotFound, "Couldn't find #{self.name} with ID=#{id}")
end