delocalize 1.1.0 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.markdown +6 -10
- data/lib/delocalize/parameter_delocalizing.rb +6 -1
- data/lib/delocalize/parsers/date_time.rb +7 -4
- data/lib/delocalize/version.rb +1 -1
- data/test/date_time_parser_test.rb +69 -5
- data/test/number_parser_test.rb +3 -2
- data/test/parameters_test.rb +12 -1
- data/test/test_helper.rb +4 -1
- metadata +3 -21
- data/lib/delocalize/rails_ext/action_view_rails3.rb +0 -53
- data/lib/delocalize/rails_ext/action_view_rails4.rb +0 -38
- data/lib/delocalize/rails_ext/active_record_rails3.rb +0 -80
- data/lib/delocalize/rails_ext/active_record_rails4.rb +0 -72
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 59bab63abe22f6890fbbe6d2d754285d0897b0bf
|
4
|
+
data.tar.gz: d6463916eeb2d036930ec25447ba1ac3e4e92d6d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e098d8423fde0322dac888e933df34313e4bd595ddc308dac2e66b9aa2a5fed2c973b6526477a130e62aefa7cca5f2dea045296fee3612dd71de0e2a41afc765
|
7
|
+
data.tar.gz: b9c601788e8fb90a21fde7156c63e7b3630beafe4c96a185e5e3361dc15a4a72df434df38c0b84642664860d4fa767c088e5b6f02ebe0d8f66041d10a2c6a32e
|
data/README.markdown
CHANGED
@@ -4,24 +4,20 @@
|
|
4
4
|
|
5
5
|
delocalize provides localized date/time and number parsing functionality for Rails.
|
6
6
|
|
7
|
-
##
|
8
|
-
|
9
|
-
Find a demo application [here](https://github.com/clemens/delocalize_demo).
|
10
|
-
|
11
|
-
## Compability
|
7
|
+
## Compatibility
|
12
8
|
|
13
9
|
This gem requires the following versions:
|
14
10
|
|
15
|
-
* Ruby >= 1.9.2
|
16
|
-
* Rails >=
|
11
|
+
* Ruby >= 2.1.10 (Ruby >= 1.9.2 *should* work but isn't officially supported)
|
12
|
+
* Rails >= 4.2 (earlier versions including probably even Rails 1 *should* work but aren't officially supported)
|
17
13
|
|
18
|
-
Check [the Travis configuration](https://github.com/clemens/delocalize/blob/
|
14
|
+
Check [the Travis configuration](https://github.com/clemens/delocalize/blob/master/.travis.yml) in order to see which configurations we are testing.
|
19
15
|
|
20
16
|
## Installation
|
21
17
|
|
22
18
|
You can use delocalize as a gem. Using delocalize as a Rails plugin has been discontinued and is no supported. If you want/need to use delocalize as a plugin (I really don't see a reason why you'd want to), consider using the `0-2-stable` branch.
|
23
19
|
|
24
|
-
### Rails 3
|
20
|
+
### Rails 3 and above
|
25
21
|
|
26
22
|
To use delocalize, put the following gem requirement in your `Gemfile`:
|
27
23
|
|
@@ -163,6 +159,6 @@ For dates and times, you have to define input formats which are taken from the a
|
|
163
159
|
|
164
160
|
[Here](https://github.com/clemens/delocalize/graphs/contributors) is a list of all people who ever contributed to delocalize.
|
165
161
|
|
166
|
-
Copyright (c) 2009-
|
162
|
+
Copyright (c) 2009-2017 Clemens Kofler <clemens@railway.at>
|
167
163
|
<http://www.railway.at/>
|
168
164
|
Released under the MIT license
|
@@ -24,7 +24,12 @@ module Delocalize
|
|
24
24
|
|
25
25
|
def delocalize_parse(options, key_stack, value)
|
26
26
|
parser = delocalize_parser_for(options, key_stack)
|
27
|
-
|
27
|
+
return value unless parser
|
28
|
+
begin
|
29
|
+
parser.parse(value)
|
30
|
+
rescue ArgumentError
|
31
|
+
value
|
32
|
+
end
|
28
33
|
end
|
29
34
|
|
30
35
|
def delocalize_parser_for(options, key_stack)
|
@@ -36,7 +36,7 @@ module Delocalize
|
|
36
36
|
input_formats(type).each do |original_format|
|
37
37
|
next unless datetime =~ /^#{apply_regex(original_format)}$/
|
38
38
|
|
39
|
-
datetime = ::DateTime.strptime(datetime, original_format)
|
39
|
+
datetime = ::DateTime.strptime(datetime, original_format) rescue break
|
40
40
|
return Date == type ?
|
41
41
|
datetime.to_date :
|
42
42
|
Time.zone.local(datetime.year, datetime.mon, datetime.mday, datetime.hour, datetime.min, datetime.sec)
|
@@ -51,13 +51,16 @@ module Delocalize
|
|
51
51
|
|
52
52
|
today = Date.current
|
53
53
|
parsed = Date._parse(datetime)
|
54
|
-
|
54
|
+
raise ArgumentError, "invalid date: #{datetime}" if parsed.empty? # the datetime value is invalid
|
55
55
|
|
56
56
|
# set default year, month and day if not found
|
57
57
|
parsed.reverse_merge!(:year => today.year, :mon => today.mon, :mday => today.mday)
|
58
|
-
datetime = Time.zone.local(*parsed.values_at(:year, :mon, :mday, :hour, :min, :sec))
|
59
58
|
|
60
|
-
Date == type
|
59
|
+
if Date == type
|
60
|
+
Date.civil(*parsed.values_at(:year, :mon, :mday))
|
61
|
+
else
|
62
|
+
Time.zone.local(*parsed.values_at(:year, :mon, :mday, :hour, :min, :sec))
|
63
|
+
end
|
61
64
|
end
|
62
65
|
|
63
66
|
def translate_month_and_day_names(datetime)
|
data/lib/delocalize/version.rb
CHANGED
@@ -5,6 +5,7 @@ require 'active_support/time'
|
|
5
5
|
|
6
6
|
describe Delocalize::Parsers::DateTime do
|
7
7
|
before do
|
8
|
+
I18n.locale = I18n.default_locale
|
8
9
|
Time.zone = 'Berlin' # make sure everything works as expected with TimeWithZone
|
9
10
|
@time_parser = Delocalize::Parsers::DateTime.new(Time)
|
10
11
|
@date_parser = Delocalize::Parsers::DateTime.new(Date)
|
@@ -14,6 +15,23 @@ describe Delocalize::Parsers::DateTime do
|
|
14
15
|
Timecop.return
|
15
16
|
end
|
16
17
|
|
18
|
+
it "parses a date/time using default parsing" do
|
19
|
+
I18n.locale = :en # force default parsing since we don't have a locale file for en
|
20
|
+
|
21
|
+
date = Date.civil(2009, 2, 28)
|
22
|
+
time = Time.zone.local(2009, 2, 28, 12, 30, 45)
|
23
|
+
@date_parser.parse('2009-02-28').must_equal date
|
24
|
+
@time_parser.parse('2009-02-28 12:30:45').must_equal time
|
25
|
+
end
|
26
|
+
|
27
|
+
it "doesn't parse date/time-like objects" do
|
28
|
+
date = Date.civil(2009, 10, 19)
|
29
|
+
time = Time.zone.local(2009, 3, 1, 12, 0, 0)
|
30
|
+
|
31
|
+
@date_parser.parse(date).must_equal date
|
32
|
+
@time_parser.parse(time).must_equal time
|
33
|
+
end
|
34
|
+
|
17
35
|
# date
|
18
36
|
it "parses a date from a string" do
|
19
37
|
date = Date.civil(2009, 10, 19)
|
@@ -27,6 +45,23 @@ describe Delocalize::Parsers::DateTime do
|
|
27
45
|
@date_parser.parse('19.10.').must_equal date
|
28
46
|
end
|
29
47
|
|
48
|
+
it "fails for an invalid date (same behavior as without delocalize)" do
|
49
|
+
must_raise_invalid_date { @date_parser.parse('29. Februar 2009') }
|
50
|
+
end
|
51
|
+
|
52
|
+
it "rejects invalid dates when using default parsing (Ruby default behavior)" do
|
53
|
+
I18n.locale = :en # force default parsing since we don't have a locale file for en
|
54
|
+
|
55
|
+
must_raise_invalid_date { @date_parser.parse('32.10.2009') }
|
56
|
+
end
|
57
|
+
|
58
|
+
|
59
|
+
it "rejects 29th February in a non leap year when using default parsing (Ruby default behavior)" do
|
60
|
+
I18n.locale = :en # force default parsing since we don't have a locale file for en
|
61
|
+
|
62
|
+
must_raise_invalid_date { @date_parser.parse('29.02.2009') }
|
63
|
+
end
|
64
|
+
|
30
65
|
# datetime
|
31
66
|
it "parses a datetime from a string" do
|
32
67
|
time = Time.zone.local(2009, 3, 1, 12, 0, 0)
|
@@ -39,6 +74,25 @@ describe Delocalize::Parsers::DateTime do
|
|
39
74
|
@time_parser.parse('1. März, 12:00 Uhr').must_equal time
|
40
75
|
end
|
41
76
|
|
77
|
+
it "doesn't fail for an invalid datetime (same behavior as without delocalize)" do
|
78
|
+
time = Time.zone.local(2009, 3, 1, 12, 0)
|
79
|
+
@time_parser.parse('29. Februar 2009, 12:00 Uhr').must_equal time
|
80
|
+
end
|
81
|
+
|
82
|
+
it "shifts invalid dates to the next month when using default parse (mimicking Ruby's default behavior)" do
|
83
|
+
I18n.locale = :en # force default parsing since we don't have a locale file for en
|
84
|
+
|
85
|
+
time = Time.zone.local(2009, 5, 1, 12, 0, 0)
|
86
|
+
@time_parser.parse('31.04.2009 12:00').must_equal time
|
87
|
+
end
|
88
|
+
|
89
|
+
it "shifts 29th February to 1st March in a non leap year when using default parse (mimicking Ruby's default behavior)" do
|
90
|
+
I18n.locale = :en # force default parsing since we don't have a locale file for en
|
91
|
+
|
92
|
+
time = Time.zone.local(2009, 3, 1, 12, 0, 0)
|
93
|
+
@time_parser.parse('29.02.2009 12:00').must_equal time
|
94
|
+
end
|
95
|
+
|
42
96
|
# time
|
43
97
|
it "parses a time from a string, defaulting to the current day" do
|
44
98
|
Timecop.freeze(Time.zone.local(2009, 3, 1, 12, 0, 0)) # prevent DST issues
|
@@ -46,11 +100,21 @@ describe Delocalize::Parsers::DateTime do
|
|
46
100
|
@time_parser.parse('9:00 Uhr').must_equal time
|
47
101
|
end
|
48
102
|
|
49
|
-
it "
|
50
|
-
|
51
|
-
|
103
|
+
it "raises ArgumentError when parsing a bad string" do
|
104
|
+
err = proc { @date_parser.parse("asdf") }.must_raise ArgumentError
|
105
|
+
err.message.must_equal "invalid date: asdf"
|
106
|
+
end
|
52
107
|
|
53
|
-
|
54
|
-
@
|
108
|
+
it "raises ArgumentError when parsing a bad date" do
|
109
|
+
must_raise_invalid_date { @date_parser.parse("02.0.2017") }
|
110
|
+
must_raise_invalid_date { @date_parser.parse("02.99.2017") }
|
111
|
+
end
|
112
|
+
|
113
|
+
def must_raise_invalid_date
|
114
|
+
begin
|
115
|
+
yield
|
116
|
+
rescue => ex
|
117
|
+
ex.message.must_equal 'invalid date'
|
118
|
+
end
|
55
119
|
end
|
56
120
|
end
|
data/test/number_parser_test.rb
CHANGED
@@ -2,6 +2,7 @@ require 'test_helper'
|
|
2
2
|
|
3
3
|
describe Delocalize::Parsers::Number do
|
4
4
|
before do
|
5
|
+
I18n.locale = I18n.default_locale
|
5
6
|
@parser = Delocalize::Parsers::Number.new
|
6
7
|
end
|
7
8
|
|
@@ -23,8 +24,8 @@ describe Delocalize::Parsers::Number do
|
|
23
24
|
|
24
25
|
it "doesn't change a number if it's already a numeric type" do
|
25
26
|
@parser.parse(1299.99).must_equal 1299.99
|
26
|
-
@parser.parse(-1299.99).must_equal
|
27
|
+
@parser.parse(-1299.99).must_equal(-1299.99)
|
27
28
|
@parser.parse(1299).must_equal 1299
|
28
|
-
@parser.parse(-1299).must_equal
|
29
|
+
@parser.parse(-1299).must_equal(-1299)
|
29
30
|
end
|
30
31
|
end
|
data/test/parameters_test.rb
CHANGED
@@ -14,6 +14,7 @@ puts "Testing parameter classes: #{parameters_classes.inspect}"
|
|
14
14
|
parameters_classes.each do |parameters_class|
|
15
15
|
describe parameters_class do
|
16
16
|
before do
|
17
|
+
I18n.locale = I18n.default_locale
|
17
18
|
Time.zone = 'Berlin' # make sure everything works as expected with TimeWithZone
|
18
19
|
end
|
19
20
|
|
@@ -159,7 +160,7 @@ parameters_classes.each do |parameters_class|
|
|
159
160
|
params = parameters_class.new(:parent => { :parent_date => '21. Mai 2004' })
|
160
161
|
|
161
162
|
## Should not throw an error:
|
162
|
-
|
163
|
+
params.delocalize({})
|
163
164
|
end
|
164
165
|
|
165
166
|
it "delocalizes arrays" do
|
@@ -170,5 +171,15 @@ parameters_classes.each do |parameters_class|
|
|
170
171
|
delocalized_params[:location].must_equal ['13.456', '51.234']
|
171
172
|
delocalized_params[:interval].must_equal [Date.civil(2013, 12, 25), Date.civil(2014, 1, 31)]
|
172
173
|
end
|
174
|
+
|
175
|
+
it "keeps invalid dates in the params hash" do
|
176
|
+
params = parameters_class.new(:first_date => "asdf", :second_date => "02.0.2017", :third_date => "02.123.2017")
|
177
|
+
|
178
|
+
delocalized_params = params.delocalize(:first_date => :date, :second_date => :date, :third_date => :date)
|
179
|
+
|
180
|
+
delocalized_params[:first_date].must_equal "asdf"
|
181
|
+
delocalized_params[:second_date].must_equal "02.0.2017"
|
182
|
+
delocalized_params[:third_date].must_equal "02.123.2017"
|
183
|
+
end
|
173
184
|
end
|
174
185
|
end
|
data/test/test_helper.rb
CHANGED
@@ -7,9 +7,11 @@ Bundler.require(:default, :development)
|
|
7
7
|
|
8
8
|
require 'minitest/autorun'
|
9
9
|
require 'minitest/spec'
|
10
|
-
require 'mocha/setup'
|
11
10
|
|
12
11
|
require 'rails'
|
12
|
+
# We need to explicitly load ActiveSupport's version of Hash#slice since Rails 3.2 somehow loads
|
13
|
+
# i18n's version first which is different from Rails' (see https://github.com/svenfuchs/i18n/commit/24e71a9a4901ed18c9cab5c53109fd9bf2416bcb).
|
14
|
+
require 'active_support/core_ext/hash/slice'
|
13
15
|
|
14
16
|
de = {
|
15
17
|
:date => {
|
@@ -65,4 +67,5 @@ tt[:date][:formats][:default] = '%d|%m|%Y'
|
|
65
67
|
I18n.backend.store_translations :de, de
|
66
68
|
I18n.backend.store_translations :tt, tt
|
67
69
|
|
70
|
+
I18n.default_locale = :de
|
68
71
|
I18n.locale = :de
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: delocalize
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Clemens Kofler
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2017-06-13 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -24,20 +24,6 @@ dependencies:
|
|
24
24
|
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '2'
|
27
|
-
- !ruby/object:Gem::Dependency
|
28
|
-
name: mocha
|
29
|
-
requirement: !ruby/object:Gem::Requirement
|
30
|
-
requirements:
|
31
|
-
- - ">="
|
32
|
-
- !ruby/object:Gem::Version
|
33
|
-
version: '0'
|
34
|
-
type: :development
|
35
|
-
prerelease: false
|
36
|
-
version_requirements: !ruby/object:Gem::Requirement
|
37
|
-
requirements:
|
38
|
-
- - ">="
|
39
|
-
- !ruby/object:Gem::Version
|
40
|
-
version: '0'
|
41
27
|
- !ruby/object:Gem::Dependency
|
42
28
|
name: timecop
|
43
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -68,10 +54,6 @@ files:
|
|
68
54
|
- lib/delocalize/parsers.rb
|
69
55
|
- lib/delocalize/parsers/date_time.rb
|
70
56
|
- lib/delocalize/parsers/number.rb
|
71
|
-
- lib/delocalize/rails_ext/action_view_rails3.rb
|
72
|
-
- lib/delocalize/rails_ext/action_view_rails4.rb
|
73
|
-
- lib/delocalize/rails_ext/active_record_rails3.rb
|
74
|
-
- lib/delocalize/rails_ext/active_record_rails4.rb
|
75
57
|
- lib/delocalize/railtie.rb
|
76
58
|
- lib/delocalize/version.rb
|
77
59
|
- test/database.yml
|
@@ -100,7 +82,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
100
82
|
version: '0'
|
101
83
|
requirements: []
|
102
84
|
rubyforge_project:
|
103
|
-
rubygems_version: 2.
|
85
|
+
rubygems_version: 2.6.11
|
104
86
|
signing_key:
|
105
87
|
specification_version: 4
|
106
88
|
summary: Localized date/time and number parsing
|
@@ -1,53 +0,0 @@
|
|
1
|
-
require 'action_view'
|
2
|
-
|
3
|
-
# TODO: also override other methods like to_check_box_tag since they might contain numeric values?
|
4
|
-
# ActionView needs some patching too
|
5
|
-
|
6
|
-
ActionView::Helpers::InstanceTag.class_eval do
|
7
|
-
include ActionView::Helpers::NumberHelper
|
8
|
-
|
9
|
-
alias original_to_input_field_tag to_input_field_tag
|
10
|
-
def to_input_field_tag(field_type, options = {})
|
11
|
-
options.symbolize_keys!
|
12
|
-
# numbers and dates/times should be localized unless value is already defined
|
13
|
-
if object && (options[:value].blank? || !options[:value].is_a?(String)) && object.respond_to?(:column_for_attribute) && column = object.column_for_attribute(method_name)
|
14
|
-
value = options[:value] || object.send(method_name)
|
15
|
-
|
16
|
-
if column.number?
|
17
|
-
number_options = I18n.t(:'number.format')
|
18
|
-
separator = options.delete(:separator) || number_options[:separator]
|
19
|
-
delimiter = options.delete(:delimiter) || number_options[:delimiter]
|
20
|
-
precision = options.delete(:precision) || number_options[:precision]
|
21
|
-
opts = { :separator => separator, :delimiter => delimiter, :precision => precision }
|
22
|
-
# integers don't need a precision
|
23
|
-
opts.merge!(:precision => 0) if column.type == :integer
|
24
|
-
|
25
|
-
hidden_for_integer = field_type == 'hidden' && column.type == :integer
|
26
|
-
|
27
|
-
# the number will be formatted only if it has no numericality errors
|
28
|
-
if object.respond_to?(:errors) && !Array(object.errors[method_name]).try(:include?, 'is not a number')
|
29
|
-
# we don't format integer hidden fields because this breaks nested_attributes
|
30
|
-
options[:value] = number_with_precision(value, opts) unless hidden_for_integer
|
31
|
-
end
|
32
|
-
elsif column.date? || column.time?
|
33
|
-
options[:value] = value ? I18n.l(value, :format => options.delete(:format)) : nil
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
|
-
original_to_input_field_tag(field_type, options)
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
# TODO: does it make sense to also override FormTagHelper methods?
|
42
|
-
# ActionView::Helpers::FormTagHelper.class_eval do
|
43
|
-
# include ActionView::Helpers::NumberHelper
|
44
|
-
#
|
45
|
-
# alias original_text_field_tag text_field_tag
|
46
|
-
# def text_field_tag(name, value = nil, options = {})
|
47
|
-
# value = options.delete(:value) if options.key?(:value)
|
48
|
-
# if value.is_a?(Numeric)
|
49
|
-
# value = number_with_delimiter(value)
|
50
|
-
# end
|
51
|
-
# original_text_field_tag(name, value, options)
|
52
|
-
# end
|
53
|
-
# end
|
@@ -1,38 +0,0 @@
|
|
1
|
-
require 'action_view'
|
2
|
-
|
3
|
-
# TODO: also override other methods like to_check_box_tag since they might contain numeric values?
|
4
|
-
# ActionView needs some patching too
|
5
|
-
|
6
|
-
ActionView::Helpers::Tags::TextField.class_eval do
|
7
|
-
include ActionView::Helpers::NumberHelper
|
8
|
-
|
9
|
-
def render_with_localization
|
10
|
-
if object && (@options[:value].blank? || !@options[:value].is_a?(String)) && object.respond_to?(:column_for_attribute) && column = object.column_for_attribute(@method_name)
|
11
|
-
value = @options[:value] || object.send(@method_name)
|
12
|
-
|
13
|
-
if column.number?
|
14
|
-
number_options = I18n.t(:'number.format')
|
15
|
-
separator = @options.delete(:separator) || number_options[:separator]
|
16
|
-
delimiter = @options.delete(:delimiter) || number_options[:delimiter]
|
17
|
-
precision = @options.delete(:precision) || number_options[:precision]
|
18
|
-
opts = { :separator => separator, :delimiter => delimiter, :precision => precision }
|
19
|
-
# integers don't need a precision
|
20
|
-
opts.merge!(:precision => 0) if column.type == :integer
|
21
|
-
|
22
|
-
hidden_for_integer = field_type == 'hidden' && column.type == :integer
|
23
|
-
|
24
|
-
# the number will be formatted only if it has no numericality errors
|
25
|
-
if object.respond_to?(:errors) && !Array(object.errors[@method_name]).try(:include?, 'is not a number')
|
26
|
-
# we don't format integer hidden fields because this breaks nested_attributes
|
27
|
-
@options[:value] = number_with_precision(value, opts) unless hidden_for_integer
|
28
|
-
end
|
29
|
-
elsif column.date? || column.time?
|
30
|
-
@options[:value] = value ? I18n.l(value, :format => @options.delete(:format)) : nil
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
|
-
render_without_localization
|
35
|
-
end
|
36
|
-
|
37
|
-
alias_method_chain :render, :localization
|
38
|
-
end
|
@@ -1,80 +0,0 @@
|
|
1
|
-
require 'active_record'
|
2
|
-
|
3
|
-
require 'active_record/connection_adapters/abstract/schema_definitions'
|
4
|
-
begin
|
5
|
-
require 'active_record/connection_adapters/column'
|
6
|
-
rescue LoadError
|
7
|
-
# Not Rails 3.1, it seems
|
8
|
-
end
|
9
|
-
|
10
|
-
# let's hack into ActiveRecord a bit - everything at the lowest possible level, of course, so we minimalize side effects
|
11
|
-
ActiveRecord::ConnectionAdapters::Column.class_eval do
|
12
|
-
def date?
|
13
|
-
klass == Date
|
14
|
-
end
|
15
|
-
|
16
|
-
def time?
|
17
|
-
klass == Time
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
ActiveRecord::Base.class_eval do
|
22
|
-
def write_attribute_with_localization(attr_name, original_value)
|
23
|
-
new_value = original_value
|
24
|
-
if column = column_for_attribute(attr_name.to_s)
|
25
|
-
if column.date?
|
26
|
-
new_value = Date.parse_localized(original_value) rescue original_value
|
27
|
-
elsif column.time?
|
28
|
-
new_value = Time.parse_localized(original_value) rescue original_value
|
29
|
-
end
|
30
|
-
end
|
31
|
-
write_attribute_without_localization(attr_name, new_value)
|
32
|
-
end
|
33
|
-
alias_method_chain :write_attribute, :localization
|
34
|
-
|
35
|
-
def convert_number_column_value_with_localization(value)
|
36
|
-
value = convert_number_column_value_without_localization(value)
|
37
|
-
value = Numeric.parse_localized(value) if I18n.delocalization_enabled?
|
38
|
-
value
|
39
|
-
end
|
40
|
-
alias_method_chain :convert_number_column_value, :localization
|
41
|
-
|
42
|
-
|
43
|
-
define_method( (Gem::Version.new(ActiveRecord::VERSION::STRING) < Gem::Version.new('3.2.9')) ? :field_changed? : :_field_changed? ) do |attr, old, value|
|
44
|
-
if column = column_for_attribute(attr)
|
45
|
-
if column.number? && column.null && (old.nil? || old == 0) && value.blank?
|
46
|
-
# For nullable numeric columns, NULL gets stored in database for blank (i.e. '') values.
|
47
|
-
# Hence we don't record it as a change if the value changes from nil to ''.
|
48
|
-
# If an old value of 0 is set to '' we want this to get changed to nil as otherwise it'll
|
49
|
-
# be typecast back to 0 (''.to_i => 0)
|
50
|
-
value = nil
|
51
|
-
elsif column.number?
|
52
|
-
value = column.type_cast(convert_number_column_value_with_localization(value))
|
53
|
-
else
|
54
|
-
value = column.type_cast(value)
|
55
|
-
end
|
56
|
-
end
|
57
|
-
old != value
|
58
|
-
end
|
59
|
-
end
|
60
|
-
|
61
|
-
ActiveRecord::Base.instance_eval do
|
62
|
-
def define_method_attribute=(attr_name)
|
63
|
-
if create_time_zone_conversion_attribute?(attr_name, columns_hash[attr_name])
|
64
|
-
method_body, line = <<-EOV, __LINE__ + 1
|
65
|
-
def #{attr_name}=(original_time)
|
66
|
-
time = original_time
|
67
|
-
unless time.acts_like?(:time)
|
68
|
-
time = time.is_a?(String) ? (I18n.delocalization_enabled? ? Time.zone.parse_localized(time) : Time.zone.parse(time)) : time.to_time rescue time
|
69
|
-
end
|
70
|
-
time = time.in_time_zone rescue nil if time
|
71
|
-
write_attribute(:#{attr_name}, original_time)
|
72
|
-
@attributes_cache["#{attr_name}"] = time
|
73
|
-
end
|
74
|
-
EOV
|
75
|
-
generated_attribute_methods.module_eval(method_body, __FILE__, line)
|
76
|
-
else
|
77
|
-
super
|
78
|
-
end
|
79
|
-
end
|
80
|
-
end
|
@@ -1,72 +0,0 @@
|
|
1
|
-
require 'active_record'
|
2
|
-
|
3
|
-
# let's hack into ActiveRecord a bit - everything at the lowest possible level, of course, so we minimalize side effects
|
4
|
-
ActiveRecord::ConnectionAdapters::Column.class_eval do
|
5
|
-
def date?
|
6
|
-
klass == Date
|
7
|
-
end
|
8
|
-
|
9
|
-
def time?
|
10
|
-
klass == Time
|
11
|
-
end
|
12
|
-
end
|
13
|
-
|
14
|
-
module ActiveRecord::AttributeMethods::Write
|
15
|
-
def type_cast_attribute_for_write(column, value)
|
16
|
-
return value unless column
|
17
|
-
|
18
|
-
value = Numeric.parse_localized(value) if column.number? && I18n.delocalization_enabled?
|
19
|
-
column.type_cast_for_write value
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
ActiveRecord::Base.class_eval do
|
24
|
-
def write_attribute_with_localization(attr_name, original_value)
|
25
|
-
new_value = original_value
|
26
|
-
if column = column_for_attribute(attr_name.to_s)
|
27
|
-
if column.date?
|
28
|
-
new_value = Date.parse_localized(original_value) rescue original_value
|
29
|
-
elsif column.time?
|
30
|
-
new_value = Time.parse_localized(original_value) rescue original_value
|
31
|
-
end
|
32
|
-
end
|
33
|
-
write_attribute_without_localization(attr_name, new_value)
|
34
|
-
end
|
35
|
-
alias_method_chain :write_attribute, :localization
|
36
|
-
|
37
|
-
define_method :_field_changed? do |attr, old, value|
|
38
|
-
if column = column_for_attribute(attr)
|
39
|
-
if column.number? && column.null && (old.nil? || old == 0) && value.blank?
|
40
|
-
# For nullable numeric columns, NULL gets stored in database for blank (i.e. '') values.
|
41
|
-
# Hence we don't record it as a change if the value changes from nil to ''.
|
42
|
-
# If an old value of 0 is set to '' we want this to get changed to nil as otherwise it'll
|
43
|
-
# be typecast back to 0 (''.to_i => 0)
|
44
|
-
value = nil
|
45
|
-
elsif column.number?
|
46
|
-
value = column.type_cast(Numeric.parse_localized(value))
|
47
|
-
else
|
48
|
-
value = column.type_cast(value)
|
49
|
-
end
|
50
|
-
end
|
51
|
-
old != value
|
52
|
-
end
|
53
|
-
|
54
|
-
def define_method_attribute=(attr_name)
|
55
|
-
if create_time_zone_conversion_attribute?(attr_name, columns_hash[attr_name])
|
56
|
-
method_body, line = <<-EOV, __LINE__ + 1
|
57
|
-
def #{attr_name}=(original_time)
|
58
|
-
time = original_time
|
59
|
-
unless time.acts_like?(:time)
|
60
|
-
time = time.is_a?(String) ? (I18n.delocalization_enabled? ? Time.zone.parse_localized(time) : Time.zone.parse(time)) : time.to_time rescue time
|
61
|
-
end
|
62
|
-
time = time.in_time_zone rescue nil if time
|
63
|
-
write_attribute(:#{attr_name}, original_time)
|
64
|
-
@attributes_cache["#{attr_name}"] = time
|
65
|
-
end
|
66
|
-
EOV
|
67
|
-
generated_attribute_methods.module_eval(method_body, __FILE__, line)
|
68
|
-
else
|
69
|
-
super
|
70
|
-
end
|
71
|
-
end
|
72
|
-
end
|