Reason #65 • March 6th, 2026

Custom equality for custom classes

Yesterday we looked at how many of Ruby's built-in data structures consider two objects with the same content to be equal by default.

Instances of custom classes, on the other hand, are not considered equal by default:

Ruby
class Person
  attr_reader :name

  def initialize(name)
    @name = name
  end
end

Person.new("Alice") == Person.new("Alice")
# => false
    

However, we can define our own equality logic by overriding the #== method in our class:

Ruby
class Person
  attr_reader :name
  attr_reader :social_security_number

  def initialize(name, social_security_number)
    @name = name
    @social_security_number = social_security_number
  end

  def ==(other)
    other.is_a?(Person) && social_security_number == other.social_security_number
  end
end

Person.new("Alice Bacon", 1337) == Person.new("Alice Bacon", 1337)
# => true

# Alice got married and changed surname, but it's still the same person:
Person.new("Alice Bacon", 1337) == Person.new("Alice Pickles", 1337)
# => true

# No luck impersonating Alice with a different social security number:
Person.new("Alice Pickles", 1337) == Person.new("Alice Pickles", 1312)
# => false
    

This can be handy when equality has a specific meaning in the domain we're modeling. For example, in Rails's ORM, ActiveRecord, two records are considered equal if they have the same class and the same primary key because they represent the same row in the database.

Reason #66 ?