From ruby-on-rails
This skill should be used when the user asks about "views", "ERB templates", "partials", "layouts", "render", "form_with", "form helpers", "view helpers", "link_to", "content_for", "yield", "collection rendering", "locals", "tag helpers", "asset helpers", "image_tag", "stylesheet_link_tag", or needs guidance on building Rails views and templates.
npx claudepluginhub bastos/ruby-plugin-marketplace --plugin ruby-on-railsThis skill uses the workspace's default tool permissions.
Comprehensive guide to Rails views, templates, partials, layouts, and view helpers.
Generates design tokens/docs from CSS/Tailwind/styled-components codebases, audits visual consistency across 10 dimensions, detects AI slop in UI.
Records polished WebM UI demo videos of web apps using Playwright with cursor overlay, natural pacing, and three-phase scripting. Activates for demo, walkthrough, screen recording, or tutorial requests.
Delivers idiomatic Kotlin patterns for null safety, immutability, sealed classes, coroutines, Flows, extensions, DSL builders, and Gradle DSL. Use when writing, reviewing, refactoring, or designing Kotlin code.
Comprehensive guide to Rails views, templates, partials, layouts, and view helpers.
<%# Comment - not rendered %>
<% code %> <%# Execute Ruby, no output %>
<%= expression %> <%# Output result (escaped) %>
<%== raw_html %> <%# Output without escaping (use carefully) %>
<%- code -%> <%# Suppress leading/trailing whitespace %>
<%# Conditionals %>
<% if @user.admin? %>
<span class="badge">Admin</span>
<% end %>
<%# Iteration %>
<% @articles.each do |article| %>
<article>
<h2><%= article.title %></h2>
<p><%= truncate(article.body, length: 100) %></p>
</article>
<% end %>
<%# Safe output %>
<%= sanitize(@article.body) %>
<%= raw(@trusted_html) %>
Partials are reusable view fragments. Filename starts with underscore.
<%# app/views/articles/_article.html.erb %>
<article id="<%= dom_id(article) %>">
<h2><%= article.title %></h2>
<p><%= article.body %></p>
</article>
<%# Render partial %>
<%= render "article", article: @article %>
<%= render partial: "article", locals: { article: @article } %>
<%# Renders _article.html.erb for each item %>
<%= render @articles %>
<%# Explicit collection %>
<%= render partial: "article", collection: @articles %>
<%# With spacer %>
<%= render partial: "article", collection: @articles, spacer_template: "article_divider" %>
<%# Cached collection %>
<%= render partial: "article", collection: @articles, cached: true %>
<%# Counter and iteration info available %>
<%# article_counter (0-indexed) %>
<%# article_iteration.first?, .last?, .index, .size %>
<%# Strict locals (Rails 7.1+) %>
<%# locals: (article:, show_author: true) -%>
<article>
<h2><%= article.title %></h2>
<% if show_author %>
<p>By <%= article.author.name %></p>
<% end %>
</article>
<%# Wrap partial in a layout %>
<%= render partial: "article", layout: "card", locals: { article: @article } %>
<%# app/views/shared/_card.html.erb %>
<div class="card">
<%= yield %>
</div>
<%# app/views/layouts/application.html.erb %>
<!DOCTYPE html>
<html>
<head>
<title><%= content_for(:title) || "My App" %></title>
<%= csrf_meta_tags %>
<%= csp_meta_tag %>
<%= stylesheet_link_tag "application", "data-turbo-track": "reload" %>
<%= javascript_importmap_tags %>
<%= yield :head %>
</head>
<body>
<%= render "shared/header" %>
<% if notice %>
<div class="notice"><%= notice %></div>
<% end %>
<% if alert %>
<div class="alert"><%= alert %></div>
<% end %>
<main>
<%= yield %>
</main>
<%= render "shared/footer" %>
</body>
</html>
<%# In view %>
<% content_for :title, "My Page Title" %>
<% content_for :head do %>
<%= stylesheet_link_tag "custom" %>
<% end %>
<% content_for :sidebar do %>
<nav>Sidebar content</nav>
<% end %>
<%# In layout %>
<%= content_for?(:sidebar) ? yield(:sidebar) : render("default_sidebar") %>
class AdminController < ApplicationController
layout "admin"
end
class ArticlesController < ApplicationController
layout "article", only: [:show]
layout :determine_layout
private
def determine_layout
current_user&.admin? ? "admin" : "application"
end
end
<%# Model-backed form %>
<%= form_with model: @article do |form| %>
<%= form.label :title %>
<%= form.text_field :title %>
<%= form.label :body %>
<%= form.text_area :body, rows: 10 %>
<%= form.label :status %>
<%= form.select :status, Article::STATUSES %>
<%= form.submit %>
<% end %>
<%# URL-based form %>
<%= form_with url: search_path, method: :get do |form| %>
<%= form.text_field :q, placeholder: "Search..." %>
<%= form.submit "Search" %>
<% end %>
<%# Text inputs %>
<%= form.text_field :name %>
<%= form.email_field :email %>
<%= form.password_field :password %>
<%= form.telephone_field :phone %>
<%= form.url_field :website %>
<%= form.number_field :quantity, min: 1, max: 100 %>
<%= form.range_field :rating, min: 1, max: 5 %>
<%= form.search_field :q %>
<%= form.text_area :description, rows: 5 %>
<%# Hidden %>
<%= form.hidden_field :status, value: "draft" %>
<%# Checkboxes and radios %>
<%= form.check_box :published %>
<%= form.radio_button :status, "draft" %>
<%= form.radio_button :status, "published" %>
<%# Select %>
<%= form.select :category_id, Category.pluck(:name, :id) %>
<%= form.select :role, %w[admin editor viewer], { include_blank: "Select role" } %>
<%# Collection select %>
<%= form.collection_select :category_id, Category.all, :id, :name %>
<%= form.collection_radio_buttons :status, Status.all, :id, :name %>
<%= form.collection_check_boxes :tag_ids, Tag.all, :id, :name %>
<%# Date/time %>
<%= form.date_field :published_on %>
<%= form.time_field :start_time %>
<%= form.datetime_local_field :event_at %>
<%= form.date_select :birthday %>
<%= form.time_zone_select :time_zone %>
<%# File upload %>
<%= form.file_field :avatar %>
<%= form.file_field :images, multiple: true %>
# Model
class Article < ApplicationRecord
has_many :comments
accepts_nested_attributes_for :comments, allow_destroy: true
end
<%= form_with model: @article do |form| %>
<%= form.text_field :title %>
<%= form.fields_for :comments do |comment_form| %>
<%= comment_form.text_area :body %>
<%= comment_form.check_box :_destroy %>
<%= comment_form.label :_destroy, "Delete" %>
<% end %>
<%= form.submit %>
<% end %>
<%# Links %>
<%= link_to "Home", root_path %>
<%= link_to "Article", @article %>
<%= link_to "Edit", edit_article_path(@article) %>
<%= link_to "Delete", @article, method: :delete, data: { turbo_method: :delete, turbo_confirm: "Sure?" } %>
<%# With block %>
<%= link_to article_path(@article) do %>
<strong><%= @article.title %></strong>
<% end %>
<%# Button (creates form) %>
<%= button_to "Subscribe", subscriptions_path, method: :post %>
<%# Email %>
<%= mail_to "support@example.com" %>
<%= mail_to "support@example.com", "Contact Us", subject: "Help Request" %>
<%# Current page check %>
<%= link_to "Home", root_path, class: ("active" if current_page?(root_path)) %>
<%# Modern tag helper syntax %>
<%= tag.div class: "container" do %>
<%= tag.h1 @article.title %>
<%= tag.p @article.body, class: "content" %>
<% end %>
<%# With data attributes %>
<%= tag.div data: { controller: "toggle", action: "click->toggle#switch" } do %>
Content
<% end %>
<%# Self-closing tags %>
<%= tag.br %>
<%= tag.hr %>
<%= tag.input type: "text", name: "query" %>
<%# class_names / token_list %>
<%= tag.div class: class_names("base", active: @active, hidden: @hidden) %>
<%# Images %>
<%= image_tag "logo.png" %>
<%= image_tag "logo.png", alt: "Logo", class: "logo", size: "100x50" %>
<%= image_tag @user.avatar, fallback: "default_avatar.png" %>
<%# Stylesheets %>
<%= stylesheet_link_tag "application", media: "all" %>
<%= stylesheet_link_tag "print", media: "print" %>
<%# JavaScript %>
<%= javascript_include_tag "application" %>
<%= javascript_importmap_tags %>
<%# Favicon %>
<%= favicon_link_tag "favicon.ico" %>
<%# Video/Audio %>
<%= video_tag "intro.mp4", controls: true, autoplay: false %>
<%= audio_tag "podcast.mp3", controls: true %>
<%# Truncate %>
<%= truncate(@article.body, length: 100) %>
<%= truncate(@article.body, length: 100, omission: "... (more)") %>
<%# Excerpt %>
<%= excerpt(@article.body, "Rails", radius: 25) %>
<%# Pluralize %>
<%= pluralize(@comments.count, "comment") %>
<%# Word wrap %>
<%= word_wrap(@text, line_width: 80) %>
<%# Simple format (converts newlines to <br> and paragraphs) %>
<%= simple_format(@article.body) %>
<%# Highlight %>
<%= highlight(@article.body, "Rails") %>
<%= number_to_currency(1234.56) %> <%# $1,234.56 %>
<%= number_to_currency(1234.56, unit: "€") %> <%# €1,234.56 %>
<%= number_to_percentage(75.5) %> <%# 75.500% %>
<%= number_to_percentage(75.5, precision: 0) %> <%# 76% %>
<%= number_with_delimiter(12345678) %> <%# 12,345,678 %>
<%= number_with_precision(111.2345, precision: 2) %> <%# 111.23 %>
<%= number_to_human(1234567) %> <%# 1.23 Million %>
<%= number_to_human_size(1234567) %> <%# 1.18 MB %>
<%= number_to_phone(5551234567) %> <%# 555-123-4567 %>
<%= distance_of_time_in_words(Time.current, 3.days.from_now) %> <%# about 3 days %>
<%= time_ago_in_words(@article.created_at) %> <%# 2 hours ago %>
<%# Remove dangerous HTML %>
<%= sanitize(@user_input) %>
<%# Allow specific tags %>
<%= sanitize(@content, tags: %w[p br strong em]) %>
<%# Strip all tags %>
<%= strip_tags(@html_content) %>
<%# Strip links but keep text %>
<%= strip_links(@content_with_links) %>
references/form-patterns.md - Complex form patterns, custom form buildersreferences/view-helpers.md - Creating custom helpers, helper organization