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.
Related
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.
I validate fields in model using:
validates :first_name, :presence => true, :if => :should_validate?
validates :last_name, :presence => true, :if => :should_validate?
...
There are many fields in model that needs to be validated and it doesn't look good if I specify :if => method for each one.
Is it possible to embed this validates methods in block instead of giving :if => method for each one?
You could write your own custom validator of course, but if you're only validating presence, this might do the trick:
validates :first_name, :last_name, :presence => true, :if => :should_validate?
I don't think there is something out of the box for this. If you want, you can use a custom validator.
What are the conditions that you need this validated? If you don't need it validated couldn't you just leave that line out? Otherwise you could just validate on certain actions so you don't need to evaluate for should_validate?, for example:
validates :first_name, :last_name, :presence => true, :only => [:create, :update]
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.
In a Ruby on Rails 3 application, I have invitations. Here is the model:
class TeamInvitation < ActiveRecord::Base
belongs_to :team
validates :email, :presence => true, :format => RFC822::EMAIL
validates_uniqueness_of :email, :scope => :team_id
end
How can I refactor the uniqueness validation to include it into the validates method?
According to the documentation, the key :uniqueness should be a boolean, but in my case i want specify the scope. How can I do that (if possible)?
Have you tried this?
:uniqueness => { :scope => :team_id }
I haven't, but I know other ones can accept a hash. Might be worth a shot.
you can try :uniqueness => true
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.