Creates Rails controllers with TDD approach - request spec first, then implementation. Use when creating new controllers, adding controller actions, implementing CRUD operations, or when user mentions controllers, routes, or API endpoints.
Install with Tessl CLI
npx tessl i github:fernandezbaptiste/rails_ai_agents --skill rails-controller90
Does it follow best practices?
If you maintain this skill, you can automatically optimize it using the tessl CLI to improve its score:
npx tessl skill review --optimize ./path/to/skillValidation for skill structure
Creates RESTful controllers following project conventions with request specs first.
spec/requests/This project uses:
authorize @resource, policy_scope(Model))current_account# spec/requests/[resources]_spec.rb
RSpec.describe "[Resources]", type: :request do
let(:user) { create(:user) }
let(:other_user) { create(:user) }
before { sign_in user, scope: :user }
describe "GET /[resources]" do
let!(:resource) { create(:[resource], account: user.account) }
let!(:other_resource) { create(:[resource], account: other_user.account) }
it "returns http success" do
get [resources]_path
expect(response).to have_http_status(:success)
end
it "shows only current_user's resources (multi-tenant)" do
get [resources]_path
expect(response.body).to include(resource.name)
expect(response.body).not_to include(other_resource.name)
end
end
describe "GET /[resources]/:id" do
let!(:resource) { create(:[resource], account: user.account) }
it "returns http success" do
get [resource]_path(resource)
expect(response).to have_http_status(:success)
end
end
describe "POST /[resources]" do
let(:valid_params) { { [resource]: attributes_for(:[resource]) } }
it "creates a new resource" do
expect {
post [resources]_path, params: valid_params
}.to change([Resource], :count).by(1)
end
it "assigns to current_account" do
post [resources]_path, params: valid_params
expect([Resource].last.account).to eq(user.account)
end
end
describe "authorization" do
let!(:other_resource) { create(:[resource], account: other_user.account) }
it "returns 404 for unauthorized access" do
get [resource]_path(other_resource)
expect(response).to have_http_status(:not_found)
end
end
endbundle exec rspec spec/requests/[resources]_spec.rb# app/controllers/[resources]_controller.rb
class [Resources]Controller < ApplicationController
before_action :set_[resource], only: [:show, :edit, :update, :destroy]
def index
authorize [Resource], :index?
@pagy, resources = pagy(policy_scope([Resource]).order(created_at: :desc))
@[resources] = resources.map { |r| [Resource]Presenter.new(r) }
end
def show
authorize @[resource]
@[resource] = [Resource]Presenter.new(@[resource])
end
def new
@[resource] = current_account.[resources].build
authorize @[resource]
end
def create
@[resource] = current_account.[resources].build([resource]_params)
authorize @[resource]
if @[resource].save
redirect_to [resources]_path, notice: "[Resource] created successfully"
else
render :new, status: :unprocessable_entity
end
end
def edit
authorize @[resource]
end
def update
authorize @[resource]
if @[resource].update([resource]_params)
redirect_to @[resource], notice: "[Resource] updated successfully"
else
render :edit, status: :unprocessable_entity
end
end
def destroy
authorize @[resource]
@[resource].destroy
redirect_to [resources]_path, notice: "[Resource] deleted successfully"
end
private
def set_[resource]
@[resource] = policy_scope([Resource]).find(params[:id])
end
def [resource]_params
params.require(:[resource]).permit(:name, :field1, :field2)
end
endbundle exec rspec spec/requests/[resources]_spec.rbFor nested routes like settings/accounts:
# app/controllers/settings/accounts_controller.rb
module Settings
class AccountsController < ApplicationController
before_action :set_account
def show
authorize @account
end
private
def set_account
@account = current_account
end
end
enddef create
@resource = current_account.resources.build(resource_params)
authorize @resource
if @resource.save
respond_to do |format|
format.html { redirect_to resources_path, notice: "Created" }
format.turbo_stream do
flash.now[:notice] = "Created"
@pagy, @resources = pagy(policy_scope(Resource).order(created_at: :desc))
render turbo_stream: [
turbo_stream.replace("resources-list", partial: "resources/list"),
turbo_stream.update("modal", "")
]
end
end
else
render :new, status: :unprocessable_entity
end
endauthorize on every actionpolicy_scope for queries15fdeaf
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.