Rails helpers are modules that contain methods designed to make your views cleaner and more maintainable. They help you extract complex logic from views and create reusable components that follow the DRY (Don't Repeat Yourself) principle.
What Are Rails Helpers?
Helpers are Ruby modules that contain methods available in your views. They're automatically included in all views and can contain presentation logic, formatting methods, and reusable view components.
Default Helper Structure
Rails automatically generates a helper file for each controller:
# app/helpers/application_helper.rb
module ApplicationHelper
# Methods here are available in all views
end
# app/helpers/users_helper.rb
module UsersHelper
# Methods here are available in users views
end
Essential Helper Patterns
1. Formatting Helpers
Create helpers for common formatting tasks:
# app/helpers/application_helper.rb
module ApplicationHelper
def format_currency(amount)
number_to_currency(amount, unit: "$", precision: 2)
end
def format_date(date)
return "Not set" if date.blank?
date.strftime("%B %d, %Y")
end
def truncate_text(text, length = 100)
return "" if text.blank?
truncate(text, length: length, omission: "...")
end
end
Usage in views:
erb
<%= format_currency(@product.price) %>
<%= format_date(@event.start_date) %>
<%= truncate_text(@article.content, 150) %>
2. Conditional Display Helpers
Handle complex display logic:
module ApplicationHelper
def display_user_status(user)
if user.active?
content_tag :span, "Active", class: "badge badge-success"
else
content_tag :span, "Inactive", class: "badge badge-danger"
end
end
def show_edit_link?(record, current_user)
current_user&.admin? || record.user == current_user
end
end
3. Navigation Helpers
Create dynamic navigation:
module ApplicationHelper
def nav_link_class(controller_name)
"nav-link #{'active' if controller_name == controller.controller_name}"
end
def breadcrumb_trail(*links)
content_tag :nav, class: "breadcrumb" do
links.map.with_index do |link, index|
if index == links.length - 1
content_tag :span, link[:text], class: "breadcrumb-item active"
else
content_tag(:span, class: "breadcrumb-item") do
link_to link[:text], link[:path]
end
end
end.join.html_safe
end
end
end
Usage:
erb
<%= breadcrumb_trail(
{ text: "Home", path: root_path },
{ text: "Products", path: products_path },
{ text: @product.name, path: "#" }
) %>
4. Form Helpers
Simplify form creation:
module ApplicationHelper
def form_group_for(form, field, options = {})
content_tag :div, class: "form-group" do
concat form.label(field, class: "form-label")
case options[:type]
when :textarea
concat form.text_area(field, class: "form-control", rows: options[:rows] || 3)
when :select
concat form.select(field, options[:choices], {}, class: "form-control")
else
concat form.text_field(field, class: "form-control")
end
if form.object.errors[field].any?
concat content_tag(:div, form.object.errors[field].first, class: "text-danger")
end
end
end
def submit_button_text(object)
object.persisted? ? "Update #{object.class.name}" : "Create #{object.class.name}"
end
end
5. Asset and Media Helpers
Handle images and assets:
module ApplicationHelper
def user_avatar(user, size: 40)
if user.avatar.present?
image_tag user.avatar,
class: "rounded-circle",
size: "#{size}x#{size}",
alt: "#{user.name}'s avatar"
else
content_tag :div, user.initials,
class: "avatar-placeholder rounded-circle",
style: "width: #{size}px; height: #{size}px; line-height: #{size}px;"
end
end
def fallback_image(primary_image, fallback_path = "placeholder.png")
primary_image.present? ? primary_image : asset_path(fallback_path)
end
end
Advanced Helper Techniques
1. Block Helpers
Create helpers that accept blocks:
module ApplicationHelper
def card(title = nil, &block)
content_tag :div, class: "card" do
card_content = ""
if title
card_content += content_tag(:div, class: "card-header") do
content_tag :h5, title, class: "card-title"
end
end
card_content += content_tag(:div, class: "card-body", &block)
card_content.html_safe
end
end
def alert_box(type = :info, &block)
css_class = "alert alert-#{type}"
content_tag :div, class: css_class, role: "alert", &block
end
end
Usage:
```erb
<%= card "User Information" do %>
Name: <%= @user.name %>
Email: <%= @user.email %>
<% end %>
<%= alert_box :success do %>
Your profile has been updated successfully!
<% end %>
```
2. Configuration Helpers
Create configurable helpers:
module ApplicationHelper
def page_title(title = nil)
base_title = "MyApp"
if title.nil?
base_title
else
"#{title} | #{base_title}"
end
end
def meta_description(description = nil)
default_description = "MyApp - The best app for managing your tasks"
description || default_description
end
end
3. Helper Classes
For complex logic, create helper classes:
# app/helpers/table_helper.rb
module TableHelper
def sortable_table_header(column, title = nil)
title ||= column.titleize
direction = column == sort_column && sort_direction == "asc" ? "desc" : "asc"
link_to title, { sort: column, direction: direction },
class: "sortable-header #{sort_indicator(column)}"
end
private
def sort_column
params[:sort] || "created_at"
end
def sort_direction
params[:direction] || "desc"
end
def sort_indicator(column)
return "" unless column == sort_column
sort_direction == "asc" ? "sort-asc" : "sort-desc"
end
end
Testing Helpers
Always test your helpers:
# test/helpers/application_helper_test.rb
require "test_helper"
class ApplicationHelperTest < ActionView::TestCase
test "format_currency returns formatted string" do
assert_equal "$19.99", format_currency(19.99)
assert_equal "$1,299.00", format_currency(1299)
end
test "format_date handles nil values" do
assert_equal "Not set", format_date(nil)
assert_equal "Not set", format_date("")
end
test "user_avatar returns image when avatar present" do
user = users(:john)
user.avatar = "avatar.jpg"
result = user_avatar(user)
assert_includes result, "avatar.jpg"
assert_includes result, "rounded-circle"
end
test "display_user_status shows correct badge" do
active_user = users(:active_user)
inactive_user = users(:inactive_user)
assert_includes display_user_status(active_user), "badge-success"
assert_includes display_user_status(inactive_user), "badge-danger"
end
end
Best Practices for Rails Helpers
1. Keep Helpers Simple
- Each helper method should have one clear responsibility
- Complex logic should be moved to service objects or model methods
2. Use Semantic Naming
# Good
def user_display_name(user)
def format_price(amount)
def highlight_search_term(text, term)
# Avoid
def process_user(user)
def handle_data(data)
def do_something(params)
3. Handle Edge Cases
def safe_format_date(date)
return "No date" if date.blank?
return "Invalid date" unless date.respond_to?(:strftime)
date.strftime("%B %d, %Y")
rescue
"Invalid date"
end
4. Make Helpers Configurable
def status_badge(status, options = {})
color_map = options[:color_map] || {
active: "success",
pending: "warning",
inactive: "danger"
}
css_class = "badge badge-#{color_map[status.to_sym] || 'secondary'}"
content_tag :span, status.humanize, class: css_class
end
5. Use Rails Helper Methods
Leverage built-in Rails helpers:
- content_tag
for generating HTML
- link_to
, image_tag
for common elements
- number_to_currency
, distance_of_time_in_words
for formatting
- truncate
, highlight
for text manipulation
Common Helper Examples for Beginners
User-Friendly Timestamps
def friendly_timestamp(timestamp)
return "Never" if timestamp.blank?
if timestamp > 1.day.ago
"#{time_ago_in_words(timestamp)} ago"
else
timestamp.strftime("%B %d, %Y")
end
end
Conditional CSS Classes
def css_class_if(condition, css_class)
css_class if condition
end
def status_class(record)
base_class = "status"
modifier = record.active? ? "active" : "inactive"
"#{base_class} #{base_class}--#{modifier}"
end
Simple Icon Helper
def icon(name, options = {})
css_class = "icon icon-#{name}"
css_class += " #{options[:class]}" if options[:class]
content_tag :i, "", class: css_class, "aria-hidden": true
end
Rails helpers are powerful tools for keeping your views clean and maintainable. Start with simple formatting helpers and gradually build more complex ones as your application grows. Remember to test your helpers and keep them focused on presentation logic rather than business logic.