Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 7 additions & 3 deletions lib/active_model/entity/attribute.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,14 @@

# Patch for ActiveModel::Type::Value
ActiveModel::Type::Value.class_eval do
# Add alias to `cast` method for casting JSON values in ActiveModel::Attribute::FromJSON class
alias_method :cast_json, :cast
# Add wrapper to `cast` method for casting JSON values in ActiveModel::Attribute::FromJSON class
def cast_json(value)
value = value.to_unsafe_h if value.is_a?(ActionController::Parameters)

# Serialize value with options, for base ActiveModel::Type::* classes it will delegates to serialize
cast(value)
end

# Serialize value with options, for base ActiveModel::Type::* classes it will call `serialize`
def serialize_with_options(value, _options = {})
serialize(value)
end
Expand Down
4 changes: 2 additions & 2 deletions lib/active_model/entity/equality.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,15 @@ module Equality
extend ActiveSupport::Concern

def eql?(other)
attributes.eql?(other.attributes)
attributes.as_json.eql?(other.attributes.as_json)
end

def ==(other)
eql?(other)
end

def hash
[self.class, *attributes.keys, *attributes.keys].hash
[self.class, *attributes.keys, *attributes.values].hash

Copilot AI Jul 7, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The hash method uses attributes.keys and attributes.values in insertion order, which may lead to inconsistent hash values for logically equal objects if key ordering differs. Consider sorting the keys and pairing each key with its corresponding value to ensure a stable hash for equal attribute sets.

Suggested change
[self.class, *attributes.keys, *attributes.values].hash
sorted_attributes = attributes.keys.sort.map { |key| [key, attributes[key]] }
[self.class, *sorted_attributes].hash

Copilot uses AI. Check for mistakes.
end
end
end
Expand Down
5 changes: 5 additions & 0 deletions spec/active_model/entity/parsers/json_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,11 @@ class Person
field_integers: [1, 3, 7]
})
end

it "converts ActionController::Parameters to hash" do
person = ParsersTest::Person.from_json(source)
expect(person.field_obj).to eq({ "x" => 1 })
end
end

context "parsing json" do
Expand Down