Rails和ActiveRecord:DRY在范围和布尔方法中使用相同的逻辑

Aug*_*ger 5 ruby activerecord ruby-on-rails

我有一个范围和方法的模型,如下所示:

class Model < ActiveRecord::Base

  scope :editable, where('updated_at > ? OR (updated_at IS NULL AND created_at > ?)', (Date.today - 3.days).beginning_of_day, (Date.today - 3.days).beginning_of_day)

  def editable?
    return (self.updated_at || self.created_at) > (Date.today - 3.days).beginning_of_day
  end

end
Run Code Online (Sandbox Code Playgroud)

我觉得我不应该在范围和方法中写两次相同的逻辑.有没有办法可以避免这种情况?

我在Rails 3.2上

谢谢

Bro*_*tse 3

不幸的是,目前没有简单的方法可以做到这一点。你能得到的最接近的是

def editable?
  self.class.editable.exists? self
end
Run Code Online (Sandbox Code Playgroud)

但是它会调用数据库来检查给定的记录是否存在,因此对于新记录或要更新的记录是没有用的。

之所以没有这样的功能,是因为这需要从 SQL/Arel 转换为 ruby​​ 代码,这可能一点也不简单(因为其他模型可能涉及 JOIN 语句)。但是如果你安装了 squeel gem,你应该能够写:

class Model < ActiveRecord::Base

  editable = -> {
    (updated_at > (Date.today - 3.days).beginning_of_day) | ((updated_at == nil) & created_at > (Date.today - 3.days).beginning_of_day)
  }

  scope :editable, where &editable

  def editable?
    instance_eval &editable
  end

end
Run Code Online (Sandbox Code Playgroud)

这几乎就是你所需要的。(未经测试!)

更新:请注意,squeel gem 目前尚未维护,这可能很危险。