Skip to content

Fix the leaking scope of `each_batch`

Mehmet Emin INAC requested to merge fix_each_batch_scope_leaking into master

What does this MR do?

This MR fixes the leaking scope problem of the each_batch method.

Since we are extending the class interface of our models with EachBatch::each_batch, calling each_batch on an instance of ActiveRecord::Relation ends up being handled by the ActiveRecord::Delegation::ClassSpecificRelation#method_missing, and this method preserves the current scope to allow chaining multiple scopes and class methods. Because of this, all the queries generated within the context of the block in each_batch are applied on top of the previous scope.

User.where(sign_in_count > 100).each_batch do |batch|
  ...
  do_something_unrelated(...)
  ...
end

def do_something_unrelated(...)
  User.where(id: 1) # applies both sign_in_count > 100 and id = 1 filters.
end

Possible solutions to this problem

  1. Move EachBatch to a non-autoloadable directory and include it to ActiveRecord::Relation
  2. Instead of including EachBatch to model, include it to Model.relation_delegate_class(ActiveRecord::Relation)(Danger: The relation_delegate_class method is part of the private API)
  3. Clear current_scope before yielding the relation to user given block

This MR fixes the problem by choosing the solution 3 from the above list.

Does this MR meet the acceptance criteria?

Conformity

Availability and Testing

Security

Does this MR contain changes to processing or storing of credentials or tokens, authorization and authentication methods or other items described in the security review guidelines? If not, then delete this Security section.

  • [-] Label as security and @ mention @gitlab-com/gl-security/appsec
  • [-] The MR includes necessary changes to maintain consistency between UI, API, email, or other methods
  • [-] Security reports checked/validated by a reviewer from the AppSec team
Edited by Mehmet Emin INAC

Merge request reports

Loading