Rails 3. How to explicitly round a number to two decimal places in the model?
You should try using the :decimal
type of database field, with the :scale
set to 2
To add a decimal column to a new table;
create_table :my_table do |t|
t.decimal :my_column, :scale => 2
end
To add a column to an existing table;
add_column :my_table, :my_column, :decimal, :scale => 2
It is wise to have precisions since some database does not have precision defaults. Such as postgresql:
add_column :my_table, my_column, precision: 30, scale: 2
Rails 3. How to display two decimal places in edit form?
You should use number_with_precision
helper. See doc.
Example:
number_with_precision(1.5, :precision => 2)
=> 1.50
Within you form helper:
<%= f.text_field :cost, :class => 'cost', :value => (number_with_precision(f.object.cost, :precision => 2) || 0) %>
BTW, if you really want to display some price, use number_to_currency
, same page for doc (In a form context, I'd keep number_with_precision
, you don't want to mess up with money symbols)
How to round an average to 2 decimal places in PostgreSQL?
PostgreSQL does not define round(double precision, integer)
. For reasons @Mike Sherrill 'Cat Recall' explains in the comments, the version of round that takes a precision is only available for numeric
.
regress=> SELECT round( float8 '3.1415927', 2 );
ERROR: function round(double precision, integer) does not exist
regress=> \df *round*
List of functions
Schema | Name | Result data type | Argument data types | Type
------------+--------+------------------+---------------------+--------
pg_catalog | dround | double precision | double precision | normal
pg_catalog | round | double precision | double precision | normal
pg_catalog | round | numeric | numeric | normal
pg_catalog | round | numeric | numeric, integer | normal
(4 rows)
regress=> SELECT round( CAST(float8 '3.1415927' as numeric), 2);
round
-------
3.14
(1 row)
(In the above, note that float8
is just a shorthand alias for double precision
. You can see that PostgreSQL is expanding it in the output).
You must cast the value to be rounded to numeric
to use the two-argument form of round
. Just append ::numeric
for the shorthand cast, like round(val::numeric,2)
.
If you're formatting for display to the user, don't use round
. Use to_char
(see: data type formatting functions in the manual), which lets you specify a format and gives you a text
result that isn't affected by whatever weirdness your client language might do with numeric
values. For example:
regress=> SELECT to_char(float8 '3.1415927', 'FM999999999.00');
to_char
---------------
3.14
(1 row)
to_char
will round numbers for you as part of formatting. The FM
prefix tells to_char
that you don't want any padding with leading spaces.
Rounding in Ruby (Rails)
You just need to pass a correct datatype into helper.
Instead of feeding it Integer
instance (995 / 100
gives you integer 9
), pass a Float
instance (995 / 100.to_f
, which gives you Float
9.95
):
number_with_precision (995 / 100.to_f, precision: 2) # or 995 / 100.0
#=> 9.95
What is the best method of handling currency/money?
You'll probably want to use a DECIMAL
type in your database. In your migration, do something like this:
# precision is the total number of digits
# scale is the number of digits to the right of the decimal point
add_column :items, :price, :decimal, :precision => 8, :scale => 2
In Rails, the :decimal
type is returned as BigDecimal
, which is great for price calculation.
If you insist on using integers, you will have to manually convert to and from BigDecimal
s everywhere, which will probably just become a pain.
As pointed out by mcl, to print the price, use:
number_to_currency(price, :unit => "€")
#=> €1,234.01
Decimal values are truncating with to_f
Can I know what will be the reason the to_f automatically reduce the limit of the decimal?
The reason is the to_f
methods are used to convert objects to Float
s, which are standard 64-bit double precision floating point numbers. The precision of these numbers is limited, therefore the precision of the original object must be automatically reduced during the conversion process in order to make it fit in a Float
. All extra precision is lost.
It looks like you are using the BigDecimal
class. The BigDecimal#to_f
method will convert the arbitrary precision floating point decimal object into a Float
. Naturally, information will be lost during this conversion should the big decimal be more precise than what Float
s allow. This conversion can actually overflow or underflow if limits are exceeded.
I was just thinking about some truncate with some limit
There is a truncate
method if you'd like explicit control over the precision of the result. No rounding of any kind will occur, there is a separate method for that.
BigDecimal#truncate
Deletes the entire fractional part of the number, leaving only an integer.
BigDecimal('3.14159').truncate #=> 3
BigDecimal#truncate(n)
Keeps
n
digits of precision, deletes the rest.BigDecimal('3.14159').truncate(3) #=> 3.141
How do I configure Rails to output decimals to the correct precision in form fields?
I ended up writing a plugin to do this: currency_text_field.
You can define your formats (arguments to number_with_precision
) in config/initializers/currency_text_field_initializer.rb
.
Then you use f.currency_text_field :rate
in your form, with an optional :format
argument to use a named format in the initializer. Otherwise it uses the format[:default]
from the initializer.
Same approach as setting the value
explicitly, but does it all behind the scenes and has named sets of options to number_with_precision
.
Related Topics
How to Upload a Local File to a Carrierwave Model
Where Is the Best Place to Add Methods to the Integer Class in Rails
Class Methods in Ruby on Rails 3 - I'm Totally Lost!
Issues with Has_Many :Through, Cache, Touch and Counter_Cache
How to Use Ruby CSV Converters
Generate a 'Link_To' to the Controller Action 'Edit', Dynamically
Using Ruby 2.0 on Amazon Opsworks
Rails 5, "Nil Is Not a Valid Asset Source"
How to Jump from Do to End of a Ruby Block Using Vim
How to Pass Named Arguments to a Rake Task
Rspec Load Time Incredible Long on Os X
How Do Get a Random Datetime Rounded to Beginning of Hour in Rails
How to Log Specific Request Details to Rails Server Logs
Package Configuration for Libffi Is Not Found in MACos While Installing Travis-Cli