From e7a28c39908768acc1b8c836ab53af546c58c0c0 Mon Sep 17 00:00:00 2001 From: Daniel Colson Date: Mon, 22 Apr 2019 19:48:17 -0400 Subject: [PATCH] Add attribute_names to ActiveModel::Attributes This adds `.attribute_names` and `#attribute_names` to `ActiveModel::Attributes` along the same lines as the corresponding methods in `ActiveRecord::AttributeMethods` (see [`.attribute_names`][class_method] and [`#attribute_names`][instance_method]. While I was here I also added documentation for '#attributes', which I added in 043ce35b186. The whole class is still `#:nodoc:` so I don't think this will have any effect for now. [class_method]: https://github.com/rails/rails/blob/cc834db1d0815744cfa173813c05d928e008e167/activerecord/lib/active_record/attribute_methods.rb#L154-L160 [instance_method]: https://github.com/rails/rails/blob/cc834db1d0815744cfa173813c05d928e008e167/activerecord/lib/active_record/attribute_methods.rb#L299-L301 --- activemodel/lib/active_model/attributes.rb | 44 ++++++++++++++++++++++ activemodel/test/cases/attributes_test.rb | 14 +++++++ 2 files changed, 58 insertions(+) diff --git a/activemodel/lib/active_model/attributes.rb b/activemodel/lib/active_model/attributes.rb index b7b2f35bcc..6048ff0113 100644 --- a/activemodel/lib/active_model/attributes.rb +++ b/activemodel/lib/active_model/attributes.rb @@ -26,6 +26,21 @@ module ActiveModel define_attribute_method(name) end + # Returns an array of attribute names as strings + # + # class Person + # include ActiveModel::Attributes + # + # attribute :name, :string + # attribute :age, :integer + # end + # + # Person.attribute_names + # # => ["name", "age"] + def attribute_names + attribute_types.keys + end + private def define_method_attribute=(name) @@ -65,10 +80,39 @@ module ActiveModel super end + # Returns a hash of all the attributes with their names as keys and the values of the attributes as values. + # + # class Person + # include ActiveModel::Model + # include ActiveModel::Attributes + # + # attribute :name, :string + # attribute :age, :integer + # end + # + # person = Person.new(name: 'Francesco', age: 22) + # person.attributes + # # => {"name"=>"Francesco", "age"=>22} def attributes @attributes.to_hash end + # Returns an array of attribute names as strings + # + # class Person + # include ActiveModel::Attributes + # + # attribute :name, :string + # attribute :age, :integer + # end + # + # person = Person.new + # person.attribute_names + # # => ["name", "age"] + def attribute_names + @attributes.keys + end + private def write_attribute(attr_name, value) diff --git a/activemodel/test/cases/attributes_test.rb b/activemodel/test/cases/attributes_test.rb index 5483fb101d..af0ddcb92f 100644 --- a/activemodel/test/cases/attributes_test.rb +++ b/activemodel/test/cases/attributes_test.rb @@ -67,6 +67,20 @@ module ActiveModel assert_equal expected_attributes, data.attributes end + test "reading attribute names" do + names = [ + "integer_field", + "string_field", + "decimal_field", + "string_with_default", + "date_field", + "boolean_field" + ] + + assert_equal names, ModelForAttributesTest.attribute_names + assert_equal names, ModelForAttributesTest.new.attribute_names + end + test "nonexistent attribute" do assert_raise ActiveModel::UnknownAttributeError do ModelForAttributesTest.new(nonexistent: "nonexistent")