Rails converting string with float value to integer - ruby-on-rails

I have a model that has an attribute named value this is saved in the db as an integer.
I input the number in the view using a text_field, I am also performing a method on it :before_save that takes the value (something like 21.37) and using the money gem convert it to just cents.
However, it seems that before I can even perform the method that converts it from a float to an integer it is being converted to some kind of integer and the decimal is being lost.
I have tested this by outputting value in the method that runs before_save: and it round it to 21
Does anyone know why this might be happening, Im not performing any other changes to it.

I'm guessing you're doing something like Coupon.new(params) in your controller, and since Rails knows Coupon's value should be an integer, it helpfully calls to_i on params[:value] for you under the covers, which turns 21.37 into 21. Here's a rather inelegant but effective fix:
params[:value] ~= /.*\.(\d+)/
params[:value] = params[:value].to_f * (10**$1.length) if $1
Do that before you do Coupon.new(params).
Another option is to simply assume you don't care about anything after the 2nd decimal place (you're dealing with cents after all). Then you can simply do params[:value] = params[:value].to_f.round(2) * 100.
Also you should consider using number_field instead of text_field in your view so you can at least be sure you're getting a number. Something like number_field(:coupon, :value, step: 0.01) should ensure your users can enter decimals.

I agree with #kitkat seems like something that would happen in the model layer. You might be able to implement your conversion to cents logic in 'before_validation' or perhaps a custom setter for 'coupon'.

Related

How to strip commas from float input?

I have a field -
:Revenue
and it should accept values like 10,000.00, but if I input such value it stores 10 into database instead of 10000.00
What should I do to strip of commas before I save?
I've tried to find a few solutions online but wasn't able to implement them as I found them incomplete. If someone could help me I would really appreciate it.
**The problem now I am facing is that as soon as I enter the value rails converts string in to float value before it can run the gsub function, like if I enter 50,000.00 its converting into float 50.0 before calling the gsub, is there any way to over the to_f method which rails is calling on the string.
Removing commas is pretty simple:
value.gsub(/,/, '').to_f
Keep in mind that European formatting often uses comma as the decimal value separator so your results would be off by a factor of 100 if processing those sorts of numbers.
You can take a String#delete.
"10,000,000.00".delete(',').to_f
# => 10000000.0
I found the solution after looking at few places and combining few solutions, since I had to use gsub before the linking to model has to be done. so I created the method in my controller and called it before create and update action. and wrote the following code in the method
params[:record][:Revenue] = params[:record][:Revenue].gsub(/,/,"")

Converting string to float or decimal sometimes results in long precision

I have a string which I want to convert to a decimal.
eg.
tax_rate = "0.07"
tax_rate.to_d
In most cases it converts to 0.07 but sometimes it converts it to 0.07000000000000001. Why?
If it helps, when I look at the log of when I insert this value into the DB, this is the relevant part:
["tax_rate", #<BigDecimal:7f9b6221d7c0,'0.7000000000 000001E-1',18(45)>]
Hopefully that makes sense to someone.
Disclaimer:
I have a feeling someone is going to ask why I'm doing this.
I've created a simple settings model, where a user can update some global settings.
The Setting model has name, value and var_type columns.
The value column is a string. I use a helper method to retrieve the value in the appropriate format depending on the value of the var_type column.
I cannot explain why but there is a chance I can tell you how to avoid having this kind of trouble when dealing with numbers: use rationals.
Here is the documentation: http://ruby-doc.org/core-1.9.3/Rational.html
As stated, a rational will always give you the exact number you want and thus will avoid rounding errors.
From the doc:
10.times.inject(0){|t,| t + 0.1} #=> 0.9999999999999999
10.times.inject(0){|t,| t + Rational('0.1')} #=> (1/1)
Let me know if this solves your problem. : )

Control ActiveRecord creation argument type and characteristics

I have a model with column amount which is a decimal in the database. I'd like to ensure that only a BigDecimal with certain precision is ever given when this model is instantiated. I've written specs to test the scenario when a Float is provided, and then I have a before_create callback that raises an error if it's not a BigDecimal.
However, by the time the value gets to the before_create callback, Rails has already converted it to a BigDecimal. This is nice I supposed, and I can probably still check for precision, but since I don't know precisely how rails goes about converting, it would be nice to check for proper argument type and precision further up the chain.
Is there any way to do this?
From http://api.rubyonrails.org/classes/ActiveRecord/Base.html
Sometimes you want to be able to read the raw attribute data without having the column-determined typecast run its course first. That can be done by using the _before_type_cast accessors that all attributes have. For example, if your Account model has a balance attribute, you can call account.balance_before_type_cast or account.id_before_type_cast.
Try to override amount=
def amount=(val)
# checking / conversion goes here, new_val as result
self[:amount] = new_val # don't use self.amount = new_val to avoid endless loop
end

Rails 3. Why do my decimal value rows are values such as #<BigDecimal:5003750,'0.1E2',9(18)>>?

Why do my decimal value rows are values such as #> instead of just a regular decimal number?
I have a cost column and I get weird values. Is that ok? If so why?
That's just how Ruby prints out BigDecimal objects by default. Not sure why they chose such an ugly format, but hey - maybe some of the extra information can be useful.
Anyway, you should still be able to use them as you expect - it's just a bit of display weirdness. If you want to print a BigDecimal in a more normal format, call to_s on it first, or use puts, which calls to_s for you.
Hope that helps!
Rails automatically casts the "row" decimal value into the Ruby object that it most resembles. In this case, a BigDecimal.
To print it out in a nice way, you can use "to_s" eg:
puts my_decimal.to_s
=> "3000000000000000000.0"
which should print it out nicer than the ugly class-named version you are seeing now.

Setting default precision for all decimal numbers in rails

Is there a way to force Rails to output all decimal numbers with a certain precision? All of the decimal fields in my database are currency amounts, so I'd like decimal numbers to show by default with a precision of 2 (i.e. 2.40). I know I can use a helper function like "number_to_currency" to do this to each individual number, but that seems a bit tedious and unnecessary.
If you're concerned about overriding "to_s" on Float having possible unforeseen side-effects, your next best bet is probably to just create a new method, but still as a core extension. Something like this:
class Float
def c
sprintf('%.2f', self)
end
end
Then can't have any unforeseen consequences, and then anywhere you'd want to display the number with two decimal places, you'd just call .c. For example:
message = "The account balance is $#{amount.c}."
Not automatic, but not much extra typing, and no possible side-effects that overriding to_s could potentially cause.
Well if you don't mind monkey patching ruby, you can add a something like this (put it in an initializer at "/config/initializers/core_extensions.rb"):
class Float
def to_s
sprintf('%.2f', self)
end
end

Resources