September 15, 2021
This blog is part of our Rails 7 series.
ActiveRecord is
one of the most powerful features in Rails. With ActiveRecord
we can easily
query and handle database objects without writing any SQL.
By using ActiveRecord Query Interface
, we can perform various query operations
like Joins
, Group
, Find
, Order
. We can also chain relations with
where
, and
, or
, not
but for and
or or
the two chaining relations
must be structurally compatible.
For any two relations to be
Structurally Compatible
they must be scoping the same model, and they must differ only by the where
clause when no group
clause has been defined. If a group
clause is present
then the relations must differ by the having
clause. Also, Neither relation
may use a limit
, offset
, or distinct
method.
Previously for and
or or
query methods, we needed to make sure that the two
relations are structurally compatible otherwise ActiveRecord
would raise an
error.
However,
Rails 7 has added ActiveRecord::Relation#structurally_compatible?
which provides a method to easily tell if two relations are structurally
compatible. We can use this method before we run and
or or
query methods on
any two relations.
Let's assume we have two models Blog
and Post
with the following relations
# app/models/blog.rb
class Blog < ApplicationRecord
has_many :posts
end
# app/models/post.rb
class Post < ApplicationRecord
belongs_to :blog
end
If we run or
query between incompatible relations we would get an
ArgumentError.
relation_1 = Blog.where(name: 'bigbinary blog')
relation_2 = Blog.joins(:posts).where(posts: { user_id: current_user.id})
begin
relation_1.or(relation_2)
rescue ArgumentError
# Rescue ArgumentError
end
We can check the structural compatibility of the two relations.
relation_1 = Blog.where(name: 'bigbinary blog')
relation_2 = Blog.where(user_id: current_user.id)
if relation_1.structurally_compatible?(relation_2) # returns true
relation_1.or(relation_2)
end
Check out this pull request for more details.
If this blog was helpful, check out our full blog archive.