I have a User model
is there a difference between
class User < ActiveRecord::Base
validates :name, :presence => true
end
and
class User < ActiveRecord::Base
def validate
errors.add_to_base "name should not be nil" if name.nil?
end
end
The validates macro is more flexible, as it also allows you to do things like:
validates :name, :format => { :with => /\A[a-zA-Z]+\z/,
:message => "Only letters allowed" }, :length => { :in => 6..20 }
The validate method is really a quick and easy way to do custom validations when existing ones do not exist. (When custom validations get too complex, then you should usually move them into custom validators and use the validates macro).
See more at http://guides.rubyonrails.org/active_record_validations_callbacks.html
Yes -- the first will fail to save an empty string, whereas the second will allow it.
Related
I have a text field that can be empty when created, but not when updated.
How can I do that in rails: Different validation rules depending on action?
The idea behind this, is to allow an admin to create a blank issue ticket, to be filled by a user.
Here is my original model (issue.rb):
class Issue < ActiveRecord::Base
attr_accessible :content, :status
validates :content, :presence => true, :length => { :maximum => 2048 }
validates :status, :inclusion => { :in => %w(WAITING REJECTED ON OFF) }
belongs_to :user
end
How can I set :presence => true of :content only when updating, but not when creating?
Thanks in advance.
You can use :on => :create in your validation statement.
Like in this question.
I need to perform the validation to make sure that only one user within a company can exist within a given category.
validates :user_id, :uniqueness => {:scope => [:category, :company_id], :message => "already exists"}
This works except the error message is set on :user_id key.
How can I do the same but set the error on the :user key (validates :user gives an error)?
Here's a simple way to check uniqueness and force the error to be assigned to the :user attribute:
class User < ActiveRecord::Base
validate :user_unique_per_company_per_category
private
def user_unique_per_company_per_category
if self.class.exists?(:user_id => user_id, :company_id => company_id, :category => category)
errors.add :user, 'already exists'
end
end
end
It would be preferable, I think, if you could figure out a way to use the default validation on :user_id, but maybe you have a special use case.
Also, if you're not using this in a form, you might consider assigning the error to :base, since you might confuse future developers who expect the error to appear on :user_id:
errors.add :base, 'already exists'
I don't think this is possible as the validates method of ActiveRecord sends the errors to the method being validated.
So validates :user trys to send to the attr_accessor of :user which doesn't exist in your model.
Though, if you're just trying to make the error message pretty you can:
alias user user_id
And then use :user in your validation.
validates :user, :uniqueness => {:scope => [:category, :company_id], :message => "already exists"}
On a side note, I wouldn't use user in the alias rather something like:
alias the_supplied_user user_id
And then in your validation:
validates :the_supplied_user, :uniqueness => {:scope => [:category, :company_id], :message => "already exists"}
I have a model called Science Subject Choice
class ScienceSubjectChoice < SubjectChoice
belongs_to :subject
belongs_to :subject_preference
validates_associated :subject
validates_associated :subject_preference
#TODO: validation
validates :priority, :presence => true, :numericality => true, :inclusion => {:in => 1..SubjectPreference::MAX_SCIENCE_SUBJECT_CHOICE}
validates_uniqueness_of :subject_id, :scope => :subject_preference_id
validates_uniqueness_of :priority, :scope => :subject_preference_id
end
the uniqueness validator don't work on unsaved data?
How can I solve it?
Solution:
Instead of validating in itself, the parent object should do the validation:
def validate_science_subject_choices_uniqueness
if science_subject_choices.map(&:priority) != science_subject_choices.map(&:priority).uniq
errors[:base] << "Duplicated priority in science subject"
end
end
Validations do not work like that. They are dynamic by nature. If you want database constraints, you have to specify it in your migrations. For instance, a :uniq => true would make sure that a value is unique in your model.
I want to display something like:
validates :field, :inclusion => { :in => fields, :message => "is not allowed: {self.field}"}
But the self is referring to the class itself rather than the instance variable.
If I understood it correctly, you want something like
class Coffee < ActiveRecord::Base
validates_inclusion_of :size, :in => %w(small medium large),
:message => "%{value} is not a valid size"
end
Example from the docs
I have a sentence and correction model with a has_one and belongs_to relationship respectively.
For some reason when I do
def create
#sentence = Sentence.find(params[:sentence_id])
#correction = #sentence.build_correction(params[:correction])
a custom validation I wrote for Correction is being called at the build_correction point. the validation is below
class Correction < ActiveRecord::Base
attr_accessible :text, :sentence_id, :user_id
belongs_to :sentence
belongs_to :user
validate :correction_is_different_than_sentence
def correction_is_different_than_sentence
errors.add(:text, "can't be the same as the original sentence.") if (text == self.sentence.text)
end
the problem is for some reason on validation the correction object doesn't have the sentence id set (despite I used the build_correction method) and so it complains
"you have nil object .... while executing nil.text" in the if clause in the validation above.
So my question is why is the validation occuring for a build command, i thought it only triggers on a create or update. And why isnt the sentence_id getting set?
Some error was creating a lot of headaches for me. Don't know why but moving custom validator call to the end of other validator calls fixed this for me.
Before
validates :name, :short_description, presence: true
validate :uniq_name
validates :price, :numericality => {:greater_than_or_equal_to => 0}
validates_attachment_content_type :image, :content_type => /image/
After
validates :name, :short_description, presence: true
validates :price, :numericality => {:greater_than_or_equal_to => 0}
validates_attachment_content_type :image, :content_type => /image/
validate :uniq_name
here is my custom validator
private
def uniq_name
return if clone?
user_product = self.user.products.unlocked.where(:name => self.name).first
errors[:name] << "has already been taken" if user_product && !user_product.id.eql?(self.id)
end
Try this, may be it will do the trick for you too.
As ever it was not rails fault but my own - its trivial, long to explain, no use to anyone else so wont explain.