Ruby on Rails is well-documented, but that means there’s a lot to go through. Of course you read all documentation for your languages, but just in case, here are some Ruby on Rails callbacks and relationship options that will cleanup, simplify, and clarify your code.
Technically, a “callback” is just executable code that is passed as an argument to a function. Ruby describes their callbacks as hooks into object life cycles, where a “hook” is a way to execute code before, after, or instead of existing code. Personally, I like the word choice of React — “lifecycle method.” These Ruby callbacks/hooks/lifecycle methods simplify code by telling X to always run before or after Y.
The most common callbacks are before_ and after_create, _initialize, _save, _update, and _destroy. See a complete list here. The callback before_destroy points out an important distinction between delete and destroy. If an object is removed via .delete, these callbacks are not called, but if it is removed via .destroy, these callbacks are called. Make sense? Destroy runs callbacks, delete does not. Think of “complete destruction,” because it completes the callbacks, but “complete deletion” doesn’t sound as cool, so it does not call those methods. Let’s take a closer look.
The next three examples do the same thing — they make sure the user’s email is lowercase before it’s saved.
The above syntax is very common. Just type “before_create” and then a space, a colon, and the name of the method. Make sure to define the method in the class (line 5).
In some cases, it might be more convenient to just write the function along with before_create using “do.”
All three methods work! Lastly, you can also add if statements to Ruby callbacks.
before_save :do_this_method, if: :this_method_returns_true
Pretty handy! Thanks, apidock.com!
Options for belongs_to
Similar to callbacks, ActiveRecord belongs_to options perform tasks at appropriate times in the object’s lifecycle.
The option dependent: can work very similarly to before_destroy above.
Here, we are telling the “choice” class that its objects must be removed when their user is removed — dependent: :destroy. Choices are destroyed with their users (but users are not destroyed with their choices, at least that we can see from this code). Referencing the discussion on destroy vs delete above, this will call the destroy callbacks for choices, as well.
The option :counter_cache keeps a running count of the number of objects in the relationship. If I wanted easy access to the number of choices my user has made, I would write
To work, this requires a column in “user” called “choices_count”. Otherwise, you can replace true with the column name. I had already made the column by the wrong name, so I thought it was easier to adjust to that.
belongs_to: :user, counter_cache: :choice_count
Note that this only increments the count and does not decrement upon deletion.
class_name & foreign_key
Lastly, you can rename relationships using :class_name and :foreign_key. This option works with belongs_to and has_many.
I needed to distinguish between foods that users have chosen (line 5) and foods that users have made (line 7). To make this distinction obvious to ActiveRecord, I refer to the latter as made_foods. Only foods that have the user’s ID in the user_id column are the user’s made_foods.
Ruby on Rails is amazing, and it’s even better when you know how to use it’s toolset well. So…
What are your favorite Ruby tools? Let us know in the comments!