我正在阅读The Rails 4 way(作者:Obie Fernandez),这是一本关于Rails的着名书籍,从我到目前为止所读到的内容,我强烈推荐它。
但是,有一个示例部分 9.2.7.1:一个类中的多个回调方法让我困惑:
请耐心等待,为了让每个人都明白这个问题,我已经复制了这本书中描述的步骤。
该部分讨论Active Record回调(before_create
,before_update
等),并且可以创建一个为您处理多个回调的类。列出的代码如下:
class Auditor
def initialize(audit_log)
@audit_log = audit_log
end
def after_create(model)
@audit_log.created(model.inspect)
end
def after_update(model)
@audit_log.updated(model.inspect)
end
def after_destroy(model)
@audit_log.destroyed(model.inspect)
end
end
然后该书说将此审核日志记录添加到Active Record类,您将执行以下操作:
class Account < ActiveRecord::Base
after_create Auditor.new(DEFAULT_AUDIT_LOG)
after_update Auditor.new(DEFAULT_AUDIT_LOG)
after_destroy Auditor.new(DEFAULT_AUDIT_LOG)
...
end
本书随后指出这段代码非常难看,不得不在三行上添加三个审核员,而且它不干。然后它继续告诉我们要解决这个问题,我们应该将acts_as_audited
方法修补到Active Record::Base
对象中,如下所示:
(该书建议将此文件放在/lib/core_ext/active_record_base.rb
)
class ActiveRecord::Base
def self.acts_as_audited(audit_log=DEFAULT_AUDIT_LOG)
auditor = Auditor.new(audit_log)
after_create auditor
after_update auditor
after_destroy auditor
end
end
使您可以按如下方式编写Account Model类:
class Account < ActiveRecord::Base
acts_as_audited
...
end
在阅读本书之前,我已经做了类似的事情,为多个Active Record模型添加了功能。我使用的技术是创建一个模块。为了坚持这个例子,我所做的与以下内容类似:
(我会将此文件放在/app/models/auditable.rb
)
module Auditable
def self.included(base)
@audit_log = base.audit_log || DEFAULT_AUDIT_LOG #The base class can override it if wanted, by specifying a self.audit_log before including this module
base.after_create audit_after_create
base.after_update audit_after_update
base.after_destroy audit_after_destroy
end
def audit_after_create
@audit_log.created(self.inspect)
end
def audit_after_update
@audit_log.updated(self.inspect)
end
def audit_after_destroy
@audit_log.destroyed(self.inspect)
end
end
请注意,此文件都替换了Auditor
和猴子修补的ActiveRecord::Base
方法。然后Account
类看起来像:
class Account < ActiveRecord::Base
include Auditable
...
end
现在你已经读过这本书的方式,以及我过去的方式。我的问题:从长远来看哪个版本更具可持续性?我意识到这是一个有点自以为是的问题,就像关于Rails的一切一样,但为了让它负责,我基本上想知道:< / p>
ActiveRecord::Base
,而不是创建并包含Module
?答案 0 :(得分:2)
出于某些原因,我会选择该模块。
显而易见;也就是说,我可以快速找到定义此行为的代码。在acts_as_*
我不知道它是来自某些gem,库代码还是在这个类中定义的。它可能会在调用堆栈中被覆盖或捎带。
便于携带。它使用通常在定义回调的库中定义的方法调用。您可以想象在非活动记录对象中分发和使用此库。
它避免在静态级别添加不必要的代码。我喜欢用更少代码来管理(减少要破解的代码)。我喜欢使用Ruby的细节,而没有做太多的事情来迫使它比现在更“好”。
在猴子补丁设置中,您将代码绑定到可能会消失的类或模块,并且在某些情况下它会无声地失败,直到您的班级无法调用acts_as_*
。
可移植性参数的一个缺点是测试参数。在这种情况下,我会说你可以编写你的代码来保护免受可移植性的影响,或者提前通过智能警告来解决在便携式使用时会发生什么作用和什么不行的问题。