Has it ever happened to you that you use a concept in your preferred programming language without really understanding why you’re using it? Or what exactly it does? This recently happened to me when I was tasked with refactoring someone else’s code: I didn’t quite understand what Rails modules
were or what Helpers
were for. So, I took some time to study this and prepared this summary on what Rails Helpers are and what they are used for!
Organizing the party
In this post, I intend to cover, in the following order:
- A general explanation of what Rails Helper methods are and the best practices associated with them
- Delve into more details about Ruby Modules and their importance within the language
- Touch on the topic of Composition vs. Inheritance, which is always good to keep fresh in mind
What are Helpers in Rails?
Helpers are methods primarily used to share reusable code between the views in your project. It's important to note that Helpers don't necessarily need to be created by developers: there are already some native methods provided by Rails to make our lives easier.
Examples of native Rails Helpers:
time_ago_in_words(Time.now)
# "less than a minute"
number_to_human(10_000)
# "10 Thousand"
Helper methods are also very important when created by programmers themselves, as they help apply the DRY principle within the project's code. By doing so, you condense a portion of the logic into a single place instead of having it scattered across various parts of the code.
Writing Your Own Helpers
There is a specific directory for creating your own Helpers in Rails, which is the app/helpers
directory. Inside this folder, you need to create a new file and, within a module
, develop what you need. Everything inside it automatically becomes visible to the views
in your project.
For example: we went to app/helpers
and created the file user_helper.rb
, which will contain all our user-related helpers. Inside it, we will build the following module
:
module UserHelper
def format_name(user)
if user.gender == "M"
"Mr. #{user.name}"
else
"Mrs. #{user.name}"
end
end
end
There is also a generic option, useful if your application is small and you need only a few Helpers, for example, which is to put everything inside the ApplicationHelper
. This is a base module in Rails, ready to receive any future helpers you develop.
Best Practices for Using Helpers
When should you use and/or create a helper?
Whenever you have reusable logic that produces HTML code. Most of the time, this involves code related to string formatting or view
elements that are conditional. It's a good idea to encapsulate this logic within a helper to avoid having it scattered and repeated throughout your application.
Use and abuse of parameters
It's a way to clearly specify from the beginning what your method needs, reducing the risk of encountering errors related to missing variables while working with information within your helper.
Try not to use helpers in Controllers
Some developers believe in the concept of Controller Helpers, which are helpers more focused on logic rather than presentation. It's also possible to use view helpers directly in controllers by invoking them with the helpers
object. For example:
class UsersController
def index
helpers.time_ago_in_words(Time.now)
end
end
RubyGuides advises caution when doing this, as it can be considered a design problem, suggesting the use of a Ruby object instead, although it doesn't provide further details on why. I also think it's worth noting this warning, and when in doubt, keep helpers confined to views, OK?
What are Ruby Modules?
Throughout this article, I've talked a lot about Ruby modules and how important they are when writing helpers. Then I realized that I didn't know what the heck a Ruby module was. So, I did some research and am sharing this important extra bit on what it is and what this useful little keyword is for.
A module is a Ruby container used to store methods, variables, and constants. It's similar to a class, but unlike a class, a module cannot be instantiated. It's somewhat similar to the concept of static in .NET.
Modules have two main purposes in Ruby:
- Creating a namespace, that is, grouping logically related objects together, which also helps avoid name conflicts
- Facilitating composition within your application
Ruby, as a programming language, does not support multiple inheritance. Therefore, to keep the code scalable and maintainable in the long run, it is necessary to apply the principle of Composition Over Inheritance. Fortunately, Ruby makes composition easier by offering what is called the Mixing Facility.
The Mixing Facility is simply a module being included by another module, or even by another class, using keywords like include
, prepend
, or extend
.
Composition vs. Inheritance
Ah, the age-old dilemma for those who program in object-oriented languages and for a paycheck. This debate is present from the earliest stages of learning to the most seasoned seniors. Precisely because it’s so prevalent in our daily work, I think it’s important to revisit the definitions of these two concepts, especially since it’s already explained above why one is more important for Rails. I’m also leaving a link to a well-detailed DevMedia article (in PT-BR) that explains the importance of each and when to use them (spoiler: most of the time, it’s not Inheritance).
Inheritance
Inheritance in programming is defined by the existence of a parent class (also known as a base class or superclass) and a child class (or subclass), and it is considered a fundamental tool for extending and reusing functionalities. In this principle, we focus heavily on the generalization of concepts: similarities between classes are placed in the parent class, while all specific business logic is placed in the child class.
In this concept, there is a strong coupling between classes, as one class depends on the other throughout the system.
Composition
In Composition, we define small behaviors that will exist between classes, which are standardized. As our classes are created and evolve, we compose more complex behaviors using these small units of behavior that have already been designed and tested. Here, the emphasis is on encapsulating logic, which is always a good practice.
🪡 Revisions and Corrections
May 30, 2023 – I corrected some parts of the text that mistakenly stated that modules
belong to Rails, when they actually belong to Ruby itself. Thanks to Sérgio Ribeiro for the heads up! 😀
✔ Links consulted
♥ RubyGuides: How to Use Rails Helpers (Complete Guide) – by Jesus Castello
★ Helper Methods – by Damely Tineo
♥ Modules in Ruby: Part I – by RubyCademy
★ DevMedia: Herança versus Composição: qual utilizar? – by Higor
Last accessed on April 2, 2023.
📩 A Last Message
Did you like the text? Do you have anything to add? Any constructive criticism? Feedback? Suggestions? Requests? Feel free to contact me via email (oli.pmatt@gmail.com), LinkedIn (/in/oliviamattiazzo) or through the comments section below! I’d be delighted to chat with you! ✨
You can also check the original post (in PT-BR) at my blog: oliviamattiazzo.dev
🪪 Credits
The icons used to illustrate this post came from the following IconFinder users:
Top comments (0)