action-view
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.
What this skill does
# Action View
Comprehensive guide to Rails views, templates, partials, layouts, and view helpers.
## Templates
### ERB Syntax
```erb
<%# Comment - not rendered %>
<% code %> <%# Execute Ruby, no output %>
<%= expression %> <%# Output result (escaped) %>
<%== raw_html %> <%# Output without escaping (use carefully) %>
<%- code -%> <%# Suppress leading/trailing whitespace %>
```
### Common ERB Patterns
```erb
<%# 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
Partials are reusable view fragments. Filename starts with underscore.
### Basic Partial
```erb
<%# 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 } %>
```
### Collection Rendering
```erb
<%# 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 %>
```
### Local Variables
```erb
<%# 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>
```
### Partial Layouts
```erb
<%# Wrap partial in a layout %>
<%= render partial: "article", layout: "card", locals: { article: @article } %>
<%# app/views/shared/_card.html.erb %>
<div class="card">
<%= yield %>
</div>
```
## Layouts
### Application Layout
```erb
<%# 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>
```
### Content For
```erb
<%# 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") %>
```
### Controller-Specific Layouts
```ruby
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
```
## Form Helpers
### form_with
```erb
<%# 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 %>
```
### Form Fields
```erb
<%# 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 %>
```
### Nested Forms
```ruby
# Model
class Article < ApplicationRecord
has_many :comments
accepts_nested_attributes_for :comments, allow_destroy: true
end
```
```erb
<%= 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 %>
```
## URL Helpers
```erb
<%# 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 "[email protected]" %>
<%= mail_to "[email protected]", "Contact Us", subject: "Help Request" %>
<%# Current page check %>
<%= link_to "Home", root_path, class: ("active" if current_page?(root_path)) %>
```
## Tag Helpers
```erb
<%# 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) %>
```
## Asset Helpers
```erb
<%# 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 %>
```
## Text Helpers
```erb
<%# 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 (conRelated in Image & Video
watch
IncludedWatch a video (URL or local path). Downloads with yt-dlp, extracts auto-scaled frames with ffmpeg, pulls the transcript from captions (or Whisper API fallback), and hands the result to Claude so it can answer questions about what's in the video.
physical-ai-defect-image-generation
IncludedUse when the user wants to orchestrate defect image generation, run associated setup, or handle outputs on OSMO. The Day 0 path handles cold-start with USD-to-ROI, image-edit augmentation, and AnomalyGen to create initial PCBA datasets. The Day 1 path performs inference and labeling on real images. This skill helps with first-time asset setup, creation of finetuning checkpoints, and configuring deployment. Trigger keywords: defect image generation, dig workflow, dig pipeline, defect image detection workflow, aoi pipeline, aoi anomalygen, usd2roi anomalygen, day 0 pcba, day 1 pcba, day 1 real-photo alignment, day 1 manual roi, metal surface anomaly, glass defect, anomalygen finetune, setup_pcb, setup_metal, setup_glass, setup_pretrained, dig setup, dig datasets, dig pretrained checkpoint, dig image-edit endpoint.
accelint-react-best-practices
IncludedReact performance optimization and best practices. ALWAYS use this skill when working with any React code - writing components, hooks, JSX; refactoring; optimizing re-renders, memoization, state management; reviewing for performance; fixing hydration mismatches; debugging infinite re-renders, stale closures, input focus loss, animations restarting; preventing remounting; implementing transitions, lazy initialization, effect dependencies. Even simple React tasks benefit from these patterns. Covers React 19+ (useEffectEvent, Activity, ref props). Triggers - useEffect, useState, useMemo, useCallback, memo, inline components, nested components, components inside components, re-render, performance, hydration, SSR, Next.js, useDeferredValue, combined hooks.
elevenlabs-agents
IncludedBuild conversational AI voice agents with ElevenLabs Platform using React, JavaScript, React Native, or Swift SDKs. Configure agents, tools (client/server/MCP), RAG knowledge bases, multi-voice, and Scribe real-time STT. Use when: building voice chat interfaces, implementing AI phone agents with Twilio, configuring agent workflows or tools, adding RAG knowledge bases, testing with CLI "agents as code", or troubleshooting deprecated @11labs packages, Android audio cutoff, CSP violations, dynamic variables, or WebRTC config. Keywords: ElevenLabs Agents, ElevenLabs voice agents, AI voice agents, conversational AI, @elevenlabs/react, @elevenlabs/client, @elevenlabs/react-native, @elevenlabs/elevenlabs-js, @elevenlabs/agents-cli, elevenlabs SDK, voice AI, TTS, text-to-speech, ASR, speech recognition, turn-taking model, WebRTC voice, WebSocket voice, ElevenLabs conversation, agent system prompt, agent tools, agent knowledge base, RAG voice agents, multi-voice agents, pronunciation dictionary, voice speed control, elevenlabs scribe, @11labs deprecated, Android audio cutoff, CSP violation elevenlabs, dynamic variables elevenlabs, case-sensitive tool names, webhook authentication
humanizer
IncludedHumanize AI-generated text by detecting and removing patterns typical of LLM output. Rewrites text to sound natural, specific, and human. Uses 28 pattern detectors, 560+ AI vocabulary terms across 3 tiers, and statistical analysis (burstiness, type-token ratio, readability) for comprehensive detection. Use when asked to humanize text, de-AI writing, make content sound more natural/human, review writing for AI patterns, score text for AI detection, or improve AI-generated drafts. Covers content, language, style, communication, and filler categories.
generating-mermaid-diagrams
IncludedSalesforce architecture diagrams using Mermaid with ASCII fallback. Use this skill when generating text-based diagrams for Salesforce architecture, OAuth flows, ERDs, integration sequences, or Agentforce structure. TRIGGER when: user says "diagram", "visualize", "ERD", or asks for sequence diagrams, flowcharts, class diagrams, or architecture visualizations in Mermaid. DO NOT TRIGGER when: user wants PNG/SVG image output (use generating-visual-diagrams), or asks about non-Salesforce systems.