Rails 7.1 adds support for Array#intersect? to ActiveRecord::Relation
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.