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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: bf99ef08d5088f5fd791efc0acf489fa51ea5417
4
- data.tar.gz: 013d7f081dea1507d1819b129ffe1697059abea5
3
+ metadata.gz: 59bab63abe22f6890fbbe6d2d754285d0897b0bf
4
+ data.tar.gz: d6463916eeb2d036930ec25447ba1ac3e4e92d6d
5
5
  SHA512:
6
- metadata.gz: a6c5091da9618f1886ddc60472593f84e42bfa2d9392c75d77b069774384811764e0899344f8e37a0cfefcef2291cc464687c7f83d55d1315d896b43de291786
7
- data.tar.gz: 18f7bbf54dfc495b934b6a7e8253fbe763dda21b72231a5ecbac47de21e3189ec388edbac91c21137999bbd07fbca681eeb922762e4de356905bd7ffa64b3991
6
+ metadata.gz: e098d8423fde0322dac888e933df34313e4bd595ddc308dac2e66b9aa2a5fed2c973b6526477a130e62aefa7cca5f2dea045296fee3612dd71de0e2a41afc765
7
+ data.tar.gz: b9c601788e8fb90a21fde7156c63e7b3630beafe4c96a185e5e3361dc15a4a72df434df38c0b84642664860d4fa767c088e5b6f02ebe0d8f66041d10a2c6a32e
@@ -4,24 +4,20 @@
4
4
 
5
5
  delocalize provides localized date/time and number parsing functionality for Rails.
6
6
 
7
- ## Demo Application
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 >= 3.0 (Rails 2 and probably even Rails 1 *should* work but aren't officially supported)
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/1-0-beta/.travis.yml) in order to see which configurations we are testing.
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-2015 Clemens Kofler <clemens@railway.at>
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
- parser ? parser.parse(value) : value
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
- return if parsed.empty? # the datetime value is invalid
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 ? datetime.to_date : datetime
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)
@@ -1,3 +1,3 @@
1
1
  module Delocalize
2
- VERSION = "1.1.0"
2
+ VERSION = "1.2.0".freeze
3
3
  end
@@ -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 "doesn't parse date/time-like objects" do
50
- date = Date.civil(2009, 10, 19)
51
- time = Time.zone.local(2009, 3, 1, 12, 0, 0)
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
- @date_parser.parse(date).must_equal date
54
- @time_parser.parse(time).must_equal time
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
@@ -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 -1299.99
27
+ @parser.parse(-1299.99).must_equal(-1299.99)
27
28
  @parser.parse(1299).must_equal 1299
28
- @parser.parse(-1299).must_equal -1299
29
+ @parser.parse(-1299).must_equal(-1299)
29
30
  end
30
31
  end
@@ -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
- delocalized_params = params.delocalize({})
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
@@ -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.1.0
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: 2016-07-20 00:00:00.000000000 Z
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.4.5.1
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