Skip to content

Pitfalls of using QueryObject pattern #41

@Galathius

Description

@Galathius

Hi folks! Thanks for your work on this gem.

QueryObject is a commonly used pattern in RoR community, and I noticed that everyone is re-implementing it similarly.
All realizations I saw were mostly designed to be used in ActiveRecord scopes definition:

class User < ApplicationRecord
  scope :active, Users::ActiveQuery
end

Using query objects in this way has quite unpleasant and hidden behavior – if you try to create some subqueries on User model inside of query object – it will be scoped to the "current" scope.

I've briefly described the problem itself here.

Also there are some instructions how to reproduce the issue with this gem:

# rails new pattern-gem-test && cd pattern-gem-test
# bundle add rails-patterns

# rails g model User name:string terminated:boolean manager_id:integer

# rails db:migrate

# app/models/user.rb
class User < ApplicationRecord
  belongs_to :manager, class_name: 'User', optional: true

  scope :with_terminated_manager, Users::WithTerminatedManagerQuery
end

# app/models/users/with_terminated_manager_query.rb
class Users::WithTerminatedManagerQuery < Patterns::Query
  queries User

  def query
    relation.where(manager: User.where(terminated: true))
  end
end

# Then by executing the scope this query:
User.where(name: 'Galalthius').with_terminated_manager
# SELECT "users".*
# FROM "users"
# WHERE "users"."name" = 'Galathius'       <---------- name condition
#   AND "users"."manager_id" IN
#     (SELECT "users"."id"
#      FROM "users"
#      WHERE "users"."name" = 'Galathius'  <---------- name condition
#        AND "users"."terminated" = TRUE)

So far I found the only workaround for this, is simply define scopes using lambdas, although this reduces readability:

  scope :with_terminated_manager, -> { Users::WithTerminatedManagerQuery.new(self).call }

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions