From a467c6bdd5722c09f5a15c0a7c5c40cc99c8be25 Mon Sep 17 00:00:00 2001
From: Jonathan del Strother <jdelStrother@gmail.com>
Date: Wed, 7 Feb 2018 13:06:11 +0000
Subject: Fix yaml deserialization of ActiveSupport::Duration

This ensures the duration's @parts hash has a default value, to avoid this regression introduced in 5.1:

  YAML.load(YAML.dump(10.minutes)) + 1  # => NoMethodError: undefined method `+' for nil:NilClass
---
 activesupport/lib/active_support/duration.rb | 8 ++++++++
 activesupport/test/core_ext/duration_test.rb | 6 ++++++
 2 files changed, 14 insertions(+)

diff --git a/activesupport/lib/active_support/duration.rb b/activesupport/lib/active_support/duration.rb
index 39deb2313f..19b2d84fc8 100644
--- a/activesupport/lib/active_support/duration.rb
+++ b/activesupport/lib/active_support/duration.rb
@@ -334,6 +334,14 @@ module ActiveSupport
       to_i
     end
 
+    def init_with(coder) #:nodoc:
+      initialize(coder["value"], coder["parts"])
+    end
+
+    def encode_with(coder) #:nodoc:
+      coder.map = { "value" => @value, "parts" => @parts }
+    end
+
     # Build ISO 8601 Duration string for this duration.
     # The +precision+ parameter can be used to limit seconds' precision of duration.
     def iso8601(precision: nil)
diff --git a/activesupport/test/core_ext/duration_test.rb b/activesupport/test/core_ext/duration_test.rb
index cd1b505c34..6366db99dc 100644
--- a/activesupport/test/core_ext/duration_test.rb
+++ b/activesupport/test/core_ext/duration_test.rb
@@ -585,6 +585,12 @@ class DurationTest < ActiveSupport::TestCase
     assert_equal time + d1, time + d2
   end
 
+  def test_durations_survive_yaml_serialization
+    d1 = YAML.load(YAML.dump(10.minutes))
+    assert_equal 600, d1.to_i
+    assert_equal 660, (d1 + 60).to_i
+  end
+
   private
     def eastern_time_zone
       if Gem.win_platform?
-- 
cgit v1.2.3