ソース情報
- リポジトリ
- CodySwannGT/lisa
- ソースの最終更新活動
- 2026年7月10日 13:59
- 検出された SKILL.md の言語
- 英語
- スター
- 3
- フォーク
- 3
インストール方法
デフォルトでは、最初にソースを確認する Prompt が選択されています。直接コマンドに切り替えるか、ローカルコピーをダウンロードすることもできます。
ソースファイルを確認
インストールを決める前に、SKILL.md と SkillsMP に表示されている付属ファイルをお読みください。
メニュー
デフォルトでは、最初にソースを確認する Prompt が選択されています。直接コマンドに切り替えるか、ローカルコピーをダウンロードすることもできます。
インストールを決める前に、SKILL.md と SkillsMP に表示されている付属ファイルをお読みください。
SOC 職業分類に基づく
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
直接コマンドでは確認用 Prompt が省略されます。実行前にソースを確認してください。
npx skills add https://github.com/CodySwannGT/lisa --skill action-view-best-practicesコマンドは1行のまま表示されます。コピー前に横へスクロールして全体を確認してください。
ローカルで確認しますか?SkillsMP が現在取得できるファイルをダウンロードできます。
SKILL.md を表示中
This skill should be used for any non-trivial request — features, bugs, stories, epics, spikes, or multi-step tasks. It accepts a ticket URL (Jira, Linear, GitHub), a file path containing a spec, or a plain-text prompt. It assembles an agent team, breaks the work into structured tasks, and manages the full lifecycle from research through implementation, code review, deploy, and empirical verification.
any non-trivial request —…
This skill should be used for any non-trivial request — features, bugs, stories, epics, spikes, or multi-step tasks. It accepts a ticket URL (Jira, Linear, GitHub), a file path containing a spec, or a plain-text prompt. It assembles an agent team, breaks the work into structured tasks, and manages the full lifecycle from research through implementation, code review, deploy, and empirical verification.
| name | action-view-best-practices |
| description | Build or Refactor Rails views… |
Views should contain markup and minimal display logic. If a view has conditionals, calculations, query calls, or complex Ruby blocks, it needs refactoring. The modern Rails 8+ stack uses Hotwire (Turbo + Stimulus) for interactivity, Propshaft for assets, and Importmap for JavaScript — no build step required.
Read the view and classify each block of code:
| Code type | Extract to | Location |
|---|---|---|
| Reusable UI patterns (buttons, cards, modals, badges) | ViewComponent | app/components/ |
| Display logic (formatting, conditional CSS, label text) | Presenter or ViewComponent | app/presenters/ or app/components/ |
| HTML-returning helper methods | ViewComponent | app/components/ |
Inline <script> tags and jQuery | Stimulus controller | app/javascript/controllers/ |
AJAX calls, remote forms, $.ajax | Turbo Frame or Turbo Stream | ERB template + controller response |
| Partial page updates via JavaScript | Turbo Frame | Wrap in turbo_frame_tag |
| Real-time broadcasts (chat, notifications) | Turbo Stream | Model broadcasts_to or controller stream |
| One-off page sections that are too long | Partial with strict locals | app/views/shared/ or alongside view |
| Complex data assembly for the view | Presenter | app/presenters/ |
| Repeated inline Ruby (loops with logic) | Collection partial or component | Partial or component |
| Instance variables used across partials | Locals / strict locals | Pass explicitly |
Turbo Frames update a specific section of the page without a full reload. No JavaScript needed.
<%# Before — jQuery AJAX %>
<div id="player-stats"></div>
<script>
$.get('/players/<%= @player.id %>/stats', function(data) {
$('#player-stats').html(data);
});
</script>
<%# After — Turbo Frame %>
<%= turbo_frame_tag "player_stats" do %>
<%= render partial: "players/stats", locals: { player: @player } %>
<% end %>
The linked page just needs a matching turbo_frame_tag with the same ID and Turbo handles the rest.
Rails UJS remote: true forms are deprecated. Turbo handles forms natively.
<%# Before — Rails UJS %>
<%= form_with model: @player, remote: true do |f| %>
...
<% end %>
<%# After — Turbo (just remove remote: true, Turbo handles it) %>
<%= form_with model: @player do |f| %>
...
<% end %>
Turbo intercepts all form submissions by default. For partial updates, wrap the form in a turbo_frame_tag. For multi-target updates, respond with a Turbo Stream:
<%# app/views/players/update.turbo_stream.erb %>
<%= turbo_stream.replace "player_header" do %>
<%= render partial: "players/header", locals: { player: @player } %>
<% end %>
<%= turbo_stream.update "flash_messages" do %>
<%= render partial: "shared/flash" %>
<% end %>
Any behavior attached to DOM elements (toggles, dropdowns, form validation, clipboard, modals) should be a Stimulus controller.
<%# Before — inline JS / jQuery %>
<button onclick="document.getElementById('details').classList.toggle('hidden')">
Toggle
</button>
<div id="details" class="hidden">...</div>
<%# After — Stimulus %>
<div data-controller="toggle">
<button data-action="click->toggle#switch">Toggle</button>
<div data-toggle-target="content" class="hidden">...</div>
</div>
// app/javascript/controllers/toggle_controller.js
import { Controller } from "@hotwired/stimulus";
export default class extends Controller {
static targets = ["content"];
switch() {
this.contentTarget.classList.toggle("hidden");
}
}
Conventions:
toggle, clipboard, dropdown, search-formtargets for elements, values for data, classes for CSS class namesFor real-time updates, use Turbo Streams over WebSockets instead of JavaScript polling.
# app/models/score.rb
class Score < ApplicationRecord
broadcasts_to ->(score) { [score.game] }, inserts_by: :prepend
end
<%# Subscribe in the view %>
<%= turbo_stream_from @game %>
<div id="scores">
<%= render @game.scores %>
</div>
New scores automatically appear without any JavaScript.
Use partials for:
Use ViewComponent for:
# app/components/stat_card_component.rb
class StatCardComponent < ViewComponent::Base
def initialize(label:, value:, trend: nil)
@label = label
@value = value
@trend = trend
end
def trend_class
case @trend
when :up then "text-green-600"
when :down then "text-red-600"
else "text-gray-500"
end
end
end
<%# app/components/stat_card_component.html.erb %>
<div class="rounded-lg border p-4">
<dt class="text-sm text-gray-500"><%= @label %></dt>
<dd class="text-2xl font-semibold"><%= @value %></dd>
<% if @trend %>
<span class="<%= trend_class %>"><%= @trend == :up ? "↑" : "↓" %></span>
<% end %>
</div>
<%# Usage %>
<%= render StatCardComponent.new(label: "Batting Avg", value: ".312", trend: :up) %>
Always declare expected locals at the top of partials. This was added in Rails 7.1 and prevents silent nil bugs.
<%# app/views/players/_card.html.erb %>
<%# locals: (player:, show_stats: false) %>
<div class="player-card">
<h3><%= player.name %></h3>
<% if show_stats %>
<%= render partial: "players/stats", locals: { player: player } %>
<% end %>
</div>
Never loop and render partials manually.
<%# Before — slow, verbose %>
<% @players.each do |player| %>
<%= render partial: "players/card", locals: { player: player } %>
<% end %>
<%# After — collection rendering (faster, cleaner) %>
<%= render partial: "players/card", collection: @players, as: :player %>
If partial A renders partial B which renders partial C, it's too deep. Flatten the structure or extract to a ViewComponent that composes its own sub-components.
When a view needs data from multiple sources or complex formatting, use a presenter instead of cramming logic into the template.
# app/presenters/player_profile_presenter.rb
class PlayerProfilePresenter
def initialize(player, current_user)
@player = player
@current_user = current_user
end
def display_name
"#{@player.first_name} #{@player.last_name}"
end
def contract_status_badge
if @player.free_agent?
{ text: "Free Agent", color: "green" }
elsif @player.contract_years_remaining <= 1
{ text: "Expiring", color: "yellow" }
else
{ text: "Under Contract", color: "gray" }
end
end
def can_edit?
@current_user.admin? || @current_user.team == @player.team
end
def formatted_salary
ActiveSupport::NumberHelper.number_to_currency(@player.salary)
<%# Clean view %>
<h1><%= @presenter.display_name %></h1>
<% badge = @presenter.contract_status_badge %>
<%= render BadgeComponent.new(text: badge[:text], color: badge[:color]) %>
<%= @presenter.formatted_salary %>
<% if @presenter.can_edit? %>
<%= link_to "Edit", edit_player_path(@player) %>
<% end %>
Rails helpers that return HTML are hard to test, hard to read, and hard to compose. Move them to ViewComponents.
# Before — helper returning HTML (bad)
module PlayersHelper
def player_avatar(player, size: :md)
sizes = { sm: "w-8 h-8", md: "w-12 h-12", lg: "w-16 h-16" }
if player.avatar.attached?
image_tag player.avatar, class: "rounded-full #{sizes[size]}"
else
content_tag :div, player.initials,
class: "rounded-full #{sizes[size]} bg-gray-300 flex items-center justify-center"
end
end
end
# After — ViewComponent (good)
# app/components/avatar_component.rb
class AvatarComponent < ViewComponent::Base
SIZES = { sm: "w-8 h-8", md: "w-12 h-12", lg: "w-16 h-16" }.freeze
def initialize(player:, size: :md)
@player = player
@size = size
end
# ... with its own template and tests
end
Keep helpers for non-HTML formatting utilities only (number formatting, date formatting, text truncation).
remote: true forms, helpers returning HTML, and deeply nested partials.remote: true and AJAX — Turbo handles forms and links natively. Convert to Turbo Frames and Turbo Streams.count or any?. Use the presenter or controller.content_for for complex logic — it creates invisible dependencies between layouts and views.html_safe or raw unless you are certain the content is sanitized.render partial: inside loops — use collection rendering instead.