rails
Ruby on Rails is a full-stack web framework following convention over configuration. It provides ActiveRecord ORM, Action Controller, Action View templates, Action Cable for WebSockets, and generators for rapid application development.
What this skill does
# Ruby on Rails
Rails is an opinionated full-stack framework that favors convention over configuration. It includes everything needed to build database-backed web apps: ORM, routing, views, mailers, jobs, and WebSocket support.
## Installation
```bash
# Create new Rails app with PostgreSQL
gem install rails
rails new myapp --database=postgresql --css=tailwind
cd myapp
rails db:create
```
## Project Structure
```
# Standard Rails project layout
app/
├── controllers/ # Request handlers
├── models/ # ActiveRecord models
├── views/ # ERB/HTML templates
├── channels/ # Action Cable channels
├── jobs/ # Background jobs
├── mailers/ # Email classes
└── serializers/ # API serializers
config/
├── routes.rb # URL routing
├── database.yml # DB config
└── environments/ # Per-env settings
db/
├── migrate/ # Schema migrations
├── schema.rb # Current schema
└── seeds.rb # Seed data
```
## Models
```ruby
# app/models/article.rb — ActiveRecord model
class Article < ApplicationRecord
belongs_to :author, class_name: "User"
has_many :comments, dependent: :destroy
validates :title, presence: true, length: { maximum: 200 }
validates :slug, presence: true, uniqueness: true
validates :body, presence: true
scope :published, -> { where(published: true) }
scope :recent, -> { order(created_at: :desc) }
before_validation :generate_slug, on: :create
private
def generate_slug
self.slug = title&.parameterize
end
end
```
## Migrations
```ruby
# db/migrate/20240101000000_create_articles.rb — database migration
class CreateArticles < ActiveRecord::Migration[7.1]
def change
create_table :articles do |t|
t.string :title, null: false, limit: 200
t.string :slug, null: false, index: { unique: true }
t.text :body, null: false
t.references :author, null: false, foreign_key: { to_table: :users }
t.boolean :published, default: false
t.timestamps
end
end
end
```
## Controllers
```ruby
# app/controllers/articles_controller.rb — RESTful controller
class ArticlesController < ApplicationController
before_action :authenticate_user!, except: [:index, :show]
before_action :set_article, only: [:show, :update, :destroy]
def index
@articles = Article.published.recent
.includes(:author)
.page(params[:page])
.per(20)
render json: @articles, include: [:author]
end
def show
render json: @article
end
def create
@article = current_user.articles.build(article_params)
if @article.save
render json: @article, status: :created
else
render json: { errors: @article.errors }, status: :unprocessable_entity
end
end
def destroy
@article.destroy
head :no_content
end
private
def set_article
@article = Article.find(params[:id])
end
def article_params
params.require(:article).permit(:title, :body)
end
end
```
## Routes
```ruby
# config/routes.rb — URL routing
Rails.application.routes.draw do
root "pages#home"
resources :articles, only: [:index, :show, :create, :update, :destroy]
namespace :api do
namespace :v1 do
resources :articles, only: [:index, :show]
end
end
mount ActionCable.server => "/cable"
end
```
## Views
```erb
<!-- app/views/articles/index.html.erb — list view template -->
<h1>Articles</h1>
<% @articles.each do |article| %>
<article>
<h2><%= link_to article.title, article_path(article) %></h2>
<p>By <%= article.author.name %> — <%= time_ago_in_words(article.created_at) %> ago</p>
<p><%= truncate(article.body, length: 200) %></p>
</article>
<% end %>
<%= paginate @articles %>
```
## Action Cable (WebSockets)
```ruby
# app/channels/chat_channel.rb — WebSocket channel
class ChatChannel < ApplicationCable::Channel
def subscribed
stream_from "chat_#{params[:room_id]}"
end
def receive(data)
ActionCable.server.broadcast("chat_#{params[:room_id]}", {
user: current_user.name,
message: data["message"]
})
end
end
```
## Background Jobs
```ruby
# app/jobs/send_notification_job.rb — Active Job
class SendNotificationJob < ApplicationJob
queue_as :default
retry_on StandardError, wait: :polynomially_longer, attempts: 5
def perform(user, message)
NotificationService.send(user, message)
end
end
# Enqueue: SendNotificationJob.perform_later(user, "Hello!")
```
## Testing
```ruby
# test/models/article_test.rb — model test
require "test_helper"
class ArticleTest < ActiveSupport::TestCase
test "validates title presence" do
article = Article.new(body: "content", author: users(:one))
assert_not article.valid?
assert_includes article.errors[:title], "can't be blank"
end
test "published scope" do
assert_includes Article.published, articles(:published_one)
assert_not_includes Article.published, articles(:draft_one)
end
end
```
## Key Commands
```bash
# Common Rails commands
rails generate model Article title:string body:text author:references
rails generate controller Articles index show create
rails db:migrate
rails db:seed
rails console # Interactive REPL
rails routes # Show all routes
rails test # Run tests
```
## Key Patterns
- Use `strong_parameters` (`params.permit`) to whitelist input — never trust user data
- Use `includes`/`eager_load` to prevent N+1 queries
- Use scopes for reusable query logic on models
- Use `before_action` for authentication and resource loading
- Use Active Job + Sidekiq/GoodJob for background processing
- Use `rails credentials:edit` for secrets — never commit them
Related in General
modeling-omnistudio-epc-catalog
IncludedSalesforce Industries CME EPC product-modeling skill for Product2-based catalog creation. Use when creating EPC products, configuring product attributes, building offer bundles with Product Child Items, or reviewing EPC DataPack JSON metadata for product catalog changes. TRIGGER when: user creates or updates Product2 EPC records, AttributeAssignment payloads, AttributeMetadata/AttributeDefaultValues, Offer bundles, or ProductChildItem relationships. DO NOT TRIGGER when: designing OmniScripts/FlexCards/Integration Procedures (use building-omnistudio-omniscript, building-omnistudio-flexcard, or building-omnistudio-integration-procedure), implementing Apex business logic (use generating-apex), or troubleshooting deployment pipelines (use deploying-metadata).
relationship-science-coach
IncludedUse this skill for direct, practical adult relationship coaching: couples conflict, repair, trust, marriage, dating, flirting, attachment patterns, emotional connection, sex, desire differences, eroticism, kink negotiation, affection, love languages, breakups, and long-term passion. Draw on Gottman, EFT and Hold Me Tight, attachment science, modern sex research, Perel, Nagoski, Kerner, Schnarch, Love and Stosny, and flexible love-language tools. Be concrete and low-hedge. Redirect only for imminent danger, abuse, coercive control, minors, non-consent, self-harm, stalking, or medical/legal/psychiatric decisions.
building-sf-integrations
IncludedSalesforce integration architecture and runtime plumbing with 120-point scoring. Use this skill to set up Named Credentials, External Credentials, External Services, REST/SOAP callout patterns, Platform Events, and Change Data Capture. TRIGGER when: user sets up Named Credentials, External Services, REST/SOAP callouts, Platform Events, CDC, or touches .namedCredential-meta.xml files. DO NOT TRIGGER when: Connected App/OAuth config (use configuring-connected-apps), Apex-only logic (use generating-apex), or data import/export (use handling-sf-data).
venue-templates
IncludedAccess comprehensive LaTeX templates, formatting requirements, and submission guidelines for major scientific publication venues (Nature, Science, PLOS, IEEE, ACM), academic conferences (NeurIPS, ICML, CVPR, CHI), research posters, and grant proposals (NSF, NIH, DOE, DARPA). This skill should be used when preparing manuscripts for journal submission, conference papers, research posters, or grant proposals and need venue-specific formatting requirements and templates.
let-fate-decide
IncludedDraws the 12 Houses of the Zodiac Tarot spread to inject entropy into planning when prompts are vague, ambiguous, or casually delegated. Interprets the spread to guide next steps. Use when the user says 'let fate decide', 'YOLO', 'whatever', 'idk', or other nonchalant phrases, makes Yu-Gi-Oh references, or when you are about to arbitrarily pick between multiple reasonable approaches. Prefer over ask-questions-if-underspecified when the user's tone is casual or playful rather than precision-seeking.
net-ops
IncludedCross-platform network troubleshooting (Windows, macOS, Linux) via local or remote shell. Use for: DNS broken, can't resolve hostnames, nslookup/dig works but apps fail, NRPT, WFP, scutil, /etc/resolver, systemd-resolved, /etc/resolv.conf, NetworkManager, VPN DNS leak residue (ProtonVPN/Mullvad/WireGuard/AnyConnect), AV/firewall blocking DNS or DoH, Tailscale DNS interaction, intermittent connectivity, remote diagnostics over SSH.