[ACCEPTED]-Rails ActiveRecord: validate single attribute-rails-activerecord

Accepted answer
Score: 46

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

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

Or add it to ActiveRecord::Base

Score: 46

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

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

validators_on(*attributes) public

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

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

e.g. we only want to validate the 7 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 6 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 5 will validate only the title attribute without 4 invoking any other validations.

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

note

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

Score: 11

I wound up building on @xlembouras's answer 2 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 1 do stuff like this in a controller:

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

Building on @coreyward's answer, I also 1 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

More Related questions