I have a model Order with the price attribute.
There are few Order records in the database without a price attribute(nil value) which was imported from the old database. There are less than 20 invalid records like this.
Now the price attribute is mandatory.
I need to add a presence validation of the price and preserve the old records.
I can't set the nil values to zero or some random values.
I have some crazy ideas about the conditional validation on the basis of the timestamp or even a list of "permitted" ids.
Something like this:
PERMITTED_IDS = [4, 8, 15, 16, 23, 42]
validates :price, presence: true, if: -> { |order| PERMITTED_IDS.exclude?(order.id) }
Is there any nice and convenient way for that?
Use on: :create
The following will only validate when the model is created.
validates :price, presence: true, on: :create
However, can't you just use allow_nil: true:
validates :price, presence: true, allow_nil: true
I would add a boolean imported attribute to the Order class, setting it to true for old records upon import. This allows you to skip validations for these records easily:
validates :price, presence: true, unless: :imported?
UPDATE
Stefan: Are old/imported records editable?
freemanoid: #Stefan yes, but I can't set the price to zero for them.
The above solution is not an option because it would allow a nil price for all old records.
You could use a custom validation that requires a price for new records, but allows nil when updating records if the price was already nil. Something like:
validates :price, presence: true,
on: :create
validates :price, presence: true,
on: :update,
unless: Proc.new { |o| p.price_was.nil? }
Related
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?
In my rails application, I have bank_details table with columns - account_number, ifsc_code, bank_name and branch_code(Only for India). But I don't know how to validates this columns before save it to database.Plese help me in this.
I will appreciate your help.
Thanks in advance.
In your model, you need to add a validates: your_column.
For example if you want to make sure that account number is present before you save to the database, you need to add validates: account_number, presence: true
There are both pre-built helpers, so you can validate by presence, name, etc, but you can also use a custom method to validate those.
Check out RailsGuides for all the details
There are so many validation that you can apply on your columns, here is a list of possible validation. you can pick as your requirement.
Validation for data should be present
validates :account_number, :ifsc_code, :branch_code, :bank_name, presence: true
data should be positive numbers only
validates :account_number, :branch_code, :numericality => { :greater_than_or_equal_to => 0 }
set length of record
validates :ifsc_code, length: { is: 11 }
validates that the attribute's value is unique right before the object gets saved
validates :account_number, uniqueness: true
In your model you can have something like this:
validates: branch_code
which is a standard validation, making sure its present
Or you can do more validation using regex
validates :bank_name, format: { with: /\A[a-zA-Z]+\z/,
message: "only allows letters" }
Here are some examples of validation:
validates :bank_name, length: { minimum: 2 }
validates :bank_name, length: { maximum: 500 }
validates :bank_name, length: { in: 6..20 }
validates :bank_name, length: { is: 6 }
Or use some advance techniques like so:
validates :bank_name, presence: true, if: "branch_code.nil?"
TransferWise provides an API you can use to validate IFSC codes and Indian account numbers:
IFSC code
https://api.transferwise.com/v1/validators/ifsc-code?ifscCode=YESB0236041
Account number
https://api.transferwise.com/v1/validators/indian-account-number?accountNumber=678911234567891
Documentation here.
In my validations, I have already used once a conditional presence like
validates :contact_name, presence: true
validates :contact_adress,
presence: true, if: :contact_name?,
Now I would like to do the contrary: condition the obligation of an attribute to the absence of the other attribute. If I let A empty, then B has to be filled and vice versa.
Would that work?
validates :attribute_A, presence true, if:attribute_B!
validates :attribute_B, presence true, if:attribute_A!
You can use unless or .blank?
validates :attribute_A, presence true, if: :attribute_B.blank?
OR
validates :attribute_A, presence true, unless: :attribute_B
From documentation of validates
There is also a list of options that could be used along with validators:
...
:unless - Specifies a method, proc or string to call to determine if the validation should not occur (e.g. unless: :skip_validation, or unless: Proc.new { |user| user.signup_step <= 2 }). The method, proc or string should return or evaluate to a true or false value.
However, it may be more clear to use if: with the help of Object#present? or Object#blank?.
In Ruby on Rails, I can't seem to find a validation model method to check for data-type.
I was hoping for something like
validates :name, datatype: :integer
but there is nothing on http://guides.rubyonrails.org/testing.html
If such a test not required? Is it because the database engine (mysql or whatever) itself would reject information with a wrong data-type?
It seems you are new to Rails there are already predefined validations in rails Ref Active Record Validations in Rails
validates :name, numericality: true
or
validates :name, numericality: { only_integer: true }
You can do something like
validates :your_field, :numericality => { :greater_than_or_equal_to => 0 }
please check the link
Validation for non-negative integers and decimal values
There is a validation for this in Rails
validates_numericality_of :value, :only_integer: true
In my form validation of my model, I'm trying to say that if the params of a column called :virtual is false, then the :location field should validate for :presence => true.
My current code is:
validates :location, if :virtual => false, :presence => true
But that's giving me a syntax error. What's the correct way to format this?
Something like:
attr_accessor :virtual # sets up a "virtual attribute" called "virtual" to which you can read/write a value
# this step isn't necessary if you already have an attribute on the model called "virtual"
validates :location, :presence => true, :unless => :virtual?
The use of virtual? should check whether the attribute virtual is true or false. Using unless means this validation is only performed if virtual is false (or is a value that is considered false).
More detail on virtual attributes and validation: Rails: Using form fields that are unassociated with a model in validations
validates :location, presence: true, if: Proc.new { |p| p.virtual == false }