diff --git a/lib/virtus/attribute_set.rb b/lib/virtus/attribute_set.rb index 66055a84..48673077 100644 --- a/lib/virtus/attribute_set.rb +++ b/lib/virtus/attribute_set.rb @@ -193,9 +193,13 @@ def set_defaults(object, filter = method(:skip_default?)) # # @api private def coerce(attributes) - ::Hash.try_convert(attributes) or raise( - NoMethodError, "Expected #{attributes.inspect} to respond to #to_hash" - ) + if attributes.respond_to?(:to_unsafe_hash) + attributes.to_unsafe_hash + elsif hash_attributes = ::Hash.try_convert(attributes) + hash_attributes + else + raise( NoMethodError, "Expected #{attributes.inspect} to respond to #to_hash" ) + end end # @api private diff --git a/spec/unit/virtus/attributes_writer_spec.rb b/spec/unit/virtus/attributes_writer_spec.rb index e52ec1ac..075f7add 100644 --- a/spec/unit/virtus/attributes_writer_spec.rb +++ b/spec/unit/virtus/attributes_writer_spec.rb @@ -14,6 +14,32 @@ expect(subject.test).to eql('Hello World') end + + context "with Rails 5 parameters" do + class FakeParams + + def initialize(hash) + @hash = hash + end + + def to_hash + raise "Cannot be called on unsafe params" + end + + def to_unsafe_hash + @hash + end + end + + it "safely assigns the hash" do + subject.attributes = FakeParams.new({ :test => 'Hello World' }) + expect(subject.test).to eql('Hello World') + end + + it "handles properly if the attributes are not hash like" do + expect { subject.attributes = 1 }.to raise_error(NoMethodError) + end + end end context 'with a class' do