使用方法澄清自定义Rails 3.0验证

时间:2011-07-06 01:01:19

标签: ruby-on-rails validation readability

我在Rails 3.0中创建了一个自定义验证器,用于验证列的组合在表中是否唯一。整个验证代码是:

class UniqueInProjectValidator < ActiveModel::EachValidator

  def validate_each(object, attribute, value)
    unless object.class.where("project_id = ? AND #{attribute} = ?", object.project_id, value).empty?
      if object.new_record?
        object.errors[attribute] << (options[:message] || "must be unique in each project")
      else
        orig_rec = object.class.find(object.id)
        if value != orig_rec.method(attribute).call || object.project_id != orig_rec.project_id
          object.errors[attribute] << (options[:message] || "must be unique in each project")
        end
      end
    end

end

请注意,识别if语句的功能并不容易,因此我希望能够使用unless方法和第二个def attribute_and_project_exist?语句替换if条件使用def attribute_or_project_changed?方法。但是,在创建这些方法时,由于封装,validates_each的参数不会通过。

现在的问题是:有没有办法以某种方式干净地允许我的两个新创建的方法访问这些变量,因为可以使用模型中的列名称,或者我坚持选择再次传递每个参数还是留下难以阅读的条件陈述?

提前致谢!

1 个答案:

答案 0 :(得分:1)

我想你可以用一个变量,一个lambda和一个“尽快返回”来清理它:

def validate_each(object, attribute, value)
  # If there is no duplication then bail out right away as
  # there is nothing to check. This reduces your nesting by
  # one level. Using a variable here helps to make your
  # intention clear.
  attribute_and_project_exists = object.class.where("project_id = ? AND #{attribute} = ?", object.project_id, value).empty?
  return unless attribute_and_project_exists

  # This lambda wraps up your second chunk of ugly if-ness and saves
  # you from computing the result unless you have to.
  attribute_or_project_changed = lambda do
    orig_rec = object.class.find(object.id)
    value != orig_rec.method(attribute).call || object.project_id != orig_rec.project_id
  end

  # Note that || short-circuits so the lambda will only be 
  # called if you have an existing record.
  if object.new_record? || attribute_or_project_changed.call
    object.errors[attribute] << (options[:message] || "must be unique in each project")
  end
end

我不知道这比你原来的好多少,但由于更好的分块,逻辑和控制流程对我来说更加清晰。