rails-controller

Rails Controller Generator (TDD)

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "rails-controller" with this command: npx skills add thibautbaissac/rails_ai_agents/thibautbaissac-rails-ai-agents-rails-controller

Rails Controller Generator (TDD)

Creates RESTful controllers following project conventions with request specs first.

Quick Start

  • Write failing request spec in spec/requests/

  • Run spec to confirm RED

  • Implement controller action

  • Run spec to confirm GREEN

  • Refactor if needed

Project Conventions

This project uses:

  • Pundit for authorization (authorize @resource , policy_scope(Model) )

  • Pagy for pagination

  • Presenters for view formatting

  • Multi-tenancy via current_account

  • Turbo Stream responses for dynamic updates

TDD Workflow

Step 1: Create Request Spec (RED)

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 end

Step 2: Run Spec (Confirm RED)

bundle exec rspec spec/requests/[resources]_spec.rb

Step 3: Implement Controller (GREEN)

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 end

Step 4: Run Spec (Confirm GREEN)

bundle exec rspec spec/requests/[resources]_spec.rb

Namespaced Controllers

For 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 end

Turbo Stream Response Pattern

def 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 end

Checklist

  • Request spec written first (RED)

  • Multi-tenant isolation tested

  • Authorization tested (404 for unauthorized)

  • Controller uses authorize on every action

  • Controller uses policy_scope for queries

  • Presenter wraps models for views

  • Strong parameters defined

  • All specs GREEN

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

Automation

hotwire-patterns

No summary provided by upstream source.

Repository SourceNeeds Review
Automation

i18n-patterns

No summary provided by upstream source.

Repository SourceNeeds Review
Automation

solid-queue-setup

No summary provided by upstream source.

Repository SourceNeeds Review
Automation

viewcomponent-patterns

No summary provided by upstream source.

Repository SourceNeeds Review