Rails 7.1 adds support for Array#intersect? to ActiveRecord::Relation

railsAugust 22, 2023Dotby Alkesh Ghorpade

In Ruby 3.1, a new method called Array#intersect? was added. This method returns true if two arrays have at least one element in common and false otherwise. Which method is helpful for cases where you only need to know whether two arrays have any common elements, and you don't need to get the intersection of the arrays.

The intersect? method works as below on Arrays.

a = [1, 2, 3]
b = [2, 3, 5, 7]
c = [4, 7, 9]

a.intersect?(b)
=> true

a.intersect?(c)
=> false

Before Rails 7.1

Before Rails 7.1, the intersect? method was not defined for ActiveRecord::Relation objects. This meant that if you tried to use the intersect? method on an ActiveRecord::Relation object, you would get the following error:

users1 = User.where(id: [1, 2, 3])
=> [#<User id: 1, email:.......>, #<User id: 2, email:.......>, #<User id: 3, email:.......>]

users2 = User.where(id: [2, 4, 5])
=> [#<User id: 2, email:.......>, #<User id: 4, email:.......>, #<User id: 5, email:.......>]

users1.intersect?(users2)

NoMethodError: undefined method `intersect?' for #<ActiveRecord::Relation....

To check if two ActiveRecord relation objects have any common elements, you had to chain the & (intersection) method with the any? or empty? methods.

For example:

users1 = User.where(id: [1, 2, 3])
=> [#<User id: 1, email:.......>, #<User id: 2, email:.......>, #<User id: 3, email:.......>]

users2 = User.where(id: [2, 4, 5])
=> [#<User id: 2, email:.......>, #<User id: 4, email:.......>, #<User id: 5, email:.......>]

users1 & users2
=> [#<User id: 2, email:.......>]

(users1 & users2).any?
=> true

(users1 & users2).empty?
=> false

This approach first computes the intersection, which stores the result in memory and then evaluates the #any? or #empty? on the result.

In Rails 7.1

Rails 7.1 added support for the Array#intersect? method to ActiveRecord::Relation objects. This means that you can now use the intersect? method to check if two ActiveRecord relation objects have any common elements.

The intersect? method is a concise and efficient way to check for common elements in two ActiveRecord relation objects. It is also memory-efficient, as it does not compute the intersection of the two relations before checking for common elements.

users1 = User.where(id: [1, 2, 3])
=> [#<User id: 1, email:.......>, #<User id: 2, email:.......>, #<User id: 3, email:.......>]

users2 = User.where(id: [2, 4, 5])
=> [#<User id: 2, email:.......>, #<User id: 4, email:.......>, #<User id: 5, email:.......>]

users1.intersect?(users2)
=> true

Note:

You cannot pass multiple ActiveRecord::Relation objects to the #intersect method.

users1 = User.where(id: [1, 2, 3])
=> [#<User id: 1, email:.......>, #<User id: 2, email:.......>, #<User id: 3, email:.......>]

users2 = User.where(id: [2, 4, 5])
=> [#<User id: 2, email:.......>, #<User id: 4, email:.......>, #<User id: 5, email:.......>]

users3 = User.where(id: [3, 8, 4])
=> [#<User id: 3, email:.......>, #<User id: 8, email:.......>, #<User id: 4, email:.......>]

users1.intersect?(users2, users3)
=> ArgumentError (wrong number of arguments (given 2, expected 1))

To know more about this feature, please refer to this PR.

Closing Remark

Could your team use some help with topics like this and others covered by ShakaCode's blog and open source? We specialize in optimizing Rails applications, especially those with advanced JavaScript frontends, like React. We can also help you optimize your CI processes with lower costs and faster, more reliable tests. Scraping web data and lowering infrastructure costs are two other areas of specialization. Feel free to reach out to ShakaCode's CEO, Justin Gordon, at justin@shakacode.com or schedule an appointment to discuss how ShakaCode can help your project!
Are you looking for a software development partner who can
develop modern, high-performance web apps and sites?
See what we've doneArrow right