Rails Validate no White Space in User Name - ruby-on-rails

I want to validate that a user name has no white/blank spaces for my Users. Is there a built in validation that does this? Or what is the best way to do this. Seems like it would be a pretty common requirement.

I would try format validator:
validates :username, format: { with: /\A[a-zA-Z0-9]+\Z/ }
as most of the time when you don't want whitespaces in username you also don't want other characters.
Or when you really only need to check for whitespace, use without instead:
validates :username, format: { without: /\s/ }
Full documentation: http://api.rubyonrails.org/classes/ActiveModel/Validations/HelperMethods.html#method-i-validates_format_of (validates ... format: {} is the same as validates_format_of ...)

I believe you will have to create a custom validator:
validate :check_empty_space
def check_empty_space
if self.attribute.match(/\s+/)
errors.add(:attribute, "No empty spaces please :(")
end
end

In your User model add validation. validates :username, format: { without: /\s/ } will remove white/blank spaces for your Users. You can even add a message alerting the user that their username contains whitespace.
class User < ActiveRecord::Base
validates :username, format: { without: /\s/, message: "must contain no spaces" }
end

You can use before_validation callback to strip whitespace
class User
before_validation :strip_blanks
protected
def strip_blanks
self.username = self.username.strip
end
end

MurifoX's answer is better, but regarding it being a common requirement, i think this is more often used:
validates :presence
class User < ActiveRecord::Base
validates :name, presence: true
end

Related

Validate last letters of input field in Rails

How would I validate the last letters of a link which is posted into my model?
Example:
[dropbox.com/dajnkqjknw7/file.mp3]
[dropbox.com/dajnkqjknw7/file.ogg]
[dropbox.com/dajnkqjknw7/file.wav]
I just want to check/validate if the last 3 (or 4) letters end on .mp3, .ogg or .wav, how would I use that within my model, use a Regex in combination with validates?
Current beat.rb model:
class Beat < ApplicationRecord
validates :bpm, format: { with: /\A\d+\z/ }, length: { maximum: 3 }
validates :link, presence: true REGEX IN HERE?
end
You can use something like this
validates :link, presence: true, format: { with: /.(mp3|ogv|wav)\z/}
where you have a dot . and after one of the valid extensions (mp3|ogv|wav), just at the end of the line \z

How to handle dependant validations on Rails?

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.

Field becomes blank when before_validation is used in Rails Admin

I am using the Rails Admin gem. When I add a new activity type and create it again with the same name, it validates that name is already taken. But whenever I try to edit one it will give you an error: "name can't be blank"
For example, I created Swimming, and I tried to add a new activity type which is swimming/SWIMMING etc. To avoid this I used the before_validation callback, to make the first letter a capital, then check the uniqueness of name.
Yes, it's working but whenever I try to edit the name field it will become blank after I submit it.
NOTE: I also tried to use validates :name, presence: true, :uniqueness => {:case_sensitive => true} only without the before_validation but it didn't work.
Activity Type
class ActivityType < ApplicationRecord
before_destroy :ensure_has_no_activity_type
before_validation :capitalize_first_letter_name
has_many :activities
validates :name, presence: true,:uniqueness => {:case_sensitive => true}, length: { maximum: 20 },format: Utilities::RegexValidations.alphanumeric_underscore
validates :description, presence: false
private
def ensure_has_no_activity_type
if activities.present?
errors.add(:base, 'Cannot delete activity type that has activity')
throw(:abort)
end
end
def capitalize_first_letter_name
# Capitalize the first letter and the rest will be small letter
self.name = self.name.capitalize!
end
end
Question: Why whenever I tried to edit and try to submit it, does the name field become blank? What is the reason for this?
The problem arises from capitalize_first_letter_name. "".capitalize! will return nil. If you change it to "".capitalize that will return blank string as expected.
Moreover, capitalize! will return nil if no changes were made. See https://ruby-doc.org/core-2.2.0/String.html#method-i-capitalize-21.

How to customize the validations in rails if the request comes from specific controller?

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?

validate_presence_of *before* before_validation

Let's say I have a before_validation that checks to make sure the first letter of a name is "y":
before_validation :check_name_first_letter_is_y
But I want to make sure that the first name is also present:
validates :name, presence: true
But this will run the before_validation BEFORE validating if there's a first name present, right? How would I check if a name is present before running my before_validate?
I could try:
after_validation :check_name_first_letter_is_y
But will that stop the save method if I return false? Or is it too late because it's already been validated?
It might be easier to do this in one call as follows (if I didn't misread your question!):
validates :name, presence: ->(rec) { rec.name.initial == 'Y' }
Update:
Introduce a new ActiveModel::EachValidator that checks the first character in the name to be y and use the presence validator as you normally would, but ensure presence validator comes before the name validator so that presence check is done before checking first letter.
# app/validators/NameValidator.rb
class NameValidator < ActiveModel::EachValidator
def validate_each(record, attribute, value)
if value.initial != 'y'
record.errors[attribute] << (options[:message] || "First letter in name must be `y`")
end
end
end
Then in your model, use the following two validations:
validates :name, presence: true
valdiates :name, name: true
Please refer: http://api.rubyonrails.org/classes/ActiveModel/Validator.html.
Also would suggest you to come up with a "Railsy" name for NameValidator class!
You can simply add a second format validation:
validates :name, presence: true, format: { with: /^y/, allow_blank: true }

Resources