Conditional validation if another validation is valid [duplicate] - ruby-on-rails

This question already has answers here:
Rails validate uniqueness only if conditional
(3 answers)
Closed 6 years ago.
I have the following three validations in a model in my rails app:
validates_presence_of :reset_code, message: 'Please enter your reset code'
validates_length_of :reset_code, is: 4, message: 'Your reset code should be 4 digits'
validates_format_of :reset_code, with: /\A[0-9]{4}\z/, message: 'Please enter a valid reset code'
I only want to fire the second and third validations if the first is valid (as there is no point in telling the user the reset code isn't the correct length or format if they haven't entered one at all).
So something along the lines of:
validates_length_of :reset_code, is: 4, message: 'Your reset code should be 4 digits', :if => :reset_code.present?

You should use new the new validation syntax, and provide a simple if: condition:
validates :reset_code, length: { is: 4 },
message: 'Your reset code should be 4 digits',
if: -> { reset_code.present? }
validates :reset_code, format: { with: /\A[0-9]{4}\z/ },
message: 'Please enter a valid reset code',
if: -> { reset_code.present? }

Related

How to not allow let users create passwords with space using ruby on rails?

I'm beginner to Ruby On Rails and I tried to do registration (name,email,password, confirming password) on my site (localhost) with restrictions like password can't be blank, password is at least 6 symbols long and password can't be like only spaces (" "). Then I want to let users edit these attributes but if they change it I want to make them write name and mail again but not password ( these 2 first are necessary, if they dont want to change it they leave them up, password is not necessarry so i want to make it blank, thats why in this code i use allow_blank: true)
# app/models/user.rb
.
.
.
has_secure_password
validates :password, presence: true, length: { minimum: 6 }, allow_blank: true
If I do it, users can register with spaces (" ") and it even allows them to break the rule with min 6 symbol ( users can do password like this: " " and I don't want this) so that's the problem.
But when I don't use allow_blank:true, when users want to edit their attributes they need to write again password ( I want to make them write only name and email but password can be left blank and it won't be changed then).
What should I do ?
Use a regular expression, through the without option of validates_format_of.
validates :password, presence: true,
length: { minimum: 6 },
format: { without: /\s/, message: "spaces not allowed" }
Okey I found the answer: instead of allow_blank: true I should have used allow_nil: true.

Having trouble testing Rails Model validations with shoulda-matchers and factory-girl-rails?

Model:
validates :email,
uniqueness: {
message: "has been taken."
},
presence: {
message: "cannot be blank."
},
length: {
minimum: 3,
message: "is too short, must be a minimum of 3 characters.",
allow_blank: true
},
format: {
with: /\A[A-Z0-9_\.&%\+\-']+#(?:[A-Z0-9\-]+\.)+(?:[A-Z]{2,13})\z/i,
message: "is invalid.",
if: Proc.new { |u| u.email && u.email.length >= 3 }
}
RSpec:
before(:each) do
#user = FactoryGirl.build(:user)
end
it { should validate_length_of(:email).is_at_least(3) }
Error:
Failure/Error: should validate_length_of(:email).is_at_least(3)
Expected errors to include "is too short (minimum is 3 characters)" when email is set to "xx",
got errors:
* "is too short (minimum is 4 characters)" (attribute: password, value: nil)
* "is too short, must be a minimum of 3 characters." (attribute: email, value: "xx")
* "is not included in the list" (attribute: state, value: "passive")
Factory:
factory :user, class: User do
email FFaker::Internet.email
password FFaker::Internet.password
username FFaker::Internet.user_name
end
I am using factory_girl_rails with shoulda_matchers. Every time I try to validate my email, I keep getting an error like above. It says the email value is "xx", but the length of the factory email is greater than that. How can I write an rspec that will pass?
Shoulda-matchers tests validations by testing the messages in the errors object.
The valdation matchers only work with the rails default error messages unless you specify otherwise:
it { should validate_length_of(:email).with_message("is too short, must be a minimum of 3 characters.") }
The with_message method is detailed in this comment.
You are understanding the error (and it's cause) wrong. The error says that it expects "is too short (minimum is 3 characters)" but in the errors it can't find that string (rspec finds "is too short, must be a minimum of 3 characters." which is what you defined on your validation).
When you use shoulda matchers and say
it { should validate_length_of(:email).is_at_least(3) }
I'm guessing it creates a test with an email shorter than 3 and checks if it fails, that's why it's ignoring your factory, internally should matcher is setting a fixed length string just to make that test pass.
When you see the errors in user, that test should actually work since the error is actually there, only the string is different. So, you have two options: remove the custom message when length is minimum: 3; or tell the matcher what message you are expecting:
it { should validate_length_of(:email).is_at_least(3).with_message("is too short, must be a minimum of 3 characters.") }

Formatting model.errors.full_messages [duplicate]

This question already has answers here:
Fully custom validation error message with Rails
(18 answers)
Closed 5 years ago.
How do you format columns names in error messages?
class Person
validates_presence_of :name, :address, :email
validates_length_of :name, in: 5..30
end
person = Person.create(address: '123 First St.')
person.errors.full_messages
# => ["Name is too short (minimum is 5 characters)",
"Name can't be blank", "Email can't be blank"]
For example, when there is an error instead I want it to print
Full name can't be blank. (instead of 'Name')
How do I do this since in the model/database its stored as :name.
Is there someway I can link a string to :name?
You can specify a custom message.
validates_length_of :name, in: 5..30, message: 'Full name must be between 5 and 30 characters'
http://guides.rubyonrails.org/active_record_validations.html#message
You can also just translate the attribute
en:
activerecord:
attributes:
person:
name: "Full name"
By adding that to the config/locales/en.yml file
http://guides.rubyonrails.org/i18n.html#translations-for-active-record-models

Cannot iterate over unique elements

I have an array of errors as below:
n.errors.full_messages
# => ["Password can't be blank", "Password can't be blank", "Password is too short (minimum is 3 characters)"]
I would like to iterate over the unique elements of this array and display them on the screen.
Validation model
class Member < ActiveRecord::Base
has_one :profile
before_save { self.username = username.downcase }
has_secure_password
validates :password, presence: true, length: { minimum: 3 }
end
n.errors.full_messages.uniq do |a|
puts a
end
uniq is not working, and "Password can't be blank" appears twice in my array. Any ideas?
Password can't be blank
Password can't be blank
Password is too short (minimum is 3 characters)
# => ["Password can't be blank"]
Edit: This doesn't actually answer the question, use the answer from #BroiSatse if google brought you here.
The reason you are getting that message twice is because of has_secure_password:
http://api.rubyonrails.org/classes/ActiveModel/SecurePassword/ClassMethods.html#method-i-has_secure_password
The first bullet point appears to add validation that makes the password required.
In your model you also add
validates :password, presence: true, length: { minimum: 3 }
The presence: true part of this adds the same validation. Remove this so its:
validates :password, length: { minimum: 3 }
This should fix the problem.
uniqe with a block uses value of the block to compare the elements. What you want is:
n.errors.full_messages.uniq.each do |m|
Anyhow, I think you're approaching the problem from the wrong angle - your problem is not how to avoid displaying duplicate messages, but how this duplication happened.
You could just do a string comparison.
Have the array that is problematic to you. Go over it and save the elements one by one to a new array.
Now when the first one is added to the new array, check that the elements allready in the array don't match the new element to be added. E.g: "My string".eql? "My sting"
There might be of course a more clever way to do this in Ruby. But that would be the idea when doing it in other languages manually.

rails 4 validates presence and length on the same parameter

Is it a good idea to having validates like this:
validates :serialnumber, presence: true, length: {7..20}, format: {with: /\d{7,20/}
As you see it generates three errors if I don't type serialnumber.
I would like to see only one error.
If I type nothing, I would like to see 'serial number is required' only.
If I type 123ABC I would like to see 'wrong length' only
And if I type 123-ABC-123 I would like to see 'wrong format' only
How to do it?
Regards
You could split it into 2 validators, check if this would work
validates :serialnumber, presence: true
validates :serialnumber, length: {7..20}, format: { with: /\d{7,20}/ }, allow_blank: true
As I understand then you want to see only one error message at a time. If that's the case then custom validation method might help. For ex.
validate :serial_number_validation_one_by_one
private
def serial_number_validation_one_by_one
if !self.serial_number.present?
errors.add(:serial_number, "must be present!")
elsif self.serial_number.length < 7 || self.serial_number.length > 20
errors.add(:serial_number, "must have length between 7 and 20!")
elsif self.serial_number.match(<your regex pattern here>)
errors.add(:serial_number, "must be properly formatted!")
end
end
Keep in mind that custom validation methods are called by validate not by validates.

Resources