Skip
Arish's avatar

39. View Helpers


View Helpers

View helpers are methods available in your views that help format data, generate URLs, create form elements, and more. Rails provides many built-in helpers, and you can create your own.

URL Helpers

erb
1<!-- Link helpers -->
2<%= link_to "Home", root_path %>
3<%= link_to "Article", @article %>
4<%= link_to "Edit", edit_article_path(@article) %>
5<%= link_to "Delete", @article, method: :delete, data: { confirm: "Are you sure?" } %>
6
7<!-- With classes -->
8<%= link_to "Articles", articles_path, class: "btn btn-primary" %>
9
10<!-- With block for complex content -->
11<%= link_to @article do %>
12  <h3><%= @article.title %></h3>
13  <span><%= @article.author.name %></span>
14<% end %>
15
16<!-- URL helpers (without link) -->
17<%= article_path(@article) %>     <!-- /articles/1 -->
18<%= article_url(@article) %>      <!-- http://example.com/articles/1 -->
19<%= new_article_path %>           <!-- /articles/new -->
20<%= edit_article_path(@article) %> <!-- /articles/1/edit -->
21
22<!-- Button to (creates a form) -->
23<%= button_to "Delete", @article, method: :delete %>
24<%= button_to "Subscribe", subscribe_path, method: :post %>

Text Helpers

erb
1<!-- Truncate -->
2<%= truncate(@article.body, length: 100) %>
3<%= truncate(@article.body, length: 100, separator: ' ') %>
4<%= truncate(@article.body, length: 100, omission: '... (more)') %>
5
6<!-- Simple format (converts newlines to <br> and paragraphs) -->
7<%= simple_format(@article.body) %>
8
9<!-- Pluralize -->
10<%= pluralize(@articles.count, 'article') %>
11<!-- "5 articles" or "1 article" -->
12
13<!-- Highlight -->
14<%= highlight(@article.body, 'keyword') %>
15<!-- Wraps matches in <mark> tags -->
16
17<!-- Excerpt -->
18<%= excerpt(@article.body, 'keyword', radius: 50) %>
19<!-- Shows text around the keyword -->
20
21<!-- Word wrap -->
22<%= word_wrap(@long_text, line_width: 80) %>
23
24<!-- Strip tags -->
25<%= strip_tags(@html_content) %>
26
27<!-- Strip links -->
28<%= strip_links(@html_with_links) %>

Number Helpers

erb
1<!-- Currency -->
2<%= number_to_currency(1234.50) %>
3<!-- $1,234.50 -->
4<%= number_to_currency(1234.50, unit: "€", format: "%n %u") %>
5<!-- 1,234.50 € -->
6
7<!-- Percentage -->
8<%= number_to_percentage(75.5) %>
9<!-- 75.500% -->
10<%= number_to_percentage(75.5, precision: 0) %>
11<!-- 76% -->
12
13<!-- Delimiter -->
14<%= number_with_delimiter(1234567) %>
15<!-- 1,234,567 -->
16
17<!-- Precision -->
18<%= number_with_precision(3.14159, precision: 2) %>
19<!-- 3.14 -->
20
21<!-- Human readable -->
22<%= number_to_human(1234567) %>
23<!-- 1.23 Million -->
24
25<!-- File size -->
26<%= number_to_human_size(1234567) %>
27<!-- 1.18 MB -->
28
29<!-- Phone -->
30<%= number_to_phone(5551234567) %>
31<!-- 555-123-4567 -->

Date and Time Helpers

erb
1<!-- Time ago -->
2<%= time_ago_in_words(@article.created_at) %>
3<!-- "3 days ago" -->
4
5<!-- Distance in words -->
6<%= distance_of_time_in_words(Time.now, @event.starts_at) %>
7<!-- "about 2 hours" -->
8
9<!-- Date formatting with strftime -->
10<%= @article.created_at.strftime("%B %d, %Y") %>
11<!-- "January 15, 2024" -->
12
13<!-- Using I18n localize -->
14<%= l(@article.created_at, format: :long) %>
15<%= l(@article.created_at, format: :short) %>
16
17<!-- Time tag (with HTML5 time element) -->
18<%= time_tag(@article.created_at) %>
19<!-- <time datetime="2024-01-15T10:30:00Z">January 15, 2024</time> -->
20
21<%= time_tag(@article.created_at) do %>
22  Published <%= time_ago_in_words(@article.created_at) %> ago
23<% end %>

Asset Helpers

erb
1<!-- Images -->
2<%= image_tag "logo.png" %>
3<%= image_tag "logo.png", alt: "Company Logo", class: "logo" %>
4<%= image_tag "logo.png", size: "100x100" %>
5<%= image_tag @user.avatar, width: 50, height: 50 %>
6
7<!-- Image path -->
8<%= image_path "icon.png" %>
9<!-- /assets/icon-abc123.png -->
10
11<!-- Stylesheets -->
12<%= stylesheet_link_tag "application" %>
13<%= stylesheet_link_tag "print", media: "print" %>
14
15<!-- JavaScript -->
16<%= javascript_include_tag "application" %>
17<%= javascript_include_tag "custom", defer: true %>
18
19<!-- Favicon -->
20<%= favicon_link_tag "favicon.ico" %>
21
22<!-- Audio/Video -->
23<%= audio_tag "sound.mp3" %>
24<%= video_tag "movie.mp4", controls: true %>

Tag Helpers

erb
1<!-- Content tag -->
2<%= content_tag :div, "Hello", class: "greeting" %>
3<!-- <div class="greeting">Hello</div> -->
4
5<%= content_tag :ul, class: "list" do %>
6  <li>Item 1</li>
7  <li>Item 2</li>
8<% end %>
9
10<!-- Tag builder (Rails 5.1+) -->
11<%= tag.div "Hello", class: "greeting" %>
12<%= tag.p class: "intro" do %>
13  Welcome to our site!
14<% end %>
15
16<!-- Self-closing tags -->
17<%= tag.br %>
18<%= tag.hr %>
19<%= tag.img src: "photo.jpg", alt: "Photo" %>
20
21<!-- Data attributes -->
22<%= tag.div data: { controller: "modal", action: "click->modal#open" } %>
23<!-- <div data-controller="modal" data-action="click->modal#open"></div> -->

Conditional Classes

erb
1<!-- Rails 6.1+ class helper -->
2<div class="<%= class_names('base', active: @active, hidden: @hidden) %>">
3<!-- active and hidden only added if their values are truthy -->
4
5<!-- Array syntax -->
6<div class="<%= ['card', ('featured' if @article.featured?)].compact.join(' ') %>">

Custom Helpers

ruby
1# app/helpers/application_helper.rb
2module ApplicationHelper
3  def full_title(page_title = "")
4    base_title = "My App"
5    page_title.empty? ? base_title : "#{page_title} | #{base_title}"
6  end
7  
8  def nav_link(text, path)
9    css_class = current_page?(path) ? "nav-link active" : "nav-link"
10    link_to text, path, class: css_class
11  end
12  
13  def format_date(date)
14    date.strftime("%B %d, %Y") if date
15  end
16  
17  def avatar_for(user, size: 50)
18    if user.avatar.attached?
19      image_tag user.avatar, size: "#{size}x#{size}", class: "avatar"
20    else
21      image_tag "default_avatar.png", size: "#{size}x#{size}", class: "avatar"
22    end
23  end
24  
25  def markdown(text)
26    renderer = Redcarpet::Render::HTML.new
27    markdown = Redcarpet::Markdown.new(renderer)
28    markdown.render(text).html_safe
29  end
30end
erb
1<title><%= full_title(@article&.title) %></title>
2
3<nav>
4  <%= nav_link "Home", root_path %>
5  <%= nav_link "Articles", articles_path %>
6</nav>
7
8<%= avatar_for(@user, size: 100) %>
9<%= format_date(@article.published_at) %>
10<%= markdown(@article.body) %>

Model-Specific Helpers

ruby
1# app/helpers/articles_helper.rb
2module ArticlesHelper
3  def article_status_badge(article)
4    if article.published?
5      tag.span "Published", class: "badge badge-success"
6    else
7      tag.span "Draft", class: "badge badge-warning"
8    end
9  end
10  
11  def reading_time(article)
12    minutes = (article.body.split.size / 200.0).ceil
13    "#{minutes} min read"
14  end
15end

View helpers keep your templates clean and maintainable!