3

我正在查看group_cache_key方法的代码,我以前从未见过这种写法:

require 'activerecord'
require 'activesupport'
require 'digest/md5'

ActiveRecord::Base.class_eval {
  Array.class_eval {
    def cache_key
      if self.empty?
        'empty/' + self.object_id.to_s
      else
        ids_hash = Digest::MD5.hexdigest(self.collect{|item| item.id }.to_s)
        update_timestamp = max {|a,b| a.updated_at <=> b.updated_at }.updated_at.to_i.to_s
        create_timestamp = max {|a,b| a.created_at <=> b.created_at }.created_at.to_i.to_s
        self.first.class.to_s.tableize+'/'+length.to_s+'-'+ids_hash+'-'+create_timestamp+'-'+update_timestamp
      end
    end
  }
}

为什么方法是这样实现的?class_eval在 Array 中包含aclass_eval并在 Array 上定义有什么意义cache_key

4

3 回答 3

3

该方法的目的是除了对单个记录进行标准缓存之外,还为记录数组添加缓存,因此它是在Array. 最有可能的是,作者试图Array通过将 ruby​​ 类包装在 .class_eval 中来不污染它ActiveRecord::Base。这种方法不会防止这种污染,但它会添加cache_key所需的方法。

于 2013-03-11T18:10:01.867 回答
1

我希望这只会ArrayActiveRecord.

所以我创建了一个小测试程序来验证:

class Test
  class Array
    def initialize(bla)
      @array = bla
    end
  end

  def self.get_array_of(something)
    Array.new([something])
  end
end

Test.class_eval {
  Array.class_eval {
    def to_s
      "BLAAAAAAAA"
    end
  }
}

puts ["a", "b", "c"].to_s
puts Test.get_array_of("b").to_s

不幸的是,该程序的输出表明只有全局Array受到影响,并且Test::Array只有默认to_s功能。真可惜。

所以我可以考虑这样做的唯一原因是,如果ActiveRecord不存在,这将引发。

于 2013-03-17T15:50:24.953 回答
1

使用class_eval而不是仅仅重新打开类的唯一原因是在类不存在的情况下快速失败。这在您显示的代码中是不可能的,因为需要 ActiveRecord。我猜作者只是有一个奇怪的风格偏好。

于 2013-03-17T03:12:50.610 回答