Wednesday, February 17, 2016

Rails: How to use the comma as decimal separator



As you know, Rails use a dot as the decimal separator when displaying and processing text fields for float values.  In this post (at this moment I am using Rails 4.2) I will explain what I did in order to accept "," or "." as decimal separator since countries like Spain using a dot for the thousands delimiter and comma for the units.

At the beginning I was thinking that maybe I could use "alias_method_chain" for getting my purpose, modify the method type_cast that ActiveRecord uses for casting the values. After researching a little bit I found an interesting link about this and finally I decided to use the Module#prepend.
Here is the final code that I am using in my projects:
I created a file inside the folder config/initializers with the next code:


require 'active_record'

module CommaAsDecimalSeparator 

    def type_cast(value)
        separator = ","
        if type == :decimal && value.is_a?(String)
            value = value.gsub(separator, '.').to_d
        end
        super(value)
    end

end

ActiveRecord::Type::Value.send(:prepend, CommaAsDecimalSeparator)




Now that your model can deal with commas, you would like your text fields to show decimal values with commas. My solution for this is to define an additional form helper decimal_field which can be used in place of text_field to show an input box for decimal values. Copy the following as decimal_field.rb into the config/initializers folder of your Rails application:


ActionView::Helpers::FormBuilder.class_eval do
     def decimal_field(field, options = {})
        value = object.send(field).to_s
        separator = I18n::t('number.format.separator')
        precision = I18n::t('number.format.precision')
        precision = options[:precision].present? ? options[:precision] : precision
        value = ActiveSupport::NumberHelper.number_to_rounded(value, {separator: separator,     delimiter: "", precision:precision}) unless value.blank?
        options[:value] = value
        options[:class] = "#{options[:class]} number_field"
        text_field(field, options)
    end
end



If you need to show the numbers in a view without a form you can use the helper number_with_delimiter(value, locale: I18n.locale). 
If you take a look to this code, I am taking into account the number.format from the locales.  In this way, you should see the decimal separator in your forms and views depending on the locale.

You can see the code in my Github repository.


No comments:

Post a Comment