بنقرة واحدة
rails-expert
Deep expertise in Ruby on Rails - ActiveRecord, patterns, performance, security, testing
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
القائمة
Deep expertise in Ruby on Rails - ActiveRecord, patterns, performance, security, testing
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
استنادا إلى تصنيف SOC المهني
When the user wants help with paid advertising campaigns on Google Ads, Meta (Facebook/Instagram), LinkedIn, Twitter/X, or other ad platforms. Also use when the user mentions 'PPC,' 'paid media,' 'ROAS,' 'CPA,' 'ad campaign,' 'retargeting,' 'audience targeting,' 'Google Ads,' 'Facebook ads,' 'LinkedIn ads,' 'ad budget,' 'cost per click,' 'ad spend,' or 'should I run ads.' Use this for campaign strategy, audience targeting, bidding, and optimization. For bulk ad creative generation and iteration, see ad-creative. For landing page optimization, see cro.
Persistent engineering knowledge vault with semantic search. Save decisions, patterns, debug solutions, and insights as Zettelkasten notes in Obsidian with automatic embedding indexing for semantic retrieval. Use this skill whenever the user says "/memo", "запомни это", "сохрани в базу", "save this", "remember this", "добавь в базу знаний", "log this pattern", or any variation of wanting to persist knowledge. Also trigger for "/memo find", "/memo search", "что я решал по X", "find in vault", "search vault", "найди в базе" to search notes — both keyword and semantic. Trigger for "/memo dedup", "/memo stats", "/memo project", "/memo reindex". This is the bridge between Claude Code sessions and long-term engineering memory across all projects.
Use when starting any new task to select the right GSD mode (fast/quick/plan-phase) and the right model tier (Haiku/Sonnet/Opus) for subagents — prevents 5-10× cost overpay on routine work
Pack the whole repo (or a remote one) into one AI-friendly file via Repomix. Use for architectural reviews, cross-repo handoff, full-codebase audits — not for single-file lookups. Triggers on "pack repo", "feed codebase to AI", "снапшот", "analyze remote repo".
花叔Design(Huashu-Design)——用HTML做高保真原型、交互Demo、幻灯片、动画、设计变体探索+设计方向顾问+专家评审的一体化设计能力。HTML是工具不是媒介,根据任务embody不同专家(UX设计师/动画师/幻灯片设计师/原型师),避免web design tropes。触发词:做原型、设计Demo、交互原型、HTML演示、动画Demo、设计变体、hi-fi设计、UI mockup、prototype、设计探索、做个HTML页面、做个可视化、app原型、iOS原型、移动应用mockup、导出MP4、导出GIF、60fps视频、设计风格、设计方向、设计哲学、配色方案、视觉风格、推荐风格、选个风格、做个好看的、评审、好不好看、review this design、带解说的动画、解说视频、概念解释视频、长视频科普、配音动画、voiceover、narration、TTS+动画、5分钟讲清楚什么是XX。**主干能力**:Junior Designer工作流(先给假设+reasoning+placeholder再迭代)、反AI slop清单、React+Babel最佳实践、Tweaks变体切换、Speaker Notes演示、Starter Components(幻灯片外壳/变体画布/动画引擎/设备边框/解说Stage)、App原型专属守则(默认从Wikimedia/Met/Unsplash取真图、每台iPhone包AppPhone状态管理器可交互、交付前跑Playwright点击测试)、Playwright验证、HTML动画→MP4/GIF视频导出(25fps基础 + 60fps插帧 + palette优化GIF + 6首场景化BGM + 自动fade)、**带解说的长动画pipeline**(豆包TTS生人声+实测时长生timeline.json+NarrationStage驱动画面+ducking混音→交付HTML实播+发布MP4双形态;铁律:整片是一个连续的运动叙事,禁PowerPoint切换)。**需求模糊时的Fallback**:设计方向顾问模式——从5流派×20种设计哲学(Pentagram信息建筑/Field.io运动诗学/Kenya Hara东方极简/Sagmeister实验先锋等)推荐3个差异化方向,展示24个预制showcase(8场景×3风格),并行生成3个视觉Demo让用户选
Use BEFORE coding any new feature, MVP, pricing/billing change, launch, or pivot. Acts as a product validation gate for solo founders — validates target user, JTBD, pain intensity, current alternative, success metric, distribution channel, structural advantage vs competitors, unit economics with SaaS-graveyard gate, cheapest experiment, and top risk. RIGID — do not proceed to technical planning until product context is documented in `.planning/product/<slug>.md` or risk is explicitly accepted. Triggers on "build", "ship", "add feature", "MVP", "launch", "pivot", "pricing", "billing", before /plan, /tdd, /gsd-plan-phase, /gsd-discuss-phase, or when user describes a feature without naming a measurable success metric.
| name | Rails Expert |
| description | Deep expertise in Ruby on Rails - ActiveRecord, patterns, performance, security, testing |
This skill provides deep Rails expertise including ActiveRecord optimization, architectural patterns, security best practices, Hotwire integration, and testing strategies.
# ❌ N+1 — 1 + N queries
Post.all.each do |post|
puts post.author.name
end
# ✅ Eager loading — 2 queries
Post.includes(:author).each do |post|
puts post.author.name
end
# ✅ Nested eager loading
Post.includes(author: :profile, comments: :user).all
# ✅ Preload vs Includes vs Eager_load
Post.preload(:author) # Separate query
Post.includes(:author) # Smart (preload or eager_load)
Post.eager_load(:author) # LEFT OUTER JOIN
# ❌ Dangerous - permits everything
params.permit!
# ❌ Sensitive fields
params.require(:user).permit(:name, :email, :admin)
# ✅ Safe - explicit whitelist
params.require(:user).permit(:name, :email, :bio)
# ✅ Admin fields with explicit check
if current_user.admin?
params.require(:user).permit(:name, :email, :admin)
else
params.require(:user).permit(:name, :email)
end
# ❌ Side effects in callbacks
class User < ApplicationRecord
after_create :send_welcome_email # Hard to test, implicit
end
# ✅ Explicit in controller/service
class UsersController < ApplicationController
def create
@user = User.create!(user_params)
UserMailer.welcome(@user).deliver_later
end
end
# When callbacks ARE appropriate:
# - Data normalization (before_validation)
# - Timestamps
# - Counter cache updates
# app/services/users/create_user.rb
module Users
class CreateUser
def initialize(params, current_user: nil)
@params = params
@current_user = current_user
end
def call
user = User.new(@params)
ActiveRecord::Base.transaction do
user.save!
create_profile(user)
enqueue_welcome_email(user)
end
Result.new(success: true, user: user)
rescue ActiveRecord::RecordInvalid => e
Result.new(success: false, errors: e.record.errors)
end
private
def create_profile(user)
Profile.create!(user: user)
end
def enqueue_welcome_email(user)
UserMailer.welcome(user).deliver_later
end
end
end
# Usage
result = Users::CreateUser.new(user_params).call
if result.success?
redirect_to result.user
else
render :new, status: :unprocessable_entity
end
# app/queries/active_users_query.rb
class ActiveUsersQuery
def initialize(relation = User.all)
@relation = relation
end
def call
@relation
.where(status: :active)
.where("last_login_at > ?", 30.days.ago)
.order(last_login_at: :desc)
end
def with_posts
call.joins(:posts).distinct
end
end
# Usage
ActiveUsersQuery.new.call
ActiveUsersQuery.new(User.premium).with_posts
# app/forms/registration_form.rb
class RegistrationForm
include ActiveModel::Model
include ActiveModel::Attributes
attribute :email, :string
attribute :password, :string
attribute :terms_accepted, :boolean
validates :email, presence: true, format: { with: URI::MailTo::EMAIL_REGEXP }
validates :password, presence: true, length: { minimum: 8 }
validates :terms_accepted, acceptance: true
def save
return false unless valid?
User.create!(email: email, password: password)
end
end
# Migration
class AddIndexesToPosts < ActiveRecord::Migration[7.1]
def change
add_index :posts, :user_id
add_index :posts, :status
add_index :posts, [:user_id, :status]
add_index :posts, :created_at
add_index :posts, :slug, unique: true
end
end
# Select only needed columns
User.select(:id, :name, :email).all
# Use exists? instead of count
User.where(email: email).exists? # Better
User.where(email: email).count > 0 # Worse
# Pluck for simple values
User.where(active: true).pluck(:email) # Returns array of emails
# find_each for large datasets
User.find_each(batch_size: 1000) do |user|
user.process_something
end
# Avoid loading all records
User.active.limit(100) # Not User.active.all
# Fragment caching
<% cache @post do %>
<%= render @post %>
<% end %>
# Russian doll caching
<% cache @post do %>
<% @post.comments.each do |comment| %>
<% cache comment do %>
<%= render comment %>
<% end %>
<% end %>
<% end %>
# Low-level caching
Rails.cache.fetch("user_#{user.id}_stats", expires_in: 1.hour) do
user.calculate_stats
end
# Counter cache
belongs_to :user, counter_cache: true
# Requires: add_column :users, :posts_count, :integer, default: 0
<%# app/views/posts/index.html.erb %>
<%= turbo_frame_tag "posts" do %>
<%= render @posts %>
<% end %>
<%# app/views/posts/_post.html.erb %>
<%= turbo_frame_tag dom_id(post) do %>
<article>
<h2><%= post.title %></h2>
<%= link_to "Edit", edit_post_path(post) %>
</article>
<% end %>
# app/controllers/posts_controller.rb
def create
@post = Post.new(post_params)
respond_to do |format|
if @post.save
format.turbo_stream
format.html { redirect_to @post }
else
format.html { render :new, status: :unprocessable_entity }
end
end
end
<%# app/views/posts/create.turbo_stream.erb %>
<%= turbo_stream.prepend "posts", @post %>
<%= turbo_stream.update "flash", partial: "shared/flash" %>
// app/javascript/controllers/search_controller.js
import { Controller } from "@hotwired/stimulus"
export default class extends Controller {
static targets = ["input", "results"]
static values = { url: String }
search() {
clearTimeout(this.timeout)
this.timeout = setTimeout(() => {
this.performSearch()
}, 300)
}
async performSearch() {
const query = this.inputTarget.value
const response = await fetch(`${this.urlValue}?q=${query}`)
this.resultsTarget.innerHTML = await response.text()
}
}
<div data-controller="search" data-search-url-value="<%= search_path %>">
<input data-search-target="input" data-action="input->search#search">
<div data-search-target="results"></div>
</div>
class PostsController < ApplicationController
private
def post_params
params.require(:post).permit(
:title,
:body,
:published,
tags: [],
metadata: [:key, :value]
)
end
end
# app/policies/post_policy.rb
class PostPolicy < ApplicationPolicy
def show?
record.published? || record.user == user
end
def update?
record.user == user || user.admin?
end
def destroy?
record.user == user || user.admin?
end
class Scope < Scope
def resolve
if user.admin?
scope.all
else
scope.where(user: user).or(scope.published)
end
end
end
end
# Controller
class PostsController < ApplicationController
def show
@post = Post.find(params[:id])
authorize @post
end
def index
@posts = policy_scope(Post)
end
end
# config/initializers/rack_attack.rb
class Rack::Attack
throttle("req/ip", limit: 100, period: 1.minute) do |req|
req.ip
end
throttle("logins/ip", limit: 5, period: 20.seconds) do |req|
if req.path == "/login" && req.post?
req.ip
end
end
end
# spec/models/user_spec.rb
RSpec.describe User, type: :model do
describe "validations" do
it { is_expected.to validate_presence_of(:email) }
it { is_expected.to validate_uniqueness_of(:email).case_insensitive }
end
describe "associations" do
it { is_expected.to have_many(:posts).dependent(:destroy) }
it { is_expected.to belong_to(:organization).optional }
end
describe "#full_name" do
let(:user) { build(:user, first_name: "John", last_name: "Doe") }
it "returns the full name" do
expect(user.full_name).to eq("John Doe")
end
end
end
# spec/factories/users.rb
FactoryBot.define do
factory :user do
sequence(:email) { |n| "user#{n}@example.com" }
password { "password123" }
trait :admin do
admin { true }
end
trait :with_posts do
transient do
posts_count { 3 }
end
after(:create) do |user, evaluator|
create_list(:post, evaluator.posts_count, user: user)
end
end
end
end
# Usage
create(:user)
create(:user, :admin)
create(:user, :with_posts, posts_count: 5)
# spec/requests/posts_spec.rb
RSpec.describe "Posts", type: :request do
let(:user) { create(:user) }
describe "GET /posts" do
it "returns success" do
get posts_path
expect(response).to have_http_status(:ok)
end
end
describe "POST /posts" do
context "when authenticated" do
before { sign_in user }
it "creates a post" do
expect {
post posts_path, params: { post: { title: "Test", body: "Content" } }
}.to change(Post, :count).by(1)
end
end
context "when not authenticated" do
it "redirects to login" do
post posts_path, params: { post: { title: "Test" } }
expect(response).to redirect_to(new_user_session_path)
end
end
end
end
# spec/system/posts_spec.rb
RSpec.describe "Managing posts", type: :system do
let(:user) { create(:user) }
before do
driven_by(:rack_test)
sign_in user
end
it "creates a new post" do
visit new_post_path
fill_in "Title", with: "My Post"
fill_in "Body", with: "Post content"
click_button "Create Post"
expect(page).to have_content("Post was successfully created")
expect(page).to have_content("My Post")
end
end
| Gem | Purpose |
|---|---|
devise | Authentication |
pundit | Authorization |
sidekiq | Background jobs |
pagy | Pagination |
ransack | Search/filtering |
friendly_id | Slugs |
paper_trail | Audit trail |
bullet | N+1 detection |
annotate | Model annotations |
rubocop-rails | Rails linting |