I need your help validating a simple Rails model.
First i want to check if the user filled all input-fields:
class Test < ActiveRecord::Base
validates :firstname, :lastname, :firstvalue, :secondvalue, presence: true
[...]
I also want to check if the :secondvalue param is bigger than :firstvalue.
Adding
validate :biggerThan
def biggerThan
if self.secondvalue < self.firstvalue
errors.add(:secondvalue, "must be bigger than First")
end
end
Well this works, but only if all other fields are filled! Creating a new Entry leaving all fields blank i am getting an undefined method <' for nil:NilClass.
Could you help me?
You can do this
validate :biggerThan, if: Proc.new{ |test| test.firstvalue.present? and test.secondvalue.present? }
It would be good if you add numericality validations also
validates :firstvalue, numericality: true
validates :secondvalue, numericality: true
Related
I've some Active Record validations on my model:
class Product < ApplicationRecord
validates :name, presence: true, length: { is: 10 }
end
That seems fine. It validates that the field name is not nil, "" and that it must have exactly 10 characters. Now, if I want to add a custom validation, I'd add the validate call:
class Product < ApplicationRecord
validates :name, presence: true, length: { is: 10 }
validate :name_must_start_with_abc
private
def name_must_start_with_abc
unless name.start_with?('abc')
self.errors['name'] << 'must start with "abc"'
end
end
end
The problem is: when the name field is nil, the presence_of validation will catch it, but won't stop it from validating using the custom method, name_must_start_with_abc, raising a NoMethodError, as name is nil.
To overcome that, I'd have to add a nil-check on the name_must_start_with_abc method.
def name_must_start_with_abc
return if name.nil?
unless name.start_with?('abc')
self.errors['name'] << 'must start with "abc"'
end
end
That's what I don't wan't to do, because if I add more "dependant" validations, I'd have to re-validate it on each custom validation method.
How to handle dependant validations on Rails? Is there a way to prevent a custom validation to be called if the other validations haven't passed?
I think there is no perfect solution unless you write all your validations as custom methods. Approach I use often:
class Product < ApplicationRecord
validates :name, presence: true, length: { is: 10 }
validate :name_custom_validator
private
def name_custom_validator
return if errors.include?(:name)
# validation code
end
end
This way you can add as many validations to :name and if any of them fails your custom validator won't execute. But the problem with this code is that your custom validation method must be last.
class Product < ApplicationRecord
validates :name, presence: true, length: { is: 10 }
validate :name_must_start_with_abc, unless: Proc.new { name.nil? }
private
def name_must_start_with_abc
unless name.start_with?('abc')
self.errors['name'] << 'must start with "abc"'
end
end
end
Please check allow_blank, :allow_nil and conditional validation as well for more options.
lets say that I want to make the possibility of posting two types of posts [long] and [short] sharing the same table [id, title, content, short:boolean, user_id] and model
and the user chose to post short post and the site only will store the content and it will be under 120 char, to recognize it we will put the short:true, but how to customize the validations if it chose short to allow empty title and content under 120 char ..... etc
Simplest way to solve your problem is conditional validations. Your model should be like this:
class Post < ActiveRecord::Base
validates :title, presence: true, unless: :short?
validates :title, absence: true, if: :short?
validates :content, presence: true
validates :content, length: { maximum: 120 }, if: :short?
end
I'm not sure i understood all conditions in your example right, hope this code is enough to make what you want.
Also you may read details about conditional validations in Rails documentation.
Since you have a short boolean field on Post, you can simply add these helper methods
class Post < AR
# this method is automatically generated by rails
def short?
short
end
def long?
!short
end
end
And then add if: or unless: to your validations:
validates :content, length: { maximum: 120 }, if: :short?
validates :content, presence: true, if: :long?
I have a model "User" with attribute "Username". Can I use validations to prevent a User being created with the Username "home"?
class User < ActiveRecord::Base
validates :username, presence: true
end
You can use an exclusion validator:
class User < ActiveRecord::Base
USERNAME_BLACKLIST = ['home'].freeze
validates :username, presence: true, exclusion: { in: USERNAME_BLACKLIST }
end
Alternatively, you can always rely on a custom validation method, using validate instead of validates, for more complex types of validation that aren't easily expressed using built-in validators:
class User < ActiveRecord::Base
validates :username, presence: true
validate :username_not_on_restricted_list
protected
def username_not_on_restricted_list
errors.add(:username, :invalid) if username == 'home'
end
end
You could also write a custom validator if you intend to reuse this functionality across multiple models.
This are my files:
word.rb
class Word < ActiveRecord::Base
has_many :word_answers, dependent: :destroy
accepts_nested_attributes_for :word_answers, allow_destroy: true,
reject_if: lambda {|attribute| attribute[:word_id].blank?}
end
word_answer.rb
class WordAnswer < ActiveRecord::Base
belongs_to :word
validates :content, uniqueness: true, presence: true
end
Is there any method that I can valiidate validates :content, uniqueness: true, presence: true of word_answer.rb in word.rb?
Rails 4.
I tried validates_associated :word_answers but it doesn't work.
I want to achieve is
(1) If I submit Word, it will give an error if there is no WordAnswer.
(2) If I submit Word, it will give an error if there is a BLANK WordAnswer.
(3) If a validation is WordAnswer is wrong, It will give an error if I submit Word.
I don't think if we can add validates :content, uniqueness: true, presence: true to Word method but you can achieve validation for WordAnswer model in Word Model by adding a before_save & before_update filters.
I guess the validations in WordAnswer model will work fine as you want them to when you use nested attributes in the form and it will validate fine.
In other case kindly explain what you actually want to achieve ?
Try the following
validate :detail
def detail
word_answers.each do |word_answer|
if word_answer.content.blank?
errors.add(:"word_answer.content", "must not be blank")
word_answer.errors.add(:content, "must not be blank")
end
end
end
It should work if your models are associated correctly.
How can define custom validator that permits first name or last name to be null but not both
My Profile class:
class Profile < ActiveRecord::Base
belongs_to :user
validates :first_name, allow_nil: true
validates :last_name, allow_nil: true
validate :first_xor_last
def first_xor_last
if (first_name.nil? and last_name.nil?)
errors[:base] << ("Specify a first or a last.")
end
end
I tries create by self first_xor_last function but does not work.
I recieve this rspec test:
context "rq11" do
context "Validators:" do
it "does not allow a User without a username" do
expect(User.new(:username=> "")).to_not be_valid
end
it "does not allow a Profile with a null first and last name" do
profile = Profile.new(:first_name=>nil, :last_name=>nil, :gender=>"male")
expect(Profile.new(:first_name=>nil, :last_name=>nil, :gender=>"male")).to_not be_valid
end
it "does not allow a Profile with a gender other than male or female " do
expect(Profile.new(:first_name=>"first", :last_name=>"last", :gender=>"neutral")).to_not be_valid
end
it "does not allow a boy named Sue" do
expect(Profile.new(:first_name=>"Sue", :last_name=>"last", :gender=>"male")).to_not be_valid
end
end
end
I should pass it.
Thanks, Michael.
First of all, allow_nill is not a valid validator. You should be using presence or absence.
Unless you really need a custom message for both fields at the same time, there's no need to use a custom validator, simply do like this:
class Profile < ActiveRecord::Base
belongs_to :user
validates :first_name, :last_name, presence: true
end
If you want to allow either one, you can use conditional validation:
class Profile < ActiveRecord::Base
belongs_to :user
validates :first_name, presence: true, unless: "last_name.present?"
validates :last_name, presence: true, unless: "first_name.present?"
end
Instead of:
errors[:base] << ("Specify a first or a last.")
do
errors.add(:base, "Specify a first or a last.")
EDIT:
The error message you get is not caused by your custom validation, but by two other validations, which seems not needed, just get rid of those two lines:
validates :first_name, allow_nil: true
validates :last_name, allow_nil: true
class Profile < ActiveRecord::Base
belongs_to :user
validate :presence_of_first_or_last_name
def presence_of_first_or_last_name
if (first_name.blank? and last_name.blank?)
errors[:base] << ("Specify a first or a last.")
end
end
end
You can lose the two validates :first_name, allow_nil: true validations since they do absolutely nothing.
Instead of .nil? you might want to use the ActiveSupport method .blank? which checks not just for nil but also if the value is an empty string "" or consists of only whitespaces.
Also as David Newton pointed out XOR is eXclusive OR which would be first_name or last_name but not both. I try to name validators according to the general scheme of ActiveModel::Validations - a descriptive name which tells what kind of validation is performed.