Sometimes, we want to have our objects take a particular action at some point in their lifecycle. For example, we might want to capitalize the names of albums. While we could technically create a validation for this, users will find it really annoying if they have to resubmit the form until every word is capitalized. Instead, we can use a callback so our Rails application takes care of it for us. Let's add a callback to titleize album names.
Here's a test:
describe Album do
it("titleizes the name of an album") do
album = Album.create({name: "giant steps", genre: "jazz"})
expect(album.name()).to(eq("Giant Steps"))
end
end
It will fail as expected. Now let's write a callback to get the test passing:
class Album < ApplicationRecord
...
before_save(:titleize_album)
private
def titleize_album
self.name = self.name.titleize
end
end
We add a callback that states the method titleize_album
will be called before_save
. Callbacks are methods that get called at certain points of an object's life cycle, such as before it is saved or after it is deleted.
We make our titleize_album
method private
. Technically, this method would work fine even if it weren't private. However, we only want it to be called inside the Album
class. The whole point of this method is that it should only be used as a callback. By default, methods are public and we don't want this method to be used elsewhere. It's a best practice to make methods private if we don't want them to be called outside of the class. Before we move on, note that Ruby is so flexible that it's always possible to create a workaround to call a private method from outside a class. The point of private methods isn't to provide strict enforcement. Instead, we can use private methods to communicate our intentions to other developers and better encapsulate our code.
Our actual callback method is simple because Rails provides a titleize
method. This is not a Ruby method. It's an additional method that Rails provides to make our lives easier. However, this method is rudimentary and will capitalize all words in a phrase. A title_case
method like the one we created in section 1 of Ruby would be better here. Feel free to customize this callback in this way to make it more accurate.
One thing that may seem a bit confusing: why is a before before_save
callback being triggered by a test that calls the create
method? before_save
is actually a point in the object creation lifecycle. before_create
is also part of the object creation lifecycle, but it actually happens after before_save
. Read the documentation on the object lifecycle to learn more.
Check out the section on callbacks in the Rails Guide. Callbacks will be part of this section's independent project, but don't worry — only a basic understanding of callbacks and a simple method will be expected.
Lesson 18 of 34
Last updated August 7, 2022