Add "attribute_for_pretty_print" method to ActiveRecord

I’d like to to improve output of records in a Rails console when some of the fields have very long values.

As of IRB version 1.3.1 (release in Jan 2021) records are pretty_printed in the console instead of inspected, so records with large values (e.g. the content of a document) look like this:

This makes it hard to navigate output in a console. Especially for arrays of items like this.

Another option is to override inspect (or attribute_for_inspect), but the output of inspect is not nearly as nice as the pretty-print output:

It would be great to:

  1. Provide a better default for long strings
  2. Provide a method that can be overridden in applications for customizing the display of fields

Would adding something like the following be OK? I can make a PR if so.

diff --git a/activerecord/lib/active_record/attribute_methods.rb b/activerecord/lib/active_record/attribute_methods.rb
index 4dc57d6eea..f0f9b55d36 100644
--- a/activerecord/lib/active_record/attribute_methods.rb
+++ b/activerecord/lib/active_record/attribute_methods.rb
@@ -288,6 +288,15 @@ def attribute_for_inspect(attr_name)
     def attribute_for_inspect(attr_name)
       attr_name = attr_name.to_s
       attr_name = self.class.attribute_aliases[attr_name] || attr_name
       value = _read_attribute(attr_name)
       format_for_inspect(attr_name, value)
+    def attribute_for_pretty_print(attr_name)
+      value = _read_attribute(attr_name)
+      if value.is_a?(String) && value.length > 50
+        "#{value[0, 50]}..."
+      else
+        value
+      end
+    end
diff --git a/activerecord/lib/active_record/core.rb b/activerecord/lib/active_record/core.rb
index d2fc5fa711..ab7a2a08ee 100644
--- a/activerecord/lib/active_record/core.rb
+++ b/activerecord/lib/active_record/core.rb
@@ -698,7 +698,7 @@ def pretty_print(pp)
               pp.text attr_name
               pp.text ":"
-              value = _read_attribute(attr_name)
+              value = attribute_for_pretty_print(attr_name)
               value = inspection_filter.filter_param(attr_name, value) unless value.nil?
               pp.pp value
1 Like

The intention definitely makes sense but I personally don’t think having this in Rails core is the way to go. Have you considered using something like Pry-rails?

IMO it would make sense for Rails to provide a good experience for this out of the box. Storing long values in a field is a perfectly reasonable thing to do, and having it behave well in the console is a reasonable expectation. In fact, Rails already does this for inspect, but IRB has changed so that “inspect” isn’t used by default, as of IRB version 1.3.1, which was released in January of last year.

Even if Rails itself doesn’t customize the actual output of (i.e. if it doesn’t do any truncating, etc) it would be helpful if Rails would at least provide an extension point where applications or libraries could customize this. E.g. even if just def attribute_for_pretty_print(attr_name); _read_attribute(attr_name) end was provided, then applications or libraries could override that. The only option right now is to either override inspect and lose the nice pretty printing entirely, or to reimplement all of ActiveRecord::Core#pretty_print, which doesn’t seem very maintainable.