使范围和实例方法具有相同的条件更干燥

时间:2015-09-30 10:44:31

标签: ruby-on-rails ruby rails-activerecord

假设您有一个定义范围的模型,其条件也在实例方法中使用:

class Thing < ActiveRecord::Base
  scope :complete?, -> {
    where(
      foo: true,
      bar: true,
      baz: true
    )
  }

  def complete?
    foo? && bar? && baz?
  end
end

如果您需要更改complete?的定义,则必须记住更改范围和实例方法。有没有一种很好的方法来合并这两个定义并使代码更干一些?

如果其中一个条件本身就是一个实例方法,则问题会稍微复杂一些:

class Thing < ActiveRecord::Base
  scope :complete?, -> {
    where(
      foo: true,
      bar: true,

      # can't use instance method `base?` here for `baz` condition
      # you would have to duplicate the logic:
      name: 'baz'
    )
  }

  def baz?
    name == 'baz'
  end

  def complete?
    foo? && bar? && baz?
  end
end

1 个答案:

答案 0 :(得分:3)

DRY的意思是“不要重复自己”。在那些片段中,我没有看到任何重复。所以没有什么可以干的。

你可能的意思是

  

有一条信息可以从中生成两种方法。如果此信息发生变化,如何才能更改一次,以免我不小心忘记更新其他地方?

嗯,你可以做一些这样的元编程体操:

class Thing < ActiveRecord::Base
  FIELDS_FOR_COMPLETE = {
    foo: true,
    bar: true,
    baz: true,
  }

  scope :complete?, -> {
    where(FIELDS_FOR_COMPLETE)
  }

  def complete?
    FIELDS_FOR_COMPLETE.all? do |method_name, expected_value|
      self.public_send(method_name) == expected_value
    end
  end
end

由您来决定哪一个更容易阅读,理解和维护。

我,我选择了第一个(有些重复的)版本。这让我思考得更少。对于可能加入该项目的任何其他rails程序员来说,它也是显而易见的。