Limit integer size in Rails migration - ruby-on-rails

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.

Related

Price Validation for Rails 4

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.

Rails currency validation

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.

rails string limit does not prevent too long strings from being inserted in db

I wrote a migration for a Rails 4 project to add a character limit to a string column. I used the following code:
change_column :articles, :name, :string, :limit => 40
The migration with rake db:migrate went fine, resulting in the following line in db/schema.rb:
t.string "name", limit: 40, null: false
But when I enter a string with more than 40 characters in the form (generated by a scaffold), there isn't any error message and the too long string is inserted in the database.
What am I doing wrong ?
Depending on the RDBMS you're using, the field limit won't be validated at the database level. To ensure you're getting great error messages when your constraints are being violated, use ActiveRecord validations.
Try:
validates_length_of :name, maximum: 40
In your model class.

How to specify the size of an integer in the migration script

We have two columns which require to be declared as t.integer size(1) and size(2).
i.e. a max size of 1 (i.e upto 9) and max size of 2 (i.e upto 99). How should I declare this in my migration script.
Do you mean that the value in that column should be restricted to the range 1-99?
Having created an integer column you could add ActiveRecord validation to the model:
validates_numericality_of :field_name, :in => 1..99
You should be able to set a :limit on your migration record. Check the documentation here -- http://api.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/TableDefinition.html#method-i-column
Ex:
add_column :my_tbl, :myint, :integer, :limit => 9
This will set a column length -- in other words, it will only allow integers up to 9 digits long.
If you want to restrict the data input for this column, you'll need to do validations in your model. Have a look at http://guides.rubyonrails.org/active_record_validations_callbacks.html#length

Is using column limit options worth it?

Is there any point to specifying a limit option on string in migrations...
class CreateAccounts < ActiveRecord::Migration
def self.up
create_table :accounts do |t|
t.string :name, :limit => 64
end
end
end
Should this be applied to all strings in the DB? What's the significance?
Strings are usually 255 characters length but not all databases treat the string field in the same way. For instance, PostgreSQL can create string column of different sizes.
There are at least 2 very good reasons to specify the value of the string field:
cross-database compatibility
database performance
If you need a string column to store the country code that is 2 chr length, why you want the database to reserve additional 253 characters for... nothing?
Also note you should always validate the length of the field value in your model.
If you try to create a record with a name that exceeds your maximum length:
SQLIte3 will silently trim the value
MySQL will silently trim the value
PostgreSQL will raise an exception
So, always validates_length_of your attribute.
The first thing that comes to mind - when you have millions of accounts, that limit will actually affect the size of your DB a lot.

Resources