ActiveRecord objects or their attributes often have to be displayed as text. And one specific attribute tends to particularly represent that model or it has to be output more frequently than other attributes. For example, the name of a product or the name of the user.
ActiveRecord default stringification
Since all class instances inherit all methods of Object in Ruby, each object also has a string interpretation. This applies to ActiveRecord too.
The model Person
rails g model Person name:string && rake db:migrate
is stringified by Object#to_s:
puts "Hello #{Person.first}"
# => "Hello #<Person:0x000000028bcf70>"
The person’s name output: Die Ausgabe des Namens der Person:
puts "Hello #{Person.first.name}"
# => "Hello Christian"
occurs quite often, compared to other attributes of Person, since every person feels addressed/ identified by the name.
Overwrite ActiveRecord#to_s
The standard implementation of ActiveRecord#to_s provides no value. Therefore, it is absolutely reasonable to overwrite #to_s if it makes sense:
class Person < ApplicationRecord
def to_s
name
end
end
The message to_s is always sent implicitly during the string interpolation:
puts "Hello #{Person.first}"
# => "Hello Christian"
The implicit string interpolation in the Ruby on Rails templates can also take advantage of the stringification:
# people/show.html.slim
.person = @person
// <div class="person">Christian</div>
The corresponding test:
require 'spec_helper.rb'
RSpec.describe Person, type: :model do
subject { Person.new name: 'Christian' }
describe '#to_s' do
it 'returns the name' do
expect(subject.to_s).to eq(subject.name)
end
end
end
Stringification through delegation
However, if there is no logic involved in the string representation of the object, overwriting by delegation is even more elegant:
class Person < ApplicationRecord
delegate :to_s, to: :name
end
Especially since there is a Shoulda Matcher, which makes the test more readable and concise:
require 'spec_helper.rb'
RSpec.describe Person, type: :model do
subject { Person.new name: 'Christian' }
it { is_expected.to delegate_method(:to_s).to(:name) }
end