用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
直接命令不会经过审查 Prompt;运行前请先检查来源。
npx skills add https://github.com/CodySwannGT/lisa --skill action-controller-best-practices命令会保持在同一行。复制前请横向滚动并检查完整内容。
想先保存到本地?可下载 SkillsMP 当前能够提供的文件。
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.
基于 SOC 职业分类
正在显示 SKILL.md
| name | action-controller-best-practices |
| description | Build or Refactor large Rails… |
Controllers should be thin traffic cops — they receive input via params, delegate to the appropriate object, and decide what to render or redirect. Each action should be roughly 5-10 lines. If an action is longer, logic needs to be extracted.
Read the controller and classify each block of code:
| Code type | Extract to | Location |
|---|---|---|
| Business logic, multi-step operations, side effects | Service object | app/services/ |
| Complex queries, filtering, sorting, search | Query object | app/queries/ |
| Context-specific param validation and persistence | Form object | app/forms/ |
| Shared before_actions, auth, pagination, error handling | Controller concern | app/controllers/concerns/ |
| Complex view data assembly, formatting, display logic | Presenter / Decorator | app/presenters/ or app/decorators/ |
| Non-RESTful custom actions on a different concept | New RESTful controller | app/controllers/ |
| Simple CRUD, strong params, render/redirect | Keep on controller | — |
Use for any business logic that goes beyond simple CRUD. A controller action should call one service at most.
Before:
def create
@player = Player.new(player_params)
@player.team = Team.find(params[:team_id])
@player.contract_start = Time.current
@player.status = :active
if @player.save
PlayerMailer.welcome(@player).deliver_later
Analytics.track("player_signed", player_id: @player.id)
NotifyScoutsJob.perform_later(@player.team_id)
redirect_to @player, notice: "Player signed"
else
render :new, status: :unprocessable_entity
end
end
After:
# Controller
def create
result = Players::SignPlayer.new(player_params, team_id: params[:team_id]).call
if result.success?
redirect_to result.player, notice: "Player signed"
else
@player = result.player
render :new, status: :unprocessable_entity
end
end
# app/services/players/sign_player.rb
module Players
class SignPlayer
def initialize(params, team_id:)
@params = params
@team_id = team_id
end
def call
player = Player.new(@params)
player.team = Team.find(@team_id)
player.contract_start = Time.current
player.status = :active
if player.save
send_notifications(player)
Result.new(success: true, player: player)
else
Result.new(success: false, player: player)
end
end
()
.welcome(player).deliver_later
.track(, player.id)
.perform_later(player.team_id)
= .new(, , )
alias_method ,
Use when index actions have complex filtering, sorting, or search logic.
Before:
def index
@players = Player.where(team_id: params[:team_id])
@players = @players.where(position: params[:position]) if params[:position].present?
@players = @players.where("age >= ?", params[:min_age]) if params[:min_age].present?
@players = @players.where(status: :active) unless params[:include_inactive]
@players = @players.joins(:stats).order("stats.war DESC")
@players = @players.page(params[:page]).per(25)
end
After:
# Controller
def index
@players = Players::FilterQuery.new(params).call
end
# app/queries/players/filter_query.rb
module Players
class FilterQuery
def initialize(params, relation: Player.all)
@params = params
@relation = relation
end
def call
filter_by_team
filter_by_position
filter_by_age
filter_by_status
sort_and_paginate
@relation
end
private
def filter_by_team
@relation = @relation.where(team_id: @params[:team_id]) if @params[:team_id].present?
end
def filter_by_position
@relation = @relation.where(position: @params[:position]) if @params[:position].present?
end
def filter_by_age
@relation = @relation.where(, []) [].present?
= .where( ) []
= .joins().order().page([]).per()
Use for shared behavior across multiple controllers: authentication, authorization, pagination, error handling, locale setting.
# app/controllers/concerns/paginatable.rb
module Paginatable
extend ActiveSupport::Concern
private
def page
params[:page] || 1
end
def per_page
[params[:per_page].to_i, 100].min.nonzero? || 25
end
end
# app/controllers/concerns/error_handleable.rb
module ErrorHandleable
extend ActiveSupport::Concern
included do
rescue_from ActiveRecord::RecordNotFound, with: :not_found
rescue_from ActionController::ParameterMissing, with: :bad_request
end
private
def not_found
render json: { error: "Not found" }, status: :not_found
end
def bad_request(exception)
render json: { error: exception.message }, status:
Guidelines for controller concerns:
Use when an action assembles complex data for the view that isn't a direct model attribute. Keeps view logic out of the controller.
# app/presenters/player_dashboard_presenter.rb
class PlayerDashboardPresenter
def initialize(player)
@player = player
end
def career_stats
@career_stats ||= @player.stats.group(:season).sum(:war)
end
def contract_status_label
return "Free Agent" if @player.contract_end&.past?
"Under Contract (#{@player.contract_end&.year})"
end
def trade_value_rating
case @player.trade_value
when 90.. then "Elite"
when 70..89 then "High"
when 50..69 then "Average"
else "Low"
end
end
end
# Controller
def show
@player = Player.find(params[])
= .new()
When a controller has custom non-RESTful actions, it usually means there's a hidden resource. Extract it into its own controller with standard CRUD actions.
Before:
class PlayersController < ApplicationController
def trade
# ...
end
def release
# ...
end
def promote_to_roster
# ...
end
end
After:
# config/routes.rb
resources :players do
resource :trade, only: [:new, :create], controller: "players/trades"
resource :release, only: [:create], controller: "players/releases"
resource :roster_promotion, only: [:create], controller: "players/roster_promotions"
end
# app/controllers/players/trades_controller.rb
module Players
class TradesController < ApplicationController
def new
@player = Player.find(params[:player_id])
end
def create
result = Players::TradePlayer.new(Player.find(params[:player_id]), trade_params).call
# ...
end
end
end
Signs you need a new controller:
_params method. If you need different permitted params per action, consider separate controllers or form objects.class PlayersController < ApplicationController
before_action :set_player, only: [:show, :edit, :update, :destroy]
def index
@players = Players::FilterQuery.new(params).call
end
def show
@presenter = PlayerDashboardPresenter.new(@player)
end
def create
result = Players::SignPlayer.new(player_params, team_id: params[:team_id]).call
if result.success?
redirect_to result.player, notice: "Player signed"
else
@player = result.player
render :new, status: :unprocessable_entity
end
end
def update
if @player.update(player_params)
redirect_to @player, notice: "Player updated"
else
render :edit, status: :unprocessable_entity
end
end
def destroy
.destroy
redirect_to players_path,
= .find(params[])
params.().permit(, , , )
rescue_from.