delocalize 1.1.0 → 1.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|