AmountField

Rails gem/plugin that accepts (amount) values in german or us format like 1.234,56 or 1,234.56“.

Installation Rails 3

Via Bundler:

# path/to/railsapp/Gemfile
gem 'amount_field_rails3', :require => 'amount_field'

$ bundle install

As Gem:

$ gem sources -a http://gemcutter.org/ (you only have to do this once)
$ sudo gem install amount_field_rails3

As plugin:

$ rails plugin install git://github.com/thomasbaustert/amount_field.git

Installation Rails 2.x

As Gem:

$ gem sources -a http://gemcutter.org/ (you only have to do this once)
$ sudo gem install amount_field

As plugin:

$ script/plugin install git://github.com/thomasbaustert/amount_field.git, :branch => 'rails23'

Example

First: Use the helper amount_field instead of the text_field helper:

<%= form_for(@product) do |f| %>
  <%= f.amount_field :price %>
   ...    
<% end %>

<%= form_for(@product) do |f| %>
  <%= amount_field :product, :price %>
   ...    
<% end %>

The helper amount_field_tag is provided too, but you have to handle the validation on your own:

<%= form_tag(:action => "create", {}) do -%> 
  <%= amount_field_tag :price, 1234.56 %>
...

Second: Use the validation macro validates_amount_format_of in your model:

class Product < ActiveRecord::Base
  validates_amount_format_of :price
  validates_numericality_of :price
  validates_presence_of :price
  ...
end

Note! Make sure you always call validates_amount_format_of before every other validation macro for the same attribute (e.g. before validates_numericality_of and validates_presence_of for price).

Configuration

The following configuration is supported:

Format Configuration

Definition:

Delimiter = thousand separator (e.g. '.' in 1.234.567)
Separator = separator of value and decimal places (e.g. ',' in 12,56)
Precision = number of decimal places

The default format configuration is defined via Rails I18n and accessable through the key number.amount_field.format from the file amount_field/locale/(en|de).yml.

Example:

I18n.locale = :de
I18n.t('number.amount_field.format') # => { :precision => 2, :delimiter => '.', :separator => ',' }

Currently only the locale de anden are supported.

If you want to define the default configuration independent from I18n, you can set it as follows:

AmountField::ActiveRecord::Validations.configuration = 
  { :precision => 1, :delimiter => ',', :separator => '.' }

An explicitly defined format will overwrite the default configuration for that attribute:

validates_amount_format_of :price, :separator => '.', :delimiter => ',', :precision => 1
# VALID: "1,234.5" (1234.5)

Standard Rails options like :allow_blank, or :allow_nil are supported:

validates_amount_format_of :price, :allow_blank => true

CSS class and prefix

By default the input field contains the CSS class amount_field so you can define a CSS layout for every amount field like:

input.amount_field {
  text-align:right;
}

The method prefix and the CSS class can be changed as follows:

AmountField::Configuration.prefix = "my_prefix"
AmountField::Configuration.css_class = "my_class"

That will create the html:

<input name="product[my_prefix_price]" class=" my_class"...

and the appropriate method my_prefix_price=(value).

Input

By default delimiter, separator and precision are optional, so “1.234,00”, “1234,00” and “1234” are all valid for the german locale (de) at the same time.

In all other cases the validation will fail and add an error message to the original attribute (e.g. price). (See Error Messages)

Output

The helper amount_field uses the Rails helper number_with_precision internally and passes the plugin format configuration as an argument. A value like 1234.56 is therefore displayed as “1.234,56” for the locale de and “1,234.56” for the locale en.

You can explicitly set the format configuration with the option format:

amount_field(:price, :format => { :separator => '', ... })

And it is possible to pass the value explicitly:

amount_field(:price, :value => ...)

Error Messages

By default the german and english messages are taken from the file amount_field/locale/(en|de).yml through the key activerecord.errors.messages.invalid_amount_format.

You can define your own by adding your Yaml file to the load path like:

# environment.rb
I18n.load_path << "#{RAILS_ROOT}/locale/en.yml"

# "#{RAILS_ROOT}/locale/en.yml"
de:
  errors:
    messages:
      invalid_amount_format: "'%{value}' ist ein ungültiges Format (%{format_example})"

The placeholder %{value} is substituted with the given value (e.g. “1.x”) and %{format_example} with a valid example of the currently accepted format (e.g. ‘d.ddd,dd’).

How does it work?

Basically the helper amount_field defines a input field like so:

<input name="product[amount_field_price]" class=" amount_field"...

The validation macro validates_amount_format_of defines a special setter method amount_field_price=(value) that accept the value. After successfully format validation the original parameter is converted to a ruby value (e.g. “1.234,56” to 1234.56) and assigned to the original attribute price. Following validation macros work on the converted value. That’s why it is currently important to call validates_amount_format_of before every other macro.

Running Tests

You need a database gem_amount_field_test to run all tests. See test_helper.rb for details.

Credits

  • Michael Schiller (for feedback and ideas)

  • Clements Teichmann (consider option ‘name’ and ‘id’)

Contact

For comments and question feel free to contact me: [email protected]

If you are using the plugin, consider recommending me at workingwithrails.com: workingwithrails.com/person/6131-thomas-baustert

Copyright © 2009 [Thomas Baustert], released under the MIT license