Avoid eager loading in Relation#pretty_print

We mimic the behaviour used with `#inspect`, only fetching up to 11
elements if records are not loaded already.

Here's the reproduction:

```
require "activerecord"

ActiveRecord::Base.establish_connection YOUR_DB_URL_THERE

ActiveRecord::Migration.new.tap do |m|
  m.create_table :foos do |t|
    t.text :name
  end
end

class Foo < ActiveRecord::Base
end

100.times { Foo.create(name: "foo#{_1}") }

pp Foo.all # loads the whole table.
```

Signed-off-by: Ulysse Buonomo <buonomo.ulysse@gmail.com>
This commit is contained in:
Ulysse Buonomo 2021-09-24 09:46:54 +02:00
parent 2b05b25809
commit 546de0f6c6
3 changed files with 48 additions and 2 deletions

View File

@ -1,3 +1,15 @@
* Avoid loading every records in `ActiveRecord::Relation#pretty_print`
```ruby
# Before
pp Foo.all # Loads the whole table.
# After
pp Foo.all # Shows 10 items and an ellipsis.
```
*Ulysse Buonomo*
* Change `QueryMethods#in_order_of` to drop records not listed in values.
`in_order_of` now filters down to the values provided, to match the behavior of the `Enumerable` version.

View File

@ -773,8 +773,13 @@ module ActiveRecord
end
end
def pretty_print(q)
q.pp(records)
def pretty_print(pp)
subject = loaded? ? records : annotate("loading for pp")
entries = subject.take([limit_value, 11].compact.min)
entries[10] = "..." if entries.size == 11
pp.pp(entries)
end
# Returns true if relation is blank.

View File

@ -2021,6 +2021,35 @@ class RelationTest < ActiveRecord::TestCase
end
end
test "relations limit the records in #pretty_print at 10" do
relation = Post.limit(11)
out = StringIO.new
PP.pp(relation, out)
assert_equal 10, out.string.scan(/#<\w*Post:/).size
assert out.string.end_with?("\"...\"]\n"), "Did not end with an ellipsis."
end
test "relations don't load all records in #pretty_print" do
assert_sql(/LIMIT|ROWNUM <=|FETCH FIRST/) do
PP.pp Post.all, StringIO.new # avoid outputting.
end
end
test "loading query is annotated in #pretty_print" do
assert_sql(%r(/\* loading for pp \*/)) do
PP.pp Post.all, StringIO.new # avoid outputting.
end
end
test "already-loaded relations don't perform a new query in #pretty_print" do
relation = Post.limit(2)
relation.to_a
assert_no_queries do
PP.pp relation, StringIO.new # avoid outputting.
end
end
test "using a custom table affects the wheres" do
post = posts(:welcome)