In one of my rails models I have this :only_integer validation:
validates :number, presence: true, numericality: { only_integer: true }
This validation also allows inputs like +82938434 with +-signs.
Which validation should I use to only allow inputs without + - only numbers?
The documentation for only_integer mentions this regex :
/\A[+-]?\d+\z/
It means you could just use:
validates :number, format: { with: /\A\d+\z/, message: "Integer only. No sign allowed." }
Rails 7 added :only_numeric option to numericality validator
validates :age, numericality: { only_numeric: true }
User.create(age: "30") # failure
User.create(age: 30) # success
Is there a way to validate email addresses such as 'myemail#mydomain.com' ?
So I should check if user has #mydomain.com extension on signup? How would regex code would look like?
This is what I am using currently, would like to add user.type = special if validation passes #mydomain.com if else user.type = normal
VALID_EMAIL_REGEX = /\A[\w+\-.]+#[a-z\d\-]+(\.[a-z\d\-]+)*\.[a-z]+\z/i
validates :email, presence: true, length: { maximum: 255 },
format: { with: VALID_EMAIL_REGEX },
uniqueness: { case_sensitive: false }
You can add model level validation on email attribute
validates :email, format: { with: /#mydomain\.com\z/i }
However the above regex doesn't put any restrictions on part of email before #
Edit:
You will have to add a before_create action which does check for #mydomain.com
before_create :set_user_type
def set_user_type
if /#mydomain\.com\z/i.match(email)
self.type = :special
else
self.type = :normal
end
end
I am writing a hacker news clone in rails to learn the framework and encountered a problem calling helper methods within a model:
class User < ActiveRecord::Base
has_secure_password validations: false
has_many :posts
validates :name,
presence: { message: username_error_message },
uniqueness: { case_sensitive: false, message: username_error_message },
length: { minimum: 2, maximum: 15, message: username_error_message }
validates :password,
presence: { message: password_error_message },
length: { minimum: 4, message: password_error_message }
private
def username_error_message
"Usernames can only contain letters, digits, dashes and underscores, and should be between 2 and 15 characters long. Please choose another."
end
def password_error_message
"Passwords should be a least 4 characters long. Please choose another."
end
end
I get the following error (Rails 4):
undefined local variable or method `username_error_message' for #<Class:XXX>
You can use constants for the repeated error messages and it will work.
class User < ActiveRecord::Base
has_secure_password validations: false
has_many :posts
USERNAME_ERROR_MESSAGE = "Usernames can only contain letters, digits, dashes and underscores, and should be between 2 and 15 characters long. Please choose another."
PASSWORD_ERROR_MESSAGE = "Passwords should be a least 4 characters long. Please choose another."
validates :name,
presence: { message: USERNAME_ERROR_MESSAGE },
uniqueness: { case_sensitive: false, message: USERNAME_ERROR_MESSAGE },
length: { minimum: 2, maximum: 15, message: USERNAME_ERROR_MESSAGE }
validates :password,
presence: { message: PASSWORD_ERROR_MESSAGE },
length: { minimum: 4, message: PASSWORD_ERROR_MESSAGE }
end
Also, there is a little problem: the error message will be repeated if more than one validation condition fails for every field. One solution is to write a custom validation method, as can be seen here: http://guides.rubyonrails.org/active_record_validations.html#custom-methods
Try using class methods instead:
validates :name,
presence: { message: Proc.new { username_error_message } },
uniqueness: { case_sensitive: false, message: Proc.new { username_error_message } },
length: { minimum: 2, maximum: 15, message: Proc.new { username_error_message } }
validates :password,
presence: { message: Proc.new { password_error_message } },
length: { minimum: 4, message: Proc.new { password_error_message } }
private
def self.username_error_message
"Usernames can only contain letters, digits, dashes and underscores, and should be between 2 and 15 characters long. Please choose another."
end
def self.password_error_message
"Passwords should be a least 4 characters long. Please choose another."
end
The fundamental problem is that you're accessing your methods before they are defined. This problem has nothing per se to do with whether they are private, constants, instance methods or class methods.
The methods are being referenced as your User class is being defined. The references exist within a hash constructor {} being passed as a parameter to the method call validates, which means it is getting evaluated at the time validates is called. It's not like you're passing a block to validates that gets evaluated at a later time.
If you move your definitions to before you reference them, it will address this fundamental problem, but it is also true that you are defining them as instance methods and referencing to them as class methods. You need to bring your mode of definition in line with your mode of access (e.g. by defining the methods as class methods).
(Note: There are a myriad of other options available to you for defining and referencing these strings beyond those noted in the other answers, including class variables, class local variables, etc. They vary primarily in terms where and how they can be accessed. You can even use instance variables and methods, although that would be odd in this case, requiring you to instantiate an object in order to reference them. The point is that Ruby is rich with possibilities and it's well worth investigating/understanding them when you have the time.)
Try this
class User < ActiveRecord::Base
has_secure_password validations: false
has_many :posts
validates :name,
presence: { message: self.username_error_message },
uniqueness: { case_sensitive: false, message: self.username_error_message },
length: { minimum: 2, maximum: 15, message: self.username_error_message }
validates :password,
presence: { message: self.password_error_message },
length: { minimum: 4, message: self.password_error_message }
def username_error_message
"Usernames can only contain letters, digits, dashes and underscores, and should be between 2 and 15 characters long. Please choose another."
end
def password_error_message
"Passwords should be a least 4 characters long. Please choose another."
end
end
private :username_error_message, :password_error_message
I just added some "self." before the methods call to give it a context of this instance.
I also changed the private declaration method
I'm building a simple JSON API using the rails-api gem.
models/user.rb:
class User < ActiveRecord::Base
has_secure_password
attr_accessible :email, :password, :password_confirmation
validates :email, presence: true, uniqueness: { case_sensitive: false }, format: { with: /^[A-Z0-9._%+-]+#[A-Z0-9.-]+\.[A-Z]{2,4}$/i }
validates :password, presence: { on: :create }, length: { minimum: 6 }
end
When I try to sign up without a password this is the JSON output I get:
{
"errors": {
"password_digest": [
"can't be blank"
],
"password": [
"can't be blank",
"is too short (minimum is 6 characters)"
]
}
}
Is it possible to hide the error message for password_digest? I'm returning the #user object with respond_with in the controller.
I've tried the following but no luck (it just duplicates the error "can't be blank"):
validates :password_digest, presence: false
#freemanoid: I tried your code, and it didn't work. But it gave me some hints. Thanks! This is what worked for me:
models/user.rb
after_validation { self.errors.messages.delete(:password_digest) }
You can manually delete this message in json handler in User model. Smth like:
class User < ActiveRecord::Base
def as_json(options = {})
self.errors.messages.delete('password_digest')
super(options)
end
end
Currently I have a function to check if the birthyear is correct:
validates :birth_year, presence: true,
format: {with: /(19|20)\d{2}/i }
I also have a function that checks if the date is correct:
validate :birth_year_format
private
def birth_year_format
errors.add(:birth_year, "should be a four-digit year") unless (1900..Date.today.year).include?(birth_year.to_i)
end
Is it possible to combine the bottom method into the validates at the top instead of the two validates I have now?
You should be able to do something like this:
validates :birth_year,
presence: true,
inclusion: { in: 1900..Date.today.year },
format: {
with: /(19|20)\d{2}/i,
message: "should be a four-digit year"
}
Take a look at: http://apidock.com/rails/ActiveModel/Validations/ClassMethods/validates
:birth_year, presence: true,
format: {
with: /(19|20)\d{2}/i
}
numericality: {
only_integer: true,
greater_than_or_equal_to: 1900,
less_than_or_equal_to: Date.today.year
}
regex
/\A(19|20)\d{2}\z/
will only only allow numbers between 1900 e 2099
\A - Start of string
\z - End of string