Views are what users see, and partials and helpers keep them consistent and DRY.
Views are ERB templates in app/views/<controller>/<action>.html.erb. <%= expr %> outputs the result, HTML-escaped by default, which protects against XSS. <% code %> runs Ruby without output, for loops and conditionals. Avoid raw and html_safe on user input.
The layout app/views/layouts/application.html.erb wraps every page; <%= yield %> marks where the action's template goes. Templates can fill named regions with content_for :title and the layout reads them with yield :title.
Partials are reusable fragments whose file names start with an underscore: _article.html.erb. Render one with <%= render "form", article: @article %> or, for a collection, <%= render @articles %>, which renders articles/_article once per record with a local article. Collection rendering is faster than looping and calling render yourself.
Helpers are Ruby methods available in views:
link_to "Edit", edit_article_path(@article)andbutton_to "Delete", @article, method: :delete.image_tag,time_ago_in_words,pluralize(3, "comment"),number_to_currency,truncate,simple_format.- Your own in
app/helpers.
Show flash messages in the layout with notice and alert. Use dom_id(@article) for consistent element ids, which Turbo uses as well. Keep logic out of views: compute data in the controller or a model method and give the view simple values.
Example
<%# app/views/layouts/application.html.erb %>
<html>
<head><title><%= content_for(:title) || "Blog" %></title></head>
<body>
<% if notice %><p class="notice"><%= notice %></p><% end %>
<%= yield %>
</body>
</html>
<%# app/views/articles/index.html.erb %>
<% content_for :title, "All articles" %>
<h1>Articles (<%= pluralize(@articles.size, "article") %>)</h1>
<%= render @articles %> <%# renders _article.html.erb for each %>
<%= link_to "New article", new_article_path %>
<%# app/views/articles/_article.html.erb %>
<article id="<%= dom_id(article) %>">
<h2><%= link_to article.title, article %></h2>
<p><%= truncate(article.body, length: 120) %></p>
<small><%= time_ago_in_words(article.created_at) %> ago</small>
</article>Remember
- <%= %> outputs escaped HTML; <% %> runs code
- Layouts wrap pages via yield; partials (_name) are reusable fragments
- render @collection renders a partial per record efficiently
Watch out for
- Calling html_safe or raw on user-supplied content, which disables escaping and allows XSS.