代码阅读:为什么下面的代码是这样实现的?

问题描述:

我期待在代码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中有class_eval,在Array上定义cache_key有什么意义?

该方法的目的是为单个记录上的标准缓存之外的记录数组添加缓存,因此它在Array中实现。很可能,作者试图通过将其包装在ActiveRecord::Base的class_eval中来污染类别ruby Array。这种方法不会防止这种污染,但它会增加所需的方法。

+0

那么,这是否也适用于'ActiveRecord :: Relation'呢? – Geo 2013-03-11 18:11:30

+2

@Tempus,这个代码是在2009年为Rails 2.3.x编写的,之前有'ActiveRecord :: Relation'(一个Rails 3.x概念)存在。不,它不适用于其他集合(除非它们是Array的子​​类)。 – PinnyM 2013-03-11 18:15:26

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

我希望这只会改变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不存在,这会提高。

+0

检查ActiveRecord的好处,虽然有更直接的方法来做同样的事情(例如'defined?')。 – PinnyM 2013-03-22 13:40:27