validates_uniqueness_of can't check on unsaved data? - ruby-on-rails

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.

Related

Rails unit testing model validation :inclusion fails

Model order.rb
class Order < ActiveRecord::Base
attr_accessible :address, :email, :name, :payment_type_id
belongs_to :payment_type
PAYMENT_TYPES = PaymentType.pluck(:id)
validates :name, :address, :email, :payment_type_id, :presence => true
validates :payment_type_id, :inclusion => {:in => PAYMENT_TYPES}
end
Model payment_type.rb
class PaymentType < ActiveRecord::Base
attr_accessible :name, :id
has_many :order
end
From browser, validation works fine, if it is wrong it give an error, else go forward.
But problem is when I run rake test:functionals from terminal. Test didn't pass the validation. If I comment this line:
validates :payment_type_id, :inclusion => {:in => PAYMENT_TYPES}
all is ok. I don't understand why it is working in one plase, but in tests not ? ...
Fixtures are all ok.
Please help.
Most likely the problem is, that you are storing your payment types in a constant.
For your tests to work, the PaymentTypes have to be available in the database before rails loads your Order model, and this might not be the case.
One way to get around this, would be to use a (memoized) class method to store your payment types. As long as you access this class method after all your PaymentTypes are in the database, you should be fine.
class Order < ActiveRecord::Base
validates :payment_type_id, :inclusion => { :in => self.payment_types }
def self.payment_types
##payment_types ||= PaymentType.pluck(:id)
end
end

Rails: How to set different validation rules on creation and update

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.

ActiveRecord validate :uniqueness on association

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"}

Sexy validator for uniqueness with :scope constraint

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

rails 3 validation on uniqueness on multiple attributes

I use Rails 3.0.0.beta4
I want to add a validation on uniqueness on two attributes, that means that my model is valid if the couple of 'recorded_at' and 'zipcode' is unique.
On one attribute here is the syntax
validates :zipcode, :uniqueness => true
thanks
In Rails 2, I would have written:
validates_uniqueness_of :zipcode, :scope => :recorded_at
In Rails 3:
validates :zipcode, :uniqueness => {:scope => :recorded_at}
For multiple attributes:
validates :zipcode, :uniqueness => {:scope => [:recorded_at, :something_else]}
Multiple Scope Parameters:
class TeacherSchedule < ActiveRecord::Base
validates_uniqueness_of :teacher_id, :scope => [:semester_id, :class_id]
end
http://apidock.com/rails/ActiveRecord/Validations/ClassMethods/validates_uniqueness_of
This should answer Greg's question.
Dont work for me, need to put scope in plural
validates_uniqueness_of :teacher_id, :scopes => [:semester_id,
:class_id]

Resources