I have a pieces model in my rails app, and each piece has a decimal called :price. I want to validate that this price is two decimal places, greater than 0, and is less than a million dollars. I have looked at numerous sources on Stack overflow, and whenever I type a decimal for these validations, for example, 4.99 , the price becomes 4.990000000000000213162820728030055761. This has happened for all the validations I have looked up. Is this because I need to specify my precision for the decimal in my database? How can I fix this?
My current validation:
validates :price, :presence => true, :format => { :with => /\A(\$)?(\d+)(\.|,)?\d{0,2}?\z/ }
Thanks guys!
I dont know which database you are using but you can define precision in your migration like this,
add_column :pieces, :price, :decimal, precision: 8, scale: 2
It will give you a total of 8 digits, with 2 after the decimal point.
About the validation,
If you want that the :price should always have two decimal place (i.e: 4.99) you can try this,
validates :price, presence: true, format: { with: /\A\d+(?:\.\d{2})?\z/ }, numericality: { greater_than: 0, less_than: 1000000 }
If you want that the :price should have at most two decimal or less (i.e: 4, 4.9, 4.99) you can try this,
validates :price, presence: true, format: { with: /\A\d+(?:\.\d{0,2})?\z/ }, numericality: { greater_than: 0, less_than: 1000000 }
Or if you dont want to validate precision and just want to round up the precision before you save it to the database you can use round_with_precision.
You should set it on the database. For example in a migration:
add_column :products, :price, :decimal, precision: 5, scale: 2
Precision is the number of digits in a number. Scale is the number of
digits to the right of the decimal point in a number. For example, the
number 123.45 has a precision of 5 and a scale of 2. In SQL Server,
the default maximum precision of numeric and decimal data types is 38.
https://msdn.microsoft.com/en-us/library/ms190476.aspx
If you're seeing that your values are having additional numbers tacked on, what's likely happening is that your column is set as a floating-point type. If you're working with dollar values do not use floating-point numbers. M. Karim's answer is fine otherwise.
Related
I am using simple_form_for for my form template which is not storing decimal numbers into my database table. When I submit the form, it throws away the precision.
Here is what I have:
my schema.rb
create_table "coupons", force: true do |t|
t.decimal "amount", precision: 10, scale: 0
end
new.html.slim
.panel-body.padded
= simple_form_for #coupon, :url => admin_coupons_path do |f|
.form-group
= f.input :amount, as: :string, input_html: { value: number_with_precision(f.object.amount, precision: 8) }, required: true
database image
Am confused as to what else I can do to make that work. Any help will be appreciated.
The missing piece to the puzzle is the precision of the decimal within the database. By default, the code above will create a decimal field in MySQL with 10 digits, all of which are to the left of the decimal point. In other words, saving 15.37 to your model will show 15.37 within the app, but when you save it, it’ll become 15 both in the data store and when you reload it.
The way around this is to specify the precision and the scale in your migration. So correct it with a followup migration:
change_column :table_name_in_plural, :column_name, :decimal, :precision => 10, :scale => 2
In this case, we’ve set the total number of digits (the precision) to 10, with 2 decimal places (the scale.) Note that you can pick your sizes as per your needs – MySQL docs give some guidelines to the storage requirements for different combinations.
Also, when picking your precision and scale, be aware that the scale (max decimal places) can’t be greater than the precisions (total digits.) That might seem obvious when written here, but without those translations in parentheses, it’s easy to get lazy and make the two values the same, which would leave you with a number that has to be less than 1.0, since all the space will be allocated to the right of the decimal place.
Reference: Here
I want to write a validation for ensuring the minimum and maximum value of an integer column.
I know I can use the helpers of the numericality validation as follow:
validates :column_name, numericality: {
only_integer: true,
greater_than: 0,
less_than: 100
}
My question however, is that if I want to give a database level validation for this, how can I go about it
PS: I'm using Postgres.
You can use a domain; something like:
CREATE DOMAIN something AS INT CHECK (VALUE BETWEEN 1 AND 99)
and then declare the table column as the type something.
How to write validation in rails so as to allow the below possible values for price
100 or $100 or 100.00 or $100.00
I have declared price field as Float in my model
My current code looks like :
validates :price,numericality: true
which is not allowing values like 100 to get saved.
You can add the format option to your validates method.
validates :price, numericality: true,
:format => { :with => /^\d{1,6}(\.\d{0,2})?$/
This will allow values of up to $999999.99 with an optional decimal place (if the decimal is present, no more than 2 digits must follow.)
But like others already mentioned - it's not the best option to save these values into the database.
I can recommend you the RubyMoney gem for working with currencies.
In Rails 4, how can you add a model validation for a maximum value on an integer column?
For example, I want to add a validation to the column "age", to have a maximum value of 100.
There are many questions with answers for Rails 3 and earlier. The docs do not mention any way of checking integer values.
Take a look at the numericality validators.
In your case, something like
validates :age, numericality: { less_than_or_equal_to: 100, only_integer: true }
How do I specify a limit on an integer size in a Rails 4 migration? (My database is PostgreSQL.)
I have fields for phone_number, which should be 8 digits long. If I specify :limit => 8, then that is byte size rather than the length of the numbers.
Is there a way to do this?
You're going about this all wrong. A phone number is not a number at all, a phone number is a string that contains (mostly) digit characters. You don't do anything numeric – such as arithmetic – with phone numbers so they're not numbers, they're strings.
Make your phone_number column a string of length eight:
t.string :phone_number, limit: 8
and clean it up and validate the format in your model:
before_validation :clean_up_phone_number
validates :phone_number,
format: { with: /\A\d{8}\z/ },
length: { maximum: 8 },
allow_nil: true
def clean_up_phone_number
# Do whatever you want or need to strip out spaces, hyphens, etc. in here
end
Or better with PostgreSQL, don't worry about the size in the database at all and use t.string :phone_number. The size limit just adds pointless overhead and using a plain varchar rather than a varchar(8) makes it easier to allow for different phone number formats (area codes, extensions, international numbers, ...) later.
Or you can do it with mv-core gem (https://github.com/vprokopchuk256/mv-core) right in a migration in this way (syntax is almost identical to AciveModel::Validations one):
def change
update_table :users do |table|
t.string :phone_number,
validates: { length: 8,
format: /\A\d{8}\z/,
allow_blank: true,
allow_nil: true }
end
end
And then bubble up that validation to your model:
class User < ActiveRecord::Base
enforce_migration_validations
end
By default your validation will be defined as CHECK constraint for PostgreSQL. But you can change that to trigger constraint, for ex.
See details in the documentation.