Skip to content

Commit

Permalink
* Add ActiveModel::Attributes#==.
Browse files Browse the repository at this point in the history
I want to be able to compare identity checks with == method.
Because I want to compare attribute identities,
but currently I have to go through the attribute method.

I wanted to use AttributeSet#== for the comparison to avoid creating
unnecessary objects, but since it does not return true if the value
before type cast are different, I used Attributes#attributes instead.

```ruby
# before
UserModel.new(id: 1) == UserModel.new(id: 1) # false

# after
UserModel.new(id: 1) == UserModel.new(id: 1) # true
```

*aaasa*
  • Loading branch information
bonobono555 committed Nov 21, 2022
1 parent 994bce4 commit 9b73de4
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 0 deletions.
20 changes: 20 additions & 0 deletions activemodel/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,23 @@
* Add ActiveModel::Attributes#==.

I want to be able to compare identity checks with == method.
Because I want to compare attribute identities,
but currently I have to go through the attribute method.

I wanted to use AttributeSet#== for the comparison to avoid creating
unnecessary objects, but since it does not return true if the value
before type cast are different, I used Attributes#attributes instead.

```ruby
# before
UserModel.new(id: 1) == UserModel.new(id: 1) # false

# after
UserModel.new(id: 1) == UserModel.new(id: 1) # true
```

*aaasa*

* Custom attribute types that inherit from Active Model built-in types and do
not override the `serialize` method will now benefit from an optimization
when serializing attribute values for the database.
Expand Down
8 changes: 8 additions & 0 deletions activemodel/lib/active_model/attributes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,14 @@ def freeze # :nodoc:
super
end

# Returns true if +comparison_object+ is the same exact object, or +comparison_object+
# is of the same type and +self+ and +comparison_object+ have the same attributes.
def ==(comparison_object)
super ||
comparison_object.instance_of?(self.class) &&
attributes == comparison_object.attributes
end

private
def _write_attribute(attr_name, value)
@attributes.write_from_user(attr_name, value)
Expand Down
33 changes: 33 additions & 0 deletions activemodel/test/cases/attributes_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,20 @@ def attribute=(_, _)
end
end

class ModelForEqualityTest
include ActiveModel::Model
include ActiveModel::Attributes

attribute :id, :integer
end

class ModelForInequalityTest
include ActiveModel::Model
include ActiveModel::Attributes

attribute :id, :integer
end

test "models that proxy attributes do not conflict with models with generated methods" do
ModelWithGeneratedAttributeMethods.new

Expand Down Expand Up @@ -175,5 +189,24 @@ def attribute=(_, _)
ModelForAttributesTest.attribute :foo, :unknown
end
end

test "equality" do
a = ModelForEqualityTest.new
assert_equal(a, a)
assert_equal(a, ModelForEqualityTest.new)

b = ModelForEqualityTest.new(id: 1)
assert_equal(b, ModelForEqualityTest.new(id: 1))
assert_equal(b, ModelForEqualityTest.new(id: "1"))
end

test "inequality" do
a = ModelForEqualityTest.new(id: 1)
b = ModelForEqualityTest.new(id: 2)
c = ModelForInequalityTest.new(id: 2)

assert_not_equal(a, b)
assert_not_equal(b, c)
end
end
end

0 comments on commit 9b73de4

Please sign in to comment.