Reputation: 475
I have a before_save in my model to covert comma to dot that was working fine. But somehow it broke. Example: user input 1,22 and the value get stored without decimal like 1.00
I need to store the value as a decimal, even if the user type comma instead of dot. Because where I live comma is the delimiter.
before_save { self.price.to_s.gsub(',', '.').to_f }
I also tried change to this:
before_save :convert_comma
private
def convert_comma
self.price = self.price.to_s.gsub(',', '.').to_f
end
I tested the comma replacement above in the console and it works, but with before_save the data get stored rounded like 1.00
Rails console:
2.3.4 :001 > p = Ticket.new("driver_id"=>"3", "origin_id"=>"AP", "origin_city_id"=>"Amapá", "destination_id"=>"GO", "destination_city_id"=>"Abadia de Goiás", "start_date"=>"29/12/2017 19:28", "return_date"=>"29/12/2017 19:28", "annotation"=>"1", "rate"=>"1", "price"=>"1233,22", "status"=>"Aberto")
=> # <Ticket id: nil, start_date: "2017-12-29 19:28:00", return_date: "2017-12-29 19:28:00", rate: #<BigDecimal:68e22a8,'0.1E1',9(18)>, price: #<BigDecimal:68e21e0,'0.1233E4',9(18)>, annotation: "1", status: "Aberto", department_id: nil, origin_id: "AP", destination_id: "GO", driver_id: 3, created_at: nil, updated_at: nil, origin_city_id: "Amapá", destination_city_id: "Abadia de Goiás", manager: nil, day: nil, user_id: nil, deleted_at: nil>
2.3.4 :002 > p.save
(0.2ms) SAVEPOINT active_record_1
SQL (0.6ms) INSERT INTO "tickets" ("start_date", "return_date", "rate", "price", "annotation", "status", "origin_id", "destination_id", "driver_id", "created_at", "updated_at", "origin_city_id", "destination_city_id") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) [["start_date", "2017-12-29 19:28:00"], ["return_date", "2017-12-29 19:28:00"], ["rate", 1.0], ["price", 1233.0], ["annotation", "1"], ["status", "Aberto"], ["origin_id", "AP"], ["destination_id", "GO"], ["driver_id", 3], ["created_at", "2017-12-29 21:55:22.119679"], ["updated_at", "2017-12-29 21:55:22.119679"], ["origin_city_id", "Amapá"], ["destination_city_id", "Abadia de Goiás"]]
(0.1ms) RELEASE SAVEPOINT active_record_1
=> true
This is really strange. Any idea of what could be happening? Thanks!
Upvotes: 1
Views: 470
Reputation: 157
The problem here is that active record is coercing the string into a BigDecimal as soon as you write the attribute in the initializer (Ticket.new). Notice that, in your console output, your instance holds a BigDecimal for the price attribute with the value '0.1233E4', rather than '0.123322e4'. This means that when your :convert_comma method runs:
self.price.to_s #=> '1233.0'
One possible solution is to override your attribute writer in your model, writing the following instance method in your ticket.rb file:
def price=(new_price)
super(BigDecimal.new(new_price.to_s.gsub(',', '.')))
end
Upvotes: 2
Reputation: 475
I have found a workaround for that here https://stackoverflow.com/a/11585385/2188585 and modified to this:
before_save :pricecomma
def pricecomma
price
end
def pricecomma=(price)
self.price = price.gsub(',', '.') unless price.blank?
end
Changed my form to:
<%= f.text_field :pricecomma %>
Still don't get what is going on. I tried the same code without this virtual attribute and don't get the replacement. But this way works fine.
Upvotes: 1
Reputation: 436
I'm not sure to have understood your problem, I think the error is trying to convert ',' in '.' on a number type. You can change the way it's print using NumberHelper methods in your views, for example:
<%= number_with_delimiter(@product.price, delimiter: ",", separator: ".") %>
delimiter is for thousands and separator for decimals, in case of currency maybe its better number_to_currency method
<%= number_to_currency(@product.price, delimiter: ".", separator: ",", unit: "€") %>
EDIT a link to ActionView::Helpers::NumberHelper references
EDIT AGAIN Since you need to allow user to digits comma as delimiter, I suggest you to look for or write by yourself a 18n file to put in your config/locales folder, for Brazil it should be br.yml. At the voice "number:" you can set currency and format, and set delimiter and separator. To set this file by default, on your config/application.rb add this line:
module YourApp
class Application < Rails::Application
# Settings in config/environments/* take precedence over those specified here.
# Application configuration should go into files in config/initializers
# -- all .rb files in that directory are automatically loaded.
config.i18n.default_locale = :br
end
end
then your number_field need to have correct step option:
<%= f.number_field :price, step: 0.01 %>
That should works and also allows you to translate your system messages :)
Upvotes: 1