Rails ActiveRecord:验证单个属性

Nik*_*hev 31 validation ruby-on-rails rails-activerecord

如果有办法我可以在Rails中验证单个属性?

就像是:

ac_object.valid?(attribute_name)
Run Code Online (Sandbox Code Playgroud)

我将它用于特定模型字段的AJAX验证.将这些验证移动到Javascript会使代码变得非常难看.

egz*_*gze 39

您可以在模型中实现自己的方法.像这样的东西

def valid_attribute?(attribute_name)
  self.valid?
  self.errors[attribute_name].blank?
end
Run Code Online (Sandbox Code Playgroud)

或者将其添加到 ActiveRecord::Base

  • 事实上,如果您使用某些表单构建器,这种方法可能会有问题.例如,您可能会开始在尚未输入的字段上显示错误. (6认同)

xle*_*ras 27

有时会有非常昂贵的验证(例如需要执行数据库查询的验证).在这种情况下,您需要避免使用,valid?因为它只是比您需要的更多.

还有另一种解决方案.你可以使用的validators_on方法ActiveModel::Validations.

validators_on(*attributes)public

列出用于验证特定属性的所有验证程序.

根据您可以手动验证您想要的属性

例如,我们只是想确认titlePost:

class Post < ActiveRecord::Base

  validates :body, caps_off: true 
  validates :body, no_swearing: true
  validates :body, spell_check_ok: true

  validates presence_of: :title
  validates length_of: :title, minimum: 30
end
Run Code Online (Sandbox Code Playgroud)

哪里no_swearingspell_check_ok都是非常昂贵的复杂方法.

我们可以做到以下几点:

def validate_title(a_title)
  Post.validators_on(:title).each do |validator|
    validator.validate_each(self, :title, a_title)
  end
end
Run Code Online (Sandbox Code Playgroud)

这将仅验证title属性而不调用任何其他验证.

p = Post.new
p.validate_title("")
p.errors.messages
#=> {:title => ["title can not be empty"]
Run Code Online (Sandbox Code Playgroud)

注意

我并不完全相信我们应该validators_on安全使用,所以我会考虑以理智的方式处理异常validates_title.

  • 使用`self.class.validators_on`并将属性名称作为参数使其更具可重用性. (2认同)

cor*_*ard 5

我总结了@xlembouras的答案,并在我的方法中添加了此方法ApplicationRecord

class ApplicationRecord < ActiveRecord::Base
  self.abstract_class = true

  def valid_attributes?(*attributes)
    attributes.each do |attribute|
      self.class.validators_on(attribute).each do |validator|
        validator.validate_each(self, attribute, send(attribute))
      end
    end
    errors.none?
  end
end
Run Code Online (Sandbox Code Playgroud)

然后,我可以在控制器中执行以下操作:

if @post.valid_attributes?(:title, :date)
  render :post_preview
else
  render :new
end
Run Code Online (Sandbox Code Playgroud)

  • **有一个错误**:“errors.none?”可能指其他错误(例如,如果此函数之前针对不同的属性运行)。可能的改进:如果您只关心布尔标志而不关心实际错误,您可以考虑在循环中返回为:`return false except self.errors[attribute].blank?`。我认为“self[attribute]”比“send(attribute)”更好,但这只是个人喜好。您也可以将其提取到关注点,而不是将其放在父类中(同样,首选项)。 (3认同)