自定义Rails缓存和关联 - 覆盖ActiveRecord.find

时间:2011-10-30 08:10:53

标签: ruby-on-rails

我想立即为find_by_id编写自定义ActiveRecord缓存。 为此,我想覆盖find方法,当只给出一个int时使用我的缓存,否则使用默认实现。

class X < ActiveRecord::Base
    def self.find(*args)
        return XCache[args[0]] if args.size == 1 && args[0].is_a?(Numeric)
        return super.find(*args)
    end
end

除了我与X的其他实例之间存在关联的情况外,一切都有效,例如:亲子关系:

has_many :x_children
has_many :children, :class_name => "X", :through => :x_children

当我致电X.find(1).children时,我收到Enumerator而不是Array,这是不好的,因为我有时使用[]运算符。

即使使用枚举器也不能正常工作 - 在迭代我得到的最后一个条目时:

NoMethodError: undefined method `call' for :all:Symbol

任何帮助都将受到高度赞赏

进一步解释:

XCache只是一个缓存ActiveRecord实例的类。 一个简单的实现可以

class XCache
    @@cache = {}
    def self.[id]
        return @@cache[id] ||= X.find(id)
    end
end

(更高级的实现可以包括到期时间,Memcached等,更通用的解决方案可以支持多个模型类。)

我不认为我的问题与缓存实现有关(但我可能错了)

2 个答案:

答案 0 :(得分:1)

正如您所见,这里有很多隐藏的复杂性。您可以查看cache-money宝石,这些人花了很多精力搞清楚。

要查看的其他宝石:simple_cacheable

答案 1 :(得分:0)

不确定它是否有帮助,但......这就是内部的发现:

  def find(*args)
    options = args.extract_options!
    validate_find_options(options)
    set_readonly_option!(options)

    case args.first
      when :first then find_initial(options)
      when :last  then find_last(options)
      when :all   then find_every(options)
      else             find_from_ids(args, options)
    end
  end

您不需要重载“find”,而是“find_from_ids”

这将让你独自留下使用find的所有其他方式,并且只针对你自己的用法。给予枚举器是find(:all)返回的...它可能有助于你的情况(或者可能不会)

其他可能性是...... Xcache只返回一个ActiveRecord,或者它有时可能返回一个集合......甚至是一个空集?

也许您可以尝试各种变体:

def self.find(*args)
    if args.size == 1 && args[0].is_a?(Numeric)
       rval = XCache[args[0]]
       return rval if rval.present?
    end
    super.find(*args)
end