问题
If there is a way I can validate single attribute in Rails?
Something like:
ac_object.valid?(attribute_name)
I'm gonna use it for AJAX validation of particular model fields. Moving these validations to the Javascript makes code really ugly.
回答1:
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
回答2:
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
.
回答3:
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
来源:https://stackoverflow.com/questions/4804591/rails-activerecord-validate-single-attribute