amount_field_rails3 3.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +6 -0
- data/Gemfile +3 -0
- data/History.txt +58 -0
- data/MIT-LICENSE +20 -0
- data/Manifest +21 -0
- data/README.rdoc +196 -0
- data/Rakefile +16 -0
- data/amount_field.gemspec +25 -0
- data/init.rb +4 -0
- data/install.rb +1 -0
- data/lib/amount_field.rb +23 -0
- data/lib/amount_field/configuration.rb +20 -0
- data/lib/amount_field/form_helper.rb +68 -0
- data/lib/amount_field/form_tag_helper.rb +22 -0
- data/lib/amount_field/validations.rb +129 -0
- data/lib/amount_field/version.rb +3 -0
- data/locale/de.yml +10 -0
- data/locale/en.yml +11 -0
- data/test/form_helper_test.rb +264 -0
- data/test/form_tag_helper_test.rb +47 -0
- data/test/models/test_product.rb +7 -0
- data/test/test_helper.rb +63 -0
- data/test/validations_test.rb +389 -0
- data/uninstall.rb +1 -0
- metadata +104 -0
data/Gemfile
ADDED
data/History.txt
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
== 3.0.0 2011-03-29
|
2
|
+
|
3
|
+
* Migrate to Rails3
|
4
|
+
|
5
|
+
== 1.4.2 2010-05-11
|
6
|
+
|
7
|
+
* Don't set default dom Id for FormBuilder amount_field, use Rails default or use given one.
|
8
|
+
|
9
|
+
== 1.4.1 2010-04-23
|
10
|
+
|
11
|
+
* Method amount_field considers given option "name" and "id":
|
12
|
+
<% form_for(@manager) do |f| %>
|
13
|
+
<%= f.amount_field :salary, :name => :salary, :id => "salary_id" %>
|
14
|
+
...
|
15
|
+
=>
|
16
|
+
<input name="salary" id="salary_id" ... /> instead of
|
17
|
+
<input name="manager[amount_field_value]" id="manager_salary"... />
|
18
|
+
* fix: display invalid value in current format (e.g. in german format: "-0,1" or "12,34"
|
19
|
+
and not "-0.1" and "12.34").
|
20
|
+
|
21
|
+
== 1.4.0 2009-10-06
|
22
|
+
|
23
|
+
* fix: negative values like '-1,00', '-1,0', '-1,' or '-1' are considered valid
|
24
|
+
* add test for '-value' and '+value'
|
25
|
+
* more test values and easier usage in tests
|
26
|
+
|
27
|
+
== 1.3.0 2009-09-06
|
28
|
+
|
29
|
+
* fix: helper amount_field_tag no works as expected (accepting name and value instead of object and method)
|
30
|
+
* add helper amount_field for ActionView::Base and amount_field for ActionView::Helpers::FormBuilder
|
31
|
+
* use an instance variable internally for the original assigned value and remove class AssignedValue
|
32
|
+
|
33
|
+
== 1.2.0 2009-09-04
|
34
|
+
|
35
|
+
* fix: an invalid value is still invalid after multiple calls to valid?
|
36
|
+
|
37
|
+
== 1.1.0 2009-08-31
|
38
|
+
|
39
|
+
* Fix "undefined method `to_f' for [...]:Array" by supported attribute of type float
|
40
|
+
(even if it is not a good idea to use float for amount because of rounding errors)
|
41
|
+
* Default configuration uses I18n.t('number.amount_field.format') from the plugin file
|
42
|
+
amount_field/locale/(en|de).yml. This means the default configuration depends on I18n.locale
|
43
|
+
and is not necessarily the german format by default anymore.
|
44
|
+
* The delimiter, separator and precision are now optional, so "1.234,00", "1234,00" and "1234" are
|
45
|
+
all valid at the same time.
|
46
|
+
|
47
|
+
== 1.0.2 2009-08-07
|
48
|
+
|
49
|
+
* fix typo and update readme concerning installation
|
50
|
+
|
51
|
+
== 1.0.1 2009-08-07
|
52
|
+
|
53
|
+
* Bugfix: a given format option for one amount field does not manipulate the default configuration
|
54
|
+
|
55
|
+
== 1.0.0 2009-07-28
|
56
|
+
|
57
|
+
* Initial release
|
58
|
+
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2009 [Thomas Baustert]
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Manifest
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
History.txt
|
2
|
+
MIT-LICENSE
|
3
|
+
Manifest
|
4
|
+
README.rdoc
|
5
|
+
Rakefile
|
6
|
+
amount_field.gemspec
|
7
|
+
init.rb
|
8
|
+
install.rb
|
9
|
+
lib/amount_field.rb
|
10
|
+
lib/amount_field/configuration.rb
|
11
|
+
lib/amount_field/form_helper.rb
|
12
|
+
lib/amount_field/form_tag_helper.rb
|
13
|
+
lib/amount_field/validations.rb
|
14
|
+
locale/de.yml
|
15
|
+
locale/en.yml
|
16
|
+
test/form_helper_test.rb
|
17
|
+
test/form_tag_helper_test.rb
|
18
|
+
test/models/test_product.rb
|
19
|
+
test/test_helper.rb
|
20
|
+
test/validations_test.rb
|
21
|
+
uninstall.rb
|
data/README.rdoc
ADDED
@@ -0,0 +1,196 @@
|
|
1
|
+
= AmountField
|
2
|
+
|
3
|
+
Rails gem/plugin that accepts (amount) values in german or us format like 1.234,56 or 1,234.56".
|
4
|
+
|
5
|
+
== Installation Rails 3
|
6
|
+
|
7
|
+
Via Bundler:
|
8
|
+
|
9
|
+
# path/to/railsapp/Gemfile
|
10
|
+
gem 'amount_field_rails3', :require => 'amount_field'
|
11
|
+
|
12
|
+
$ bundle install
|
13
|
+
|
14
|
+
As Gem:
|
15
|
+
|
16
|
+
$ gem sources -a http://gemcutter.org/ (you only have to do this once)
|
17
|
+
$ sudo gem install amount_field_rails3
|
18
|
+
|
19
|
+
As plugin:
|
20
|
+
|
21
|
+
$ rails plugin install git://github.com/thomasbaustert/amount_field.git
|
22
|
+
|
23
|
+
== Installation Rails 2.x
|
24
|
+
|
25
|
+
As Gem:
|
26
|
+
|
27
|
+
$ gem sources -a http://gemcutter.org/ (you only have to do this once)
|
28
|
+
$ sudo gem install amount_field
|
29
|
+
|
30
|
+
As plugin:
|
31
|
+
|
32
|
+
$ script/plugin install git://github.com/thomasbaustert/amount_field.git, :branch => 'rails23'
|
33
|
+
|
34
|
+
== Example
|
35
|
+
|
36
|
+
First: Use the helper <tt>amount_field</tt> instead of the <tt>text_field</tt> helper:
|
37
|
+
|
38
|
+
<%= form_for(@product) do |f| %>
|
39
|
+
<%= f.amount_field :price %>
|
40
|
+
...
|
41
|
+
<% end %>
|
42
|
+
|
43
|
+
<%= form_for(@product) do |f| %>
|
44
|
+
<%= amount_field :product, :price %>
|
45
|
+
...
|
46
|
+
<% end %>
|
47
|
+
|
48
|
+
The helper <tt>amount_field_tag</tt> is provided too, but you have to handle the validation on
|
49
|
+
your own:
|
50
|
+
|
51
|
+
<%= form_tag(:action => "create", {}) do -%>
|
52
|
+
<%= amount_field_tag :price, 1234.56 %>
|
53
|
+
...
|
54
|
+
|
55
|
+
Second: Use the validation macro <tt>validates_amount_format_of</tt> in your model:
|
56
|
+
|
57
|
+
class Product < ActiveRecord::Base
|
58
|
+
validates_amount_format_of :price
|
59
|
+
validates_numericality_of :price
|
60
|
+
validates_presence_of :price
|
61
|
+
...
|
62
|
+
end
|
63
|
+
|
64
|
+
Note! Make sure you always call <tt>validates_amount_format_of</tt> *before* every
|
65
|
+
other validation macro for the same attribute (e.g. before <tt>validates_numericality_of</tt>
|
66
|
+
and <tt>validates_presence_of</tt> for <tt>price</tt>).
|
67
|
+
|
68
|
+
== Configuration
|
69
|
+
|
70
|
+
The following configuration is supported:
|
71
|
+
|
72
|
+
=== Format Configuration
|
73
|
+
|
74
|
+
Definition:
|
75
|
+
|
76
|
+
Delimiter = thousand separator (e.g. '.' in 1.234.567)
|
77
|
+
Separator = separator of value and decimal places (e.g. ',' in 12,56)
|
78
|
+
Precision = number of decimal places
|
79
|
+
|
80
|
+
The default format configuration is defined via Rails I18n and accessable through the key
|
81
|
+
<tt>number.amount_field.format</tt> from the file <tt>amount_field/locale/(en|de).yml</tt>.
|
82
|
+
|
83
|
+
Example:
|
84
|
+
|
85
|
+
I18n.locale = :de
|
86
|
+
I18n.t('number.amount_field.format') # => { :precision => 2, :delimiter => '.', :separator => ',' }
|
87
|
+
|
88
|
+
Currently only the locale <tt>de</tt> and<tt>en</tt> are supported.
|
89
|
+
|
90
|
+
If you want to define the default configuration independent from I18n, you can set it as follows:
|
91
|
+
|
92
|
+
AmountField::ActiveRecord::Validations.configuration =
|
93
|
+
{ :precision => 1, :delimiter => ',', :separator => '.' }
|
94
|
+
|
95
|
+
An explicitly defined format will overwrite the default configuration for that attribute:
|
96
|
+
|
97
|
+
validates_amount_format_of :price, :separator => '.', :delimiter => ',', :precision => 1
|
98
|
+
# VALID: "1,234.5" (1234.5)
|
99
|
+
|
100
|
+
Standard Rails options like <tt>:allow_blank</tt>, or <tt>:allow_nil</tt> are supported:
|
101
|
+
|
102
|
+
validates_amount_format_of :price, :allow_blank => true
|
103
|
+
|
104
|
+
=== CSS class and prefix
|
105
|
+
|
106
|
+
By default the input field contains the CSS class <tt>amount_field</tt> so you can define
|
107
|
+
a CSS layout for every amount field like:
|
108
|
+
|
109
|
+
input.amount_field {
|
110
|
+
text-align:right;
|
111
|
+
}
|
112
|
+
|
113
|
+
The method prefix and the CSS class can be changed as follows:
|
114
|
+
|
115
|
+
AmountField::Configuration.prefix = "my_prefix"
|
116
|
+
AmountField::Configuration.css_class = "my_class"
|
117
|
+
|
118
|
+
That will create the html:
|
119
|
+
|
120
|
+
<input name="product[my_prefix_price]" class=" my_class"...
|
121
|
+
|
122
|
+
and the appropriate method <tt>my_prefix_price=(value)</tt>.
|
123
|
+
|
124
|
+
== Input
|
125
|
+
|
126
|
+
By default delimiter, separator and precision are optional, so "1.234,00", "1234,00" and "1234"
|
127
|
+
are all valid for the german locale (de) at the same time.
|
128
|
+
|
129
|
+
In all other cases the validation will fail and add an error message to the original
|
130
|
+
attribute (e.g. <tt>price</tt>). (See Error Messages)
|
131
|
+
|
132
|
+
== Output
|
133
|
+
|
134
|
+
The helper <tt>amount_field</tt> uses the Rails helper <tt>number_with_precision</tt> internally
|
135
|
+
and passes the plugin format configuration as an argument. A value like 1234.56 is therefore
|
136
|
+
displayed as "1.234,56" for the locale <tt>de</tt> and "1,234.56" for the locale <tt>en</tt>.
|
137
|
+
|
138
|
+
You can explicitly set the format configuration with the option <tt>format</tt>:
|
139
|
+
|
140
|
+
amount_field(:price, :format => { :separator => '', ... })
|
141
|
+
|
142
|
+
And it is possible to pass the value explicitly:
|
143
|
+
|
144
|
+
amount_field(:price, :value => ...)
|
145
|
+
|
146
|
+
== Error Messages
|
147
|
+
|
148
|
+
By default the german and english messages are taken from the file
|
149
|
+
<tt>amount_field/locale/(en|de).yml</tt> through the key
|
150
|
+
<tt>activerecord.errors.messages.invalid_amount_format</tt>.
|
151
|
+
|
152
|
+
You can define your own by adding your Yaml file to the load path like:
|
153
|
+
|
154
|
+
# environment.rb
|
155
|
+
I18n.load_path << "#{RAILS_ROOT}/locale/en.yml"
|
156
|
+
|
157
|
+
# "#{RAILS_ROOT}/locale/en.yml"
|
158
|
+
de:
|
159
|
+
errors:
|
160
|
+
messages:
|
161
|
+
invalid_amount_format: "'%{value}' ist ein ungültiges Format (%{format_example})"
|
162
|
+
|
163
|
+
The placeholder <tt>%{value}</tt> is substituted with the given value (e.g. "1.x") and
|
164
|
+
<tt>%{format_example}</tt> with a valid example of the currently accepted format (e.g. 'd.ddd,dd').
|
165
|
+
|
166
|
+
== How does it work?
|
167
|
+
|
168
|
+
Basically the helper <tt>amount_field</tt> defines a input field like so:
|
169
|
+
|
170
|
+
<input name="product[amount_field_price]" class=" amount_field"...
|
171
|
+
|
172
|
+
The validation macro <tt>validates_amount_format_of</tt> defines a special setter method
|
173
|
+
<tt>amount_field_price=(value)</tt> that accept the value. After successfully format
|
174
|
+
validation the original parameter is converted to a ruby value (e.g. "1.234,56" to 1234.56)
|
175
|
+
and assigned to the original attribute <tt>price</tt>. Following validation macros work on
|
176
|
+
the converted value. That's why it is currently important to call
|
177
|
+
<tt>validates_amount_format_of</tt> before every other macro.
|
178
|
+
|
179
|
+
== Running Tests
|
180
|
+
|
181
|
+
You need a database <tt>gem_amount_field_test</tt> to run all tests.
|
182
|
+
See test_helper.rb for details.
|
183
|
+
|
184
|
+
== Credits
|
185
|
+
|
186
|
+
* Michael Schiller (for feedback and ideas)
|
187
|
+
* Clements Teichmann (consider option 'name' and 'id')
|
188
|
+
|
189
|
+
== Contact
|
190
|
+
|
191
|
+
For comments and question feel free to contact me: business@thomasbaustert.de
|
192
|
+
|
193
|
+
If you are using the plugin, consider recommending me at workingwithrails.com:
|
194
|
+
http://workingwithrails.com/person/6131-thomas-baustert
|
195
|
+
|
196
|
+
Copyright (c) 2009 [Thomas Baustert], released under the MIT license
|
data/Rakefile
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'bundler'
|
2
|
+
Bundler::GemHelper.install_tasks
|
3
|
+
|
4
|
+
require 'rake'
|
5
|
+
require 'rake/testtask'
|
6
|
+
require 'rake/rdoctask'
|
7
|
+
|
8
|
+
desc 'Default: run tests'
|
9
|
+
task :default => :test
|
10
|
+
|
11
|
+
Rake::TestTask.new(:test) do |t|
|
12
|
+
t.libs << 'lib'
|
13
|
+
t.libs << 'test'
|
14
|
+
t.pattern = 'test/**/*_test.rb'
|
15
|
+
t.verbose = true
|
16
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "amount_field/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "amount_field_rails3"
|
7
|
+
s.version = AmountField::VERSION
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.authors = ["Thomas Baustert"]
|
10
|
+
s.email = ["business@thomasbaustert.de"]
|
11
|
+
s.homepage = "http://github.com/thomasbaustert/amount_field"
|
12
|
+
s.summary = %q{Rails gem/plugin that accepts (amount) values in german or us format like 1.234,56 or 1,234.56}
|
13
|
+
s.description = %q{Rails gem/plugin that accepts (amount) values in german or us format like 1.234,56 or 1,234.56}
|
14
|
+
|
15
|
+
s.rubyforge_project = "amount_field_rails3"
|
16
|
+
|
17
|
+
s.add_development_dependency "mysql2"
|
18
|
+
|
19
|
+
s.files = `git ls-files`.split("\n")
|
20
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
21
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
22
|
+
s.require_paths = ["lib"]
|
23
|
+
end
|
24
|
+
|
25
|
+
|
data/init.rb
ADDED
data/install.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
# Install hook code here
|
data/lib/amount_field.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
# AmountField
|
2
|
+
|
3
|
+
require 'amount_field/configuration'
|
4
|
+
require 'amount_field/validations'
|
5
|
+
require 'amount_field/form_helper'
|
6
|
+
require 'amount_field/form_tag_helper'
|
7
|
+
|
8
|
+
ActiveRecord::Base.class_eval do
|
9
|
+
include AmountField::ActiveRecord::Validations
|
10
|
+
end
|
11
|
+
|
12
|
+
ActionView::Helpers::FormBuilder.class_eval do
|
13
|
+
include AmountField::Helpers::FormBuilder
|
14
|
+
end
|
15
|
+
|
16
|
+
ActionView::Base.class_eval do
|
17
|
+
include AmountField::Helpers::FormHelper
|
18
|
+
include AmountField::Helpers::FormTagHelper
|
19
|
+
end
|
20
|
+
|
21
|
+
I18n.load_path << "#{File.dirname(__FILE__)}/../locale/en.yml"
|
22
|
+
I18n.load_path << "#{File.dirname(__FILE__)}/../locale/de.yml"
|
23
|
+
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module AmountField
|
2
|
+
class Configuration
|
3
|
+
|
4
|
+
##
|
5
|
+
# Defines the prefix for the special setter method name:
|
6
|
+
# def #{prefix}_xxx=(value) ...
|
7
|
+
# end
|
8
|
+
#
|
9
|
+
@@prefix = 'amount_field'
|
10
|
+
mattr_accessor :prefix
|
11
|
+
|
12
|
+
##
|
13
|
+
# Defines the CSS class name for the <tt>amount_field</tt> helper.
|
14
|
+
# <input ...class="... #{css_class}" .../>
|
15
|
+
#
|
16
|
+
@@css_class = 'amount_field'
|
17
|
+
mattr_accessor :css_class
|
18
|
+
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
module AmountField #:nodoc:
|
2
|
+
module Helpers #:nodoc:
|
3
|
+
|
4
|
+
#TODO/2010-04-23/tb remove redundant code
|
5
|
+
# using @template.amount_field(object, method, options) !?
|
6
|
+
|
7
|
+
module FormHelper
|
8
|
+
|
9
|
+
include ActionView::Helpers::NumberHelper
|
10
|
+
|
11
|
+
def amount_field(object_name, method, options = {})
|
12
|
+
format_options = I18n.t(:'number.amount_field.format', :raise => true) rescue {}
|
13
|
+
format_options = format_options.merge(AmountField::ActiveRecord::Validations.configuration)
|
14
|
+
format_options.merge!(options.delete(:format) || {})
|
15
|
+
|
16
|
+
object = options.delete(:object) || instance_variable_get("@#{object_name}")
|
17
|
+
|
18
|
+
# if no explicit value is given, we set a formatted one. In case of an error we take the
|
19
|
+
# original value inserted by the user.
|
20
|
+
if object.errors[method].blank?
|
21
|
+
options[:value] ||= number_with_precision(object.send(method), format_options)
|
22
|
+
else
|
23
|
+
options[:value] ||= object.send("#{AmountField::Configuration.prefix}_#{method}") || object.send("#{method}_before_type_cast")
|
24
|
+
end
|
25
|
+
|
26
|
+
options[:name] ||= "#{object_name}[#{AmountField::Configuration.prefix}_#{method}]"
|
27
|
+
options[:class] = "#{options[:class]} #{AmountField::Configuration.css_class}"
|
28
|
+
options[:id] ||= "#{object_name}_#{method}"
|
29
|
+
|
30
|
+
text_field(object_name, method, options)
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
|
35
|
+
module FormBuilder
|
36
|
+
|
37
|
+
include ActionView::Helpers::NumberHelper
|
38
|
+
|
39
|
+
def amount_field(method, options = {})
|
40
|
+
format_options = I18n.t(:'number.amount_field.format', :raise => true) rescue {}
|
41
|
+
format_options = format_options.merge(AmountField::ActiveRecord::Validations.configuration)
|
42
|
+
format_options.merge!(options.delete(:format) || {})
|
43
|
+
|
44
|
+
if (explicit_object = options.delete(:object))
|
45
|
+
self.object = explicit_object
|
46
|
+
end
|
47
|
+
|
48
|
+
# if no explicit value is given, we set a formatted one. In case of an error we take the
|
49
|
+
# original value inserted by the user.
|
50
|
+
if object.errors[method].blank?
|
51
|
+
options[:value] ||= number_with_precision(object.send(method), format_options)
|
52
|
+
else
|
53
|
+
options[:value] ||= object.send("#{AmountField::Configuration.prefix}_#{method}") || object.send("#{method}_before_type_cast")
|
54
|
+
end
|
55
|
+
|
56
|
+
# Note: we don't set options[:id] here, because caller or Rails knows best what to do.
|
57
|
+
# We accidentally set it to "foo[bar]_name" instead of "foo_bar_name".
|
58
|
+
options[:name] ||= "#{object_name}[#{AmountField::Configuration.prefix}_#{method}]"
|
59
|
+
options[:class] = "#{options[:class]} #{AmountField::Configuration.css_class}"
|
60
|
+
|
61
|
+
text_field(method, options)
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|