Claude Code Plugins

Community-maintained marketplace

Feedback

Rails Conventions

@betamatt/claude-plugins
0
0

This skill should be used when the user is working in a Rails 7+ application and asks about "Rails conventions", "naming conventions", "Rails structure", "Hotwire patterns", "Turbo frames", "Stimulus controllers", "Rails directory structure", "Rails best practices", or needs guidance on idiomatic Rails patterns for production systems.

Install Skill

1Download skill
2Enable skills in Claude

Open claude.ai/settings/capabilities and find the "Skills" section

3Upload to Claude

Click "Upload skill" and select the downloaded ZIP file

Note: Please verify skill by going through its instructions before using it.

SKILL.md

name Rails Conventions
description This skill should be used when the user is working in a Rails 7+ application and asks about "Rails conventions", "naming conventions", "Rails structure", "Hotwire patterns", "Turbo frames", "Stimulus controllers", "Rails directory structure", "Rails best practices", or needs guidance on idiomatic Rails patterns for production systems.
version 1.0.0

Rails 7+ Conventions for Production Systems

Production-focused guidance for Rails 7+ conventions, naming patterns, directory structure, and modern frontend integration with Hotwire.

Core Naming Conventions

Models

  • Class names: Singular, CamelCase (User, OrderItem, PaymentTransaction)
  • Table names: Plural, snake_case (users, order_items, payment_transactions)
  • Foreign keys: Singular model name + _id (user_id, order_id)
  • Join tables: Alphabetical order, plural (categories_products, roles_users)

Controllers

  • Class names: Plural, CamelCase + Controller (UsersController, Api::V1::OrdersController)
  • Files: Plural, snake_case (users_controller.rb, api/v1/orders_controller.rb)
  • RESTful actions: index, show, new, create, edit, update, destroy

Routes

Prefer resourceful routes over custom routes:

# Production pattern
resources :orders do
  resources :line_items, shallow: true
  member do
    post :cancel
    post :refund
  end
  collection do
    get :pending
  end
end

# API versioning
namespace :api do
  namespace :v1 do
    resources :orders, only: [:index, :show, :create]
  end
end

Views and Partials

  • Views: app/views/controller_name/action.html.erb
  • Partials: Prefix with underscore _partial.html.erb
  • Shared partials: app/views/shared/_partial.html.erb
  • Component partials: app/views/components/_button.html.erb

Directory Structure

Standard Rails 7 Layout

app/
├── assets/
│   └── stylesheets/
├── channels/           # ActionCable channels
├── controllers/
│   ├── concerns/       # Controller concerns
│   └── api/           # API controllers
├── helpers/
├── javascript/
│   └── controllers/   # Stimulus controllers
├── jobs/              # ActiveJob classes
├── mailers/
├── models/
│   └── concerns/      # Model concerns
├── views/
│   ├── layouts/
│   ├── shared/
│   └── components/    # View components (if using)
config/
├── initializers/
├── locales/
└── environments/
db/
├── migrate/
└── seeds.rb
lib/
├── tasks/             # Rake tasks
└── templates/         # Generator templates
spec/ or test/

Service Objects

Place in app/services/ with clear naming:

# app/services/orders/create_service.rb
module Orders
  class CreateService
    def initialize(user:, cart:)
      @user = user
      @cart = cart
    end

    def call
      # Implementation
    end
  end
end

# Usage: Orders::CreateService.new(user: current_user, cart: @cart).call

Query Objects

Place in app/queries/:

# app/queries/orders/pending_query.rb
module Orders
  class PendingQuery
    def initialize(relation = Order.all)
      @relation = relation
    end

    def call
      @relation.where(status: :pending)
               .where("created_at > ?", 24.hours.ago)
               .includes(:line_items, :user)
    end
  end
end

Hotwire Patterns (Rails 7+)

Turbo Frames

Use for partial page updates without full navigation:

<%# Index page with inline editing %>
<%= turbo_frame_tag "orders" do %>
  <% @orders.each do |order| %>
    <%= turbo_frame_tag dom_id(order) do %>
      <%= render order %>
    <% end %>
  <% end %>
<% end %>

<%# Edit form that replaces the frame %>
<%= turbo_frame_tag dom_id(@order) do %>
  <%= render "form", order: @order %>
<% end %>

Turbo Streams

Use for real-time updates and multi-element updates:

# Controller action
def create
  @order = Order.create(order_params)

  respond_to do |format|
    format.turbo_stream
    format.html { redirect_to orders_path }
  end
end
<%# create.turbo_stream.erb %>
<%= turbo_stream.prepend "orders", @order %>
<%= turbo_stream.update "order_count", Order.count %>

Stimulus Controllers

Naming convention: controller-name_controller.js

// app/javascript/controllers/dropdown_controller.js
import { Controller } from "@hotwired/stimulus"

export default class extends Controller {
  static targets = ["menu"]
  static values = { open: Boolean }

  toggle() {
    this.openValue = !this.openValue
  }

  openValueChanged() {
    this.menuTarget.classList.toggle("hidden", !this.openValue)
  }
}
<div data-controller="dropdown" data-dropdown-open-value="false">
  <button data-action="click->dropdown#toggle">Menu</button>
  <div data-dropdown-target="menu" class="hidden">
    <!-- Menu content -->
  </div>
</div>

Configuration Patterns

Credentials (Rails 7+)

# Edit credentials
bin/rails credentials:edit

# Environment-specific
bin/rails credentials:edit --environment production

Access pattern:

Rails.application.credentials.dig(:aws, :access_key_id)
Rails.application.credentials.stripe[:secret_key]

Environment Configuration

# config/environments/production.rb
Rails.application.configure do
  config.force_ssl = true
  config.log_level = :info
  config.active_job.queue_adapter = :sidekiq
end

Initializers

Name by feature, not gem:

# config/initializers/stripe.rb (not payments.rb)
Stripe.api_key = Rails.application.credentials.stripe[:secret_key]

Production Patterns

Strong Parameters

def order_params
  params.require(:order).permit(
    :shipping_address_id,
    :notes,
    line_items_attributes: [:id, :product_id, :quantity, :_destroy]
  )
end

Callbacks Best Practices

Avoid callback chains for business logic. Prefer service objects:

# Avoid
class Order < ApplicationRecord
  after_create :send_confirmation, :update_inventory, :notify_warehouse
end

# Prefer
class Orders::CreateService
  def call
    Order.transaction do
      order = Order.create!(params)
      OrderMailer.confirmation(order).deliver_later
      Inventory::DeductService.new(order).call
      Warehouse::NotifyJob.perform_later(order.id)
      order
    end
  end
end

Scopes

Define commonly used queries as scopes:

class Order < ApplicationRecord
  scope :recent, -> { where("created_at > ?", 30.days.ago) }
  scope :pending, -> { where(status: :pending) }
  scope :with_items, -> { includes(:line_items) }
  scope :for_user, ->(user) { where(user: user) }
end

Additional Resources

Reference Files

For detailed patterns and examples:

  • references/hotwire-patterns.md - Advanced Turbo and Stimulus patterns
  • references/api-conventions.md - API versioning, serialization, authentication patterns