5

在我的用户模型中,我通常怀疑电子邮件、名字、姓氏、密码等。

我有几种情况需要跳过所有或部分验证。

目前,我有一个看起来像这样的除非条件:

  validates :first_name, presence: :true, etc..., unless: :skip_first_name_validation?
  validates :last_name, presence: :true, etc..., unless: :skip_last_name_validation?
  validates :email, presence: :true, etc..., unless: :skip_email_validation?

当然我也有:

  attr_accessor :skip_first_name_validation, :skip_last_name_validation, etc.

然后我使用私有方法来检查每个的状态:

  def skip_first_name_validation?
    skip_first_name_validation
  end

  def skip_last_name_validation?
    skip_last_name_validation
  end

  def skip_email_validation?
    skip_email_validation
  end

  etc..

true从那里开始,每当我需要跳过验证时,我只需在我的控制器中为每个人分配一个值。


因此,尽管所有这些都可以正常工作,但我想知道是否有更优雅的方法?

理想情况下,如果我可以对模型中的每个属性使用这样的简单条件,那就太好了:

:skip_validation?

在我的控制器中,只需执行以下操作:

skip_validation(:first_name, :last_name, :password) = true

有人可以就我如何编程提出建议吗?我不想使用现有的 gem/库,但我想了解如何在 rails 中编程这种行为。谢谢。

4

2 回答 2

1

这可以帮助您动态定义所有设置器和检查器

private 
def self.skip_validations_for(*args)
  
  # this block dynamically defines a setter method 'set_validations' 
  # e.g.
  #   set_validations(true, :email, :last_name, :first_name)
  #   set_validations(false, :email, :last_name, :first_name)
  define_method('set_validations') do |value, *params|
    params.each do |var|
      self.send("skip_#{var.to_s}_validations=", value)
    end
  end

  # this block walks through the passed in fields and defines a checker
  # method `skip_[field_name]_validation?
  args.each do |arg|
    if self.method_defined? arg
      send :define_method, "skip_#{attr.to_s}_validation?" do 
        send "skip_#{attr.to_s}_validation"  
      end
    end
  end
end

然后在您的模型中,无论这是本机的还是通过模块包含的,您都可以添加:

Class Foo < ActiveRecord::Base
  validate :bar, :presence => true
  validate :baz, :length_of => 10

  skip_validations_for :bar, :baz
end

届时您将可以访问

set_validations(true, :bar, :baz)

skip_bar_validation? 

更新:

这段代码会去哪里?

这取决于您希望使用它的范围。如果您只想覆盖一个模型中的验证,那么您可以将其全部直接放入该模型中。但是,如果您希望创建一个Module允许您在每个类中执行此操作的文件,那么您必须创建一个Module将其放入lib/目录并确保它位于加载路径中。也许可以帮助你。

为什么事情发生了如此巨大的变化?

最初我在一个实例上使用 _validations 方法,这是一个返回验证哈希的 ActiveRecord 方法(字段名称 -> ActiveRecord::Validation)。这种做事的方法自动开启了每个领域的能力。允许您选择所需的特定字段更符合 Rails 的要求。

于 2012-05-04T14:16:36.460 回答
0

我不是元编程方面的专家,但我想你可以像这样实现它。

class User < ActiveRecord::Base
  ...
  %w(email first_name last_name).each do |attr|
    self.send :attr_accessor, "skip_#{attr}_validation".to_sym
    self.send :alias, "skip_#{attr}_validation?".to_sym, "skip_#{attr}_validation".to_sym
    self.send :validates_presence_of, attr, { unless: "skip_#{attr}_validation?".to_sym }
  end

  def skip_validation_for(*attrs)
    attrs.map{|attr| send "skip_#{attr}_validation=", true }
  end
end

混入模型中并不是很优雅,但您可以将其制成一个模块 - 使用可能类似于:

class User < ActiveRecord::Base
  include SkipValidations
  skip_validations :email, :first_name, :last_name
end
于 2012-05-04T14:10:29.507 回答