How to use Decimal with precision and scale? - ruby-on-rails

Using rails 3.0.3, I migrated a decimal column in my base using the following migration:
change_table :products do |t|
t.change :price, :decimal, :precision => 10, :scale => 2
# other code
end
The migration works ok, but I can still store value like 4.64564 where it should only store 4.65
On top of that, except in the migration file I created, schema.rb does not contain info about scale/precision.
Why does rails accept precision/scale migration to ignore it?

You should try with
change_column :products, :price, :decimal, :precision => 10, :scale => 2

I had the same problem, please look at that lib:
https://github.com/dmgr/dmg_decimal
With it you can use it in a model like that:
def price= val
self[:price] = Dmg::Decimal.real(val, scale: 2, precision: 10).to_d if val.present?
end

Related

Rails money column with no cents

I have a Rails 3.2 app where I'm asking for next year's budget request. The amount field is money - but, I don't want any decimals.
I will be using the data to display with number_to_currency.
Should I use:
add_column :mytable, :amount, :decimal, :precision => 12, :scale => 0
Or:
add_column :mytable, :amount, :integer
Thanks for the help!
Use
add_column :mytable, :amount, :integer
and number_to_currency(x/100) or number_to_currency(x/100, {options})
This way you avoid any rounding issues.

PostgreSQL: add_column "after" option usage in Rails migration

I'm trying to add a new column, 'latitude', to an existing Postgres table, after the 'location' column.
Using this syntax puts the column in the correct place:
add_column :table, :column, :decimal, :after => :existing_column
And using this syntax ensures that the field is the correct data type
add_column :table, :column, :decimal, {:precision => 10, :scale => 6}
But when I try and combine the two:
add_column :table, :column, :decimal, {:precision => 10, :scale => 6}, :after => :existing_column
I get "ArgumentError: wrong number of arguments (5 for 3..4)"
"Not to worry", I thought, "I'll just combine the arguements!":
add_column :table, :column, :decimal, {:precision => 10, :scale => 6, :after => :existing_column}
But then the columns appear at the end of the table. What am I doing wrong?
Thanks :)
Your last definition is correct. But the problem here isn't with Rails, but with PostgreSQL, which doesn't allow to add a column at specific position. Read more: How can I specify the position for a new column in PostgreSQL?

How do I create a rails migration to remove/change precision and scale on decimal?

I am trying to remove the precision and scale attributes from decimal (PostgreSQL NUMERIC) fields in my database?
The fields:
t.decimal "revenue_per_transaction", :precision => 8, :scale => 2
t.decimal "item_quantity", :precision => 8, :scale => 2
t.decimal "goal_conversion", :precision => 8, :scale => 2
t.decimal "goal_abandon", :precision => 8, :scale => 2
t.decimal "revenue", :precision => 8, :scale => 2
What do I need to add to my migration to change these to unbounded scale and precision, or to increase the scale? At the moment I'm hitting the scale limit and getting errors like:
ERROR: numeric field overflow
Here's the context: "PG::Error - numeric field overflow" on Heroku
format :
change_column(table_name, column_name, type, options): Changes the column to a different type using the same parameters as add_column.
First in you terminal:
rails g migration change_numeric_field_in_my_table
Then in your migration file:
class ChangeNumbericFieldInMyTable < ActiveRecord::Migration
def self.up
change_column :my_table, :revenue_per_transaction, :decimal, :precision => give whatever, :scale => give whatever
end
end
then
run rake db:migrate
Source : http://api.rubyonrails.org/classes/ActiveRecord/Migration.html
In your migration file change your field to :integer
and run
run rake db:migrate

Set a default value in a decimal column

How do you set a default value in a decimal column in Rails? I've tried both the following, using Rails 3 and Postgresql, but after each one the console tells me the default values are still nil. If I set the value from the console, there's no problem, but it doesn't seem to work in the migration.
#Attempt 1
add_column :providers, :commission, :decimal, :precision=>6,:scale=>4,:default=>0.1
and
#Attempt 2
add_column :providers, :commission, :decimal, :precision=>6,:scale=>4,:default=>BigDecimal("0.1")
Many thanks for your help!
It turns out I also need to set :null=>false
The following code worked:
add_column :providers, :commission, :decimal, :precision=>6,:scale=>4,:default=>0.1, :null => false

Rails: Cannot add :precision or :scale options with change_column in a migration?

This seems to have been asked before: rails decimal precision and scale
But when running a change_column migration for :precision or :scale they don't actually affect the schema or database, but db:migrate runs without errors.
My migration file looks like this:
class ChangePrecisionAndScaleOfPaybackPeriodInTags < ActiveRecord::Migration
def self.up
change_column :tags, :payback_period, :decimal, { :scale => 3, :precision => 10 }
end
def self.down
change_column :tags, :payback_period, :decimal
end
end
But my schema (and the data) remains as:
t.decimal "payback_period"
Anybody else have this issue?
Thanks,
Josh
Had a related (but not same) problem. I was just changing scale, so when changing the :scale you need the full line:
change_column :something, :weight, :decimal, :precision => 10, :scale => 2
omitting :decimal (which it already was) and :precision (which already was 10) will cause the migration to fail.
Does Not Work for SQLite3
For this simple test app that I'm running I have SQLite3 setup. Apparently, SQLite3 doesn't rely on column type declarations and is more dynamic, looking at the column's content instead - as was stumbled upon here:
Modify a Column's Type in sqlite3
I haven't tested it but I'm sure that's why the schema wasn't being changed, because change_column doesn't translate to anything in SQLite3.
Thanks for the replies guys.
Delete and regenerate db\schema.rb file.
rake db:schema:dump
A hack, but it should get you where you need to go:
class ChangePrecisionAndScaleOfPaybackPeriodInTags < ActiveRecord::Migration
def self.up
execute "ALTER TABLE tags CHANGE payback_period DECIMAL(3,10)"
end
def self.down
change_column :tags, :payback_period, :decimal
end
end

Resources