Rails ActiveRecord:验证单个属性

发布于 2024-10-14 12:17:57 字数 111 浏览 2 评论 0原文

有什么方法可以验证 ActiveRecord 中的单个属性吗?

像这样的东西:

ac_object.valid?(attribute_name)

Is there any way I can validate a single attribute in ActiveRecord?

Something like:

ac_object.valid?(attribute_name)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

还给你自由 2024-10-21 12:17:57

有时有些验证非常昂贵(例如需要执行数据库查询的验证)。在这种情况下,您需要避免使用 valid? 因为它所做的事情远远超出了您的需要。

还有一个替代解决方案。您可以使用 ActiveModel::Validations< 的 validators_on 方法/代码>。

validators_on(*attributes) 公共

列出所有用于验证特定的验证器
属性。

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

例如我们只想验证 Posttitle

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

其中 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

这将仅验证标题属性,而不调用任何其他验证。

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

请注意,

我并不完全相信我们应该安全地使用 validators_on,因此我会考虑在 validates_title 中以合理的方式处理异常。

Sometimes there are validations that are quite expensive (e.g. validations that need to perform database queries). In that case you need to avoid using valid? because it simply does a lot more than you need.

There is an alternative solution. You can use the validators_on method of ActiveModel::Validations.

validators_on(*attributes) public

List all validators that are being used to validate a specific
attribute.

according to which you can manually validate for the attributes you want

e.g. we only want to validate the title of Post:

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

Where no_swearing and spell_check_ok are complex methods that are extremely expensive.

We can do the following:

def validate_title(a_title)
  Post.validators_on(:title).each do |validator|
    validator.validate_each(self, :title, a_title)
  end
end

which will validate only the title attribute without invoking any other validations.

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

note

I am not completely confident that we are supposed to use validators_on safely so I would consider handling an exception in a sane way in validates_title.

〃安静 2024-10-21 12:17:57

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

def valid_attribute?(attribute_name)
  self.valid?
  self.errors[attribute_name].blank?
end

或者将其添加到ActiveRecord::Base

You can implement your own method in your model. Something like this

def valid_attribute?(attribute_name)
  self.valid?
  self.errors[attribute_name].blank?
end

Or add it to ActiveRecord::Base

夏末 2024-10-21 12:17:57

我最终以 @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

然后我可以在控制器中执行类似的操作:

if @post.valid_attributes?(:title, :date)
  render :post_preview
else
  render :new
end

I wound up building on @xlembouras's answer and added this method to my 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

Then I can do stuff like this in a controller:

if @post.valid_attributes?(:title, :date)
  render :post_preview
else
  render :new
end
ゞ花落谁相伴 2024-10-21 12:17:57

在 @coreyward 的回答的基础上,我还添加了一个 validate_attributes! 方法:

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

  def validate_attributes!(*attributes)
    valid_attributes?(*attributes) || raise(ActiveModel::ValidationError.new(self))
  end
end

Building on @coreyward's answer, I also added a validate_attributes! method:

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

  def validate_attributes!(*attributes)
    valid_attributes?(*attributes) || raise(ActiveModel::ValidationError.new(self))
  end
end
贵在坚持 2024-10-21 12:17:57

由于 validator.validate_each 是私有方法,我在使用其他解决方案时遇到了问题。

下面是在 Rails 6 下运行的代码片段:

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(self)
      end
    end
    errors.none?
  end
end

I had problems with other solutions due to validator.validate_each being a private method.

Here's a snippet that's working under Rails 6:

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(self)
      end
    end
    errors.none?
  end
end
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文