Skip to content

Fix Relation#load to return self instead of an Array - #267

Merged
degwinthegreat merged 2 commits into
kufu:masterfrom
degwinthegreat:fix-relation-load-return-value
Jul 9, 2026
Merged

degwinthegreat merged 2 commits into
kufu:masterfrom
degwinthegreat:fix-relation-load-return-value

Conversation

@degwinthegreat

Copy link
Copy Markdown
Contributor

Problem

ActiveRecord::Relation#load is expected to return the relation itself (self), not the records:

https://github.com/rails/rails/blob/v8.1.3/activerecord/lib/active_record/relation.rb#L1193-L1206

# Causes the records to be loaded from the database if they have not
# been loaded already. You can use this if for some reason you need
# to explicitly load some records before actually using them. The
# return value is the relation itself, not the records.
#
#   Post.where(published: true).load # => #<ActiveRecord::Relation>
def load(&block)
  if !loaded? || scheduled?
    @records = exec_queries(&block)
    @loaded = true
  end

  self
end

Employee.all.load                     #=> Employee::ActiveRecord_Relation
Employee.valid_at(Time.current).load  #=> Array

However, the bitemporal override of #load ended with records.each. Since Relation#each is delegated to records (the loaded Array) by ActiveRecord::Delegation, records.each returns the Array — which leaked out as the return value of #load when valid_datetime or transaction_datetime is set:

https://github.com/rails/rails/blob/v8.1.3/activerecord/lib/active_record/relation/delegation.rb#L100-L103

delegate :to_xml, :encode_with, :length, :each, :join, :intersect?,
         :[], :&, :|, :+, :-, :sample, :reverse, :rotate, :compact, :in_groups, :in_groups_of,
         :to_sentence, :to_fs, :to_formatted_s, :as_json,
         :shuffle, :split, :slice, :index, :rindex, to: :records

Fix

Return records (the relation returned by super) at the end of #load, matching Active Record's contract that load returns self.

🤖 Generated with Claude Code

ActiveRecord::Relation#load is expected to return the relation itself,
but the bitemporal override ended with `records.each`, whose return
value (the records Array) leaked out when valid_datetime or
transaction_datetime is set, e.g. `Employee.valid_at(time).load`.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The variable holds the relation itself returned by `super`
(Relation#load returns self), not an array of records. Renaming it
clarifies that #load returns the relation, as suggested in the PR
review.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

@kymmt90 kymmt90 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

@degwinthegreat
degwinthegreat merged commit 2b3a926 into kufu:master Jul 9, 2026
20 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants