Skip to content

Commit ebcc2a5

Browse files
committed
Base: read from known_attributes in respond_to_missing?
Prior to this commit, the `respond_to_missing?` implementation had a conditional to supports attributes being able to be written to through methods "did not respond to" (like `send("#{attr_name}=", value)`), as well as `?`-suffixed predicate methods. The `method_missing` implementation has a set of conditionals similar to `respond_to_missing`, but with subtle variations through checking for an attribute name's inclusion in `known_attributes` (attributes defined by the Schema **or** assigned during `Base#load`) rather than the attribute name's inclusion in `attributes` (the current instance's assigned values, without any attributes declared in the Schema). Without the implementation changes, the following tests introduced in this commit fail: ``` 1) Failure: BaseTest#test_respond_to_known_attributes [test/cases/base_test.rb:972]: Expected #<Person:0x000000011d0cdcf8 @attributes={}, @prefix_options={}, @persisted=false> (Person) to respond to #name=. ``` This commit changes the `respond_to_missing?` conditional to check for the presence of the key in `known_attributes` rather than `attributes` so that instances will respond to `=`-suffixed writers and `?`-suffixed predicates for attributes that are declared in the resource's Schema that have not yet been assigned to.
1 parent b549319 commit ebcc2a5

File tree

2 files changed

+47
-2
lines changed

2 files changed

+47
-2
lines changed

lib/active_resource/base.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1653,7 +1653,7 @@ def respond_to_missing?(method, include_priv = false)
16531653
super
16541654
elsif known_attributes.include?(method_name)
16551655
true
1656-
elsif method_name =~ /(?:=|\?)$/ && attributes.include?($`)
1656+
elsif method_name =~ /(?:=|\?)$/ && known_attributes.include?($`)
16571657
true
16581658
else
16591659
# super must be called at the end of the method, because the inherited respond_to?

test/cases/base_test.rb

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -960,7 +960,52 @@ def test_respond_to
960960
assert_respond_to matz, :name
961961
assert_respond_to matz, :name=
962962
assert_respond_to matz, :name?
963-
assert_not matz.respond_to?(:super_scalable_stuff)
963+
assert_not_respond_to matz, :super_scalable_stuff
964+
assert_not_respond_to matz, :super_scalable_stuff=
965+
end
966+
967+
def test_respond_to_known_attributes
968+
previous_schema = Person.schema
969+
Person.schema = { name: "string" }
970+
971+
person = Person.new
972+
973+
assert_respond_to person, :name
974+
assert_respond_to person, :name=
975+
assert_not_respond_to person, :super_scalable_stuff
976+
assert_not_respond_to person, :super_scalable_stuff=
977+
ensure
978+
Person.schema = previous_schema
979+
end
980+
981+
def test_reading_an_unknown_attribute_raises_NoMethodError
982+
assert_raises NoMethodError, match: "unknown_attribute" do
983+
Post.new.unknown_attribute
984+
end
985+
end
986+
987+
def test_writing_an_unknown_attribute_assigns_a_value_that_can_be_read
988+
post = Post.new
989+
990+
post.unknown_attribute = "assigned"
991+
992+
assert_respond_to post, :unknown_attribute
993+
assert_equal "assigned", post.unknown_attribute
994+
end
995+
996+
def test_writing_nil_to_an_existing_attribute_can_be_read
997+
post = Post.new unknown_attribute: "assigned"
998+
999+
post.unknown_attribute = nil
1000+
1001+
assert_nil post.unknown_attribute
1002+
assert_respond_to post, :unknown_attribute
1003+
end
1004+
1005+
def test_predicate_for_an_unknown_attribute_returns_nil
1006+
post = Post.new
1007+
1008+
assert_not_predicate post, :unknown_attribute?
9641009
end
9651010

9661011
def test_custom_header

0 commit comments

Comments
 (0)