diff --git a/lib/active_resource.rb b/lib/active_resource.rb index 4379acd372..42b074aa53 100644 --- a/lib/active_resource.rb +++ b/lib/active_resource.rb @@ -35,6 +35,7 @@ module ActiveResource URI_PARSER = defined?(URI::RFC2396_PARSER) ? URI::RFC2396_PARSER : URI::RFC2396_Parser.new + autoload :AttributeSet autoload :Base autoload :Callbacks autoload :Coder diff --git a/lib/active_resource/attribute_set.rb b/lib/active_resource/attribute_set.rb new file mode 100644 index 0000000000..2ce7318075 --- /dev/null +++ b/lib/active_resource/attribute_set.rb @@ -0,0 +1,12 @@ +# frozen_string_literal: true + +module ActiveResource + class AttributeSet < DelegateClass(Hash) # :nodoc: + MESSAGE = "Writing to the attributes hash is deprecated. Set attributes directly on the instance instead." + + deprecate(**[ :[]=, :store, :update, :merge! ].index_with(MESSAGE), + deprecator: ActiveResource.deprecator) + + delegate :is_a?, to: :__getobj__ + end +end diff --git a/lib/active_resource/base.rb b/lib/active_resource/base.rb index edf92e5c25..291a3ddad8 100644 --- a/lib/active_resource/base.rb +++ b/lib/active_resource/base.rb @@ -1276,9 +1276,17 @@ def split_options(options = {}) end end - attr_accessor :attributes # :nodoc: attr_accessor :prefix_options # :nodoc: + def attributes=(value) # :nodoc: + ActiveResource.deprecator.warn("#attributes= is deprecated. Call #load on the instance instead.") + @attributes = value + end + + def attributes # :nodoc: + AttributeSet.new(@attributes) + end + # If no schema has been defined for the class (see # ActiveResource::schema=), the default automatic schema is # generated from the current instance's attributes @@ -1385,7 +1393,7 @@ def id # Sets the \id attribute of the resource. def id=(id) - attributes[self.class.primary_key] = id + @attributes[self.class.primary_key] = id end # Test for equality. Resource are equal if and only if +other+ is the same object or @@ -1439,7 +1447,7 @@ def hash # next_invoice.customer # => That Company def dup self.class.new.tap do |resource| - resource.attributes = @attributes + resource.send :instance_variable_set, "@attributes", @attributes resource.prefix_options = @prefix_options end end @@ -1842,7 +1850,7 @@ def method_missing(method_symbol, *arguments) # :nodoc: if method_name =~ /(=|\?)$/ case $1 when "=" - attributes[$`] = arguments.first + @attributes[$`] = arguments.first when "?" attributes[$`] end diff --git a/test/cases/base_test.rb b/test/cases/base_test.rb index 462920ac92..4d7dc579b1 100644 --- a/test/cases/base_test.rb +++ b/test/cases/base_test.rb @@ -1743,4 +1743,38 @@ def test_paths_without_format ensure ActiveResource::Base.include_format_in_path = true end + + def test_deprecate_attributes_write + person = Person.find(1) + + assert_deprecated("#attributes= is deprecated. Call #load on the instance instead.", ActiveResource.deprecator) do + person.attributes = { "name" => "changed" } + end + + assert_equal "changed", person.name + end + + def test_deprecate_attributes_store + [ :[]=, :store ].each do |store| + person = Person.find(1) + + assert_deprecated("Writing to the attributes hash is deprecated. Set attributes directly on the instance instead.", ActiveResource.deprecator) do + person.attributes.send(store, "name", "changed") + end + + assert_equal "changed", person.name + end + end + + def test_deprecate_attributes_update + [ :update, :merge! ].each do |update| + person = Person.find(1) + + assert_deprecated("Writing to the attributes hash is deprecated. Set attributes directly on the instance instead.", ActiveResource.deprecator) do + person.attributes.send(update, "name" => "changed") + end + + assert_equal "changed", person.name + end + end end