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:
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.
Using that until one of the two changes lands in a release:
class ApplicationRecord < ActiveRecord::Base
primary_abstract_class
# Copied from Rails Core, until maybe https://github.com/rails/rails/pull/45122 lands
# Solution inspired by https://discuss.rubyonrails.org/t/add-attribute-for-pretty-print-method-to-activerecord/81741
unless Object.const_defined?("ActiveSupport::Inspect")
def attribute_for_pretty_print(attr_name)
return "<BINARY VALUE>" if self.class.type_for_attribute(attr_name).type == :binary
_read_attribute(attr_name)
end
def pretty_print(pp)
return super if custom_inspect_method_defined?
pp.object_address_group(self) do
if defined?(@attributes) && @attributes
attr_names = self.class.attribute_names.select { |name| _has_attribute?(name) }
pp.seplist(attr_names, proc { pp.text "," }) do |attr_name|
pp.breakable " "
pp.group(1) do
pp.text attr_name
pp.text ":"
pp.breakable
value = attribute_for_pretty_print(attr_name) # this has been changed to create a hook
value = inspection_filter.filter_param(attr_name, value) unless value.nil?
pp.pp value
end
end
else
pp.breakable " "
pp.text "not initialized"
end
end
end
end
end