How use validation inclusion in rails - ruby-on-rails

class Stadium < ActiveRecord::Base
validates :name, :presence => true
validates :city, :presence => true
validates :contructiondate, :presence => true
validates :capacity, :presence => true
validates :image, :presence => true
validates :name, :uniqueness => true
validates :city, :uniqueness => true
validates :capacity, :numericality => { :only_integer => true, :greater_than_or_equal_to => 0 }
validates :image, :format => { :with => /^(http|https):\/\/[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,5}(:[0-9]{1,5})?(\/.*)?$/ix, :message => "Uniforme Invalido", :multiline => true }
validates :city, :inclusion => { :in => %w(Belo Horizonte Brasilia Curitiba Fortaleza Manaus Natal Recife Rio de Janeiro Salvador Sao Paulo), :message => "%{value} no esta permitido" }
validate :mydate_is_date?
def mydate_is_date?
errors.add(:contructiondate, 'must be a valid date') if !contructiondate.is_a?(Date)
end
end
I have a problem with inclusion, It works perfectly with words like Natal, Manaus, Salvador, but with words like "Sao Paulo", "Rio de Janeiro" does not work, How could I fix it?
Thanks

Try escaping the spaces with a backslash \.
Without escaping:
> %w(Belo Horizonte Brasilia Curitiba Fortaleza Manaus Natal Recife Rio de Janeiro Salvador Sao Paulo)
=> ["Belo",
"Horizonte",
"Brasilia",
"Curitiba",
"Fortaleza",
"Manaus",
"Natal",
"Recife",
"Rio",
"de",
"Janeiro",
"Salvador",
"Sao",
"Paulo"]
With escaping:
> %w(Belo Horizonte Brasilia Curitiba Fortaleza Manaus Natal Recife Rio\ de\ Janeiro Salvador Sao\ Paulo)
=> ["Belo",
"Horizonte",
"Brasilia",
"Curitiba",
"Fortaleza",
"Manaus",
"Natal",
"Recife",
"Rio de Janeiro",
"Salvador",
"Sao Paulo"]

Related

Validation Rails

Hi this is my User model
class User < ActiveRecord::Base
has_many :events
validates :cellphone, numericality:{ only_integer: true, message:"no es un numero"}, format: { with: /\d{11}/, message: "mal formato, deben ser 11 digitos, incluyendo codigo de area" }, :allow_blank => true
validates :phone, numericality:{ only_integer: true, message:"no es un numero"}, format: { with: /\d{11}/, message: "mal formato, deben ser 11 digitos, incluyendo codigo de area" }, :allow_blank => true
validates_numericality_of :cellphone, :on => :create, :message => "no es un numero", :allow_blank => true
validates_numericality_of :document, :on => :create, :message => "no es un numero", :allow_blank => true
validates :name, :presence => true
validates :lastname, :presence => true
validates :document, :presence => true, :uniqueness => true
validates :cellphone, :presence => true, :uniqueness => true
validates :phone, :presence => true, :uniqueness => true
validates_format_of :email,:with => Devise::email_regexp, :allow_blank => true
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
end
I want to valida, example :cellphone, numericality only if it pass :cellphone, :presence => true validation.
I already read all the post here in StackOverflow but i cant seem to understand what they are doing.
If some1 could help me with this step by step.
Thanks
:allow_blank => true
:presence => true
As #apneadiving mentioned in the comment, these two are 180 degree apart from each other. If one is true, the other one should be false. You can't have both at the same time.
What you are asking is that you want to check for the numericality if and only if the record is presence. For that, you can do the following:
validates :cellphone, numericality:{ ... }, format: { ... }, :allow_blank => true
In this way, since cellphone field can be blank, numericality will only be checked for it if it exists.
The other option is: You can pass a block to check if the field exists, and it does, check for numericality.
Here's how:
validate :cellphone, numbericality: { ... }, :if => lambda{ |object| object.cellphone.present? }

Validates allow_blank of multiple columns

I validate Realty objects depending on their active_state, so if it's pending, multiple fields are allowed to be blank.
with_options :if => Proc.new { |a| a.active_state == 'pending'} do |realty|
realty.validates :street, :length => {:in => 1..100}, :allow_blank => true
realty.validates :postalcode, :numericality => {:only_integer => true}, :length => {:in => 4..5}, :allow_blank => true
realty.validates :city, :length => {:in => 1..50}, :allow_blank => true
realty.validates :description, :length => {:maximum => 8000}, :allow_blank => true
realty.validates :leasing_costs, :numericality => {:only_integer => true}, :length => {:in => 1..9}, :allow_blank => true
end
with_options :if => Proc.new { |a| a.active_state != 'pending'} do |realty|
realty.validates :street, :length => {:in => 1..100}
realty.validates :postalcode, :numericality => {:only_integer => true}, :length => {:in => 4..5}
realty.validates :city, :length => {:in => 1..50}
realty.validates :description, :length => {:maximum => 8000}
realty.validates :leasing_costs, :numericality => {:only_integer => true}, :length => {:in => 1..9}
end
The only difference are those :allow_blank => true options.
I want to make this code more dry, so my attempt would be to use the normal validations block once:
validates :street, :length => {:in => 1..100}
validates :postalcode, :numericality => {:only_integer => true}, :length => {:in => 4..5}
validates :city, :length => {:in => 1..50}
validates :description, :length => {:maximum => 8000}
validates :leasing_costs, :numericality => {:only_integer => true}, :length => {:in => 1..9}
and then simply call some function on all of those fields in case the state is pending:
with_options :if => Proc.new { |a| a.active_state == 'pending'} do |realty|
realty.allow_blank_of :street, :postalcode, :city, :description, :leasing_costs
end
Similar to all those validates_uniqueness_of :x, :y, :z methods.
I couldn't find a function to fit my need. How can I approach this?
It would be nice if the :allow_blank option took a proc, but I don't think it does. However, you can achieve the same result using the :if option since :allow_blank is essentially a way of saying "if the attribute is blank then don't run this validation requirement". So try this:
with_options :if => Proc.new { |a| a.active_state == 'pending' ? a.present? : true } do |realty|
realty.validates :street, :length => {:in => 1..100}
realty.validates :postalcode, :numericality => {:only_integer => true}, :length => {:in => 4..5}
realty.validates :city, :length => {:in => 1..50}
realty.validates :description, :length => {:maximum => 8000}
realty.validates :leasing_costs, :numericality => {:only_integer => true}, :length => {:in => 1..9}
end
The proc in this case is saying... if the active_state is 'pending' and the attribute is present then execute this validation. But if the active_state is not 'pending' then the attribute isn't allowed to be blank so always run the validation. I hope I got that logic right based on your needs.
From pdobb's answer
However, you can achieve the same result using the :if
option since :allow_blank is essentially a way of saying "if the
attribute is blank then don't run this validation requirement".
Based on pdobbs explanation what allow_blank => true actually does, I could narrow the validations down to:
validates :street, :length => {:in => 1..100}, :unless => :pending?
validates :postalcode, :numericality => {:only_integer => true}, :length => {:in => 4..5}, :unless => :pending?
validates :city, :length => {:in => 1..50}, :unless => :pending?
validates :description, :length => {:maximum => 8000}, :unless => :pending?
validates :leasing_costs, :numericality => {:only_integer => true}, :length => {:in => 1..9}, :unless => :pending?
def pending?
active_state == "pending"
end
So I simply skip all of those validations if the active_state is "pending".
Allot more DRY :)
I haven't ran this, but I think this may work
before_commit :build_callback_validator, :on => :create
def build_callback_validator
validates :street, :length => {:in => 1..100}
validates :postalcode, :numericality => {:only_integer => true}, :length => {:in => 4..5}
validates :city, :length => {:in => 1..50}
validates :description, :length => {:maximum => 8000}
validates :leasing_costs, :numericality => {:only_integer => true}, :length => {:in => 1..9}
if self.active_state != 'pending'
self.allow_blank_of :street, :postalcode, :city, :description, :leasing_costs
end
end

Rails put validation in a module mixin?

Some validations are repetitive in my models:
validates :name, :length => { :minimum => 2 }, :presence => true, :uniqueness => true
validates :name_seo, :length => { :minimum => 2 }, :presence => true, :uniqueness => true
How would I put that in a mixin? I get this error if I just put 'em in a mixin
app/models/validations.rb:5: undefined method `validates' for Validations:Module (NoMethodError)
module Validations
extend ActiveSupport::Concern
included do
validates :name, :length => { :minimum => 2 }, :presence => true, :uniqueness => true
validates :name_seo, :length => { :minimum => 2 }, :presence => true, :uniqueness => true
end
end
The validates macro must be evaluated in the context of the includer, not of the module (like you probably were doing).
Your module should look something like this:
module CommonValidations
extend ActiveSupport::Concern
included do
validates :name, :length => { :minimum => 2 }, :presence => true, :uniqueness => true
validates :name_seo, :length => { :minimum => 2 }, :presence => true, :uniqueness => true
end
end
Then in your model:
class Post < ActiveRecord::Base
include CommonValidations
...
end
I'm using ActiveSupport::Concern here to make the code a little clearer.

Rails conditional validation of Zip Code for many countries

I need a model-level validation for Zip codes in USA and Canada. This code makes me feel bad:
zip_regex_usa = %r{\d{5}(-\d{4})?}
zip_regex_canada = %r{[ABCEGHJKLMNPRSTVXY]\d[A-Z] \d[A-Z]\d}
validates :shipping_zip, :presence => true, :format => { :with => zip_regex_usa }, :if => :shipping_to_usa?
validates :shipping_zip, :presence => true, :format => { :with => zip_regex_canada }, :if => :shipping_to_canada?
validates :billing_zip, :presence => true, :format => { :with => zip_regex_usa }, :if => :billing_to_usa?
validates :billing_zip, :presence => true, :format => { :with => zip_regex_canada }, :if => :billing_to_canada?
def shipping_to_usa?
shipping_country == 'US'
end
def billing_to_usa?
billing_country == 'US'
end
def shipping_to_canada?
shipping_country == 'CA'
end
def billing_to_canada?
billing_country == 'CA'
end
How to make this code more elegant, writing a single validation line for each field?
You can use gem validates_as_postal_code
It allows you to check zip codes like this:
class Person < ActiveRecord::Base
validates_as_postal_code :postal_code, :country => "CA", :allow_blank => true
end
and there're more options
EDIT:
There's also one nice gem: going_postal check it out!
I pulled some bits together into this gem: validates_zipcode.
It currently supports 259 countries zipcode formats and plays nice with Rails 3 & 4.
You can use it like this:
class Address < ActiveRecord::Base
validates_zipcode :zipcode
validates :zipcode, zipcode: true
validates :zipcode, zipcode: { country_code: :ru }
validates :zipcode, zipcode: { country_code_attribute: :my_zipcode }
end

Numericality Validations, Catching nil Values on Comparisons

I have an object that contains a number range and a description [min_val, max_val, name].
I need to validate that min_val < max_val. However, if one of them is blank I get a nil comparison error, instead, I'd like to tell the user that a number is required.
Also, how can I change the error message for numericality?
validates :min_val, :presence => true, :numericality => {:greater_than => 0, :less_than => :max_val}
validates :max_val, :presence => true, :numericality => {:greater_than => 0, :greater_than => :min_val}
validates :name, :presence => true, :if => Proc.new { |r| !r.min_val.nil? || !r.max_val.nil? }
You can use :message to specify a custom error message.
validates :max_val, :presence => true, :numericality => {:greater_than => 0, :message => " is an invalid number."}
validates :min_val, :presence => true, :numericality => {:greater_than => 0, :message => " is an invalid number."}
validate do |record|
record.errors.add_to_base("The min_val should be less than max_val") if min_val.to_i >= max_val.to_i
end
validates :name, :presence => true, :if => Proc.new { |r| !r.min_val.nil? || !r.max_val.nil? }

Resources