用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
直接命令不会经过审查 Prompt;运行前请先检查来源。
npx skills add https://github.com/doanchienthangdev/omgkit --skill rails命令会保持在同一行。复制前请横向滚动并检查完整内容。
想先保存到本地?可下载 SkillsMP 当前能够提供的文件。
正在显示 SKILL.md
基于 SOC 职业分类
| name | rails |
| description | Enterprise Ruby on Rails development with Active Record, API mode, testing, and production patterns |
| category | frameworks |
| triggers | ["rails","ruby on rails","ror","active record","ruby api","rails api","ruby web","rubygems"] |
Enterprise-grade Ruby on Rails development following industry best practices. This skill covers Active Record, API mode, service objects, authentication, testing with RSpec, background jobs, and production deployment configurations used by top engineering teams.
Build scalable Ruby applications with confidence:
# app/models/user.rb
class User < ApplicationRecord
has_secure_password
# Associations
has_many :memberships, dependent: :destroy
has_many :organizations, through: :memberships
has_many :owned_organizations, class_name: 'Organization', foreign_key: :owner_id
has_many :projects, foreign_key: :created_by
# Validations
validates :email, presence: true, uniqueness: { case_sensitive: false },
format: { with: URI::MailTo::EMAIL_REGEXP }
validates :name, presence: true, length: { minimum: 2, maximum: 100 }
validates :password, length: { minimum: 8 }, if: -> { new_record? || password.present? }
validates :role, inclusion: { in: %w[admin user guest] }
# Callbacks
before_save :downcase_email
# Scopes
scope :active, -> { where(is_active: true) }
scope :admins, -> { where(role: 'admin') }
scope :search, ->(query) {
return all if query.blank?
where('name ILIKE :q OR email ILIKE :q', q: "%#{query}%")
}
# Enums
enum :role, { guest: 'guest', user: 'user', admin: 'admin' }, default: :user
# Instance methods
def admin?
role == 'admin'
end
def member_of?(organization)
organizations.exists?(organization.id)
end
private
def downcase_email
self.email = email.downcase
end
end
# app/models/organization.rb
class Organization < ApplicationRecord
belongs_to :owner, class_name: 'User'
has_many :memberships, dependent: :destroy
has_many :members, through: :memberships, source: :user
has_many :projects, dependent: :destroy
validates :name, presence: true, length: { maximum: 255 }
validates :slug, presence: true, uniqueness: true,
format: { with: /\A[a-z0-9-]+\z/ }
scope :for_user, ->(user) { joins(:memberships).where(memberships: { user_id: user.id }) }
before_validation :generate_slug, on: :create
private
def generate_slug
self.slug ||= name&.parameterize
end
end
# app/models/project.rb
class Project < ApplicationRecord
belongs_to :organization
belongs_to :creator, class_name: 'User', foreign_key: :created_by
has_many :tasks, dependent: :destroy
validates :name, presence: true, length: { maximum: 255 }
validates :name, uniqueness: { scope: :organization_id }
enum :status, { draft: 'draft', active: 'active', completed: 'completed', archived: 'archived' }
scope :active, -> { where(status: :active) }
include Discard::Model
default_scope -> { kept }
end
# app/serializers/user_serializer.rb
class UserSerializer
include JSONAPI::Serializer
attributes :id, :email, :name, :role, :is_active, :created_at, :updated_at
attribute :organization_count do |user|
user.organizations.count
end
has_many :organizations, serializer: OrganizationSerializer, if: Proc.new { |_record, params|
params && params[:include_organizations]
}
end
# app/serializers/organization_serializer.rb
class OrganizationSerializer
include JSONAPI::Serializer
attributes :id, :name, :slug, :created_at
attribute :member_count do |organization|
organization.members.count
end
belongs_to :owner, serializer: UserSerializer
end
# app/serializers/pagination_serializer.rb
class PaginationSerializer
def initialize()
= collection
= serializer_class
= options
{
serialized_data,
{
.current_page,
.limit_value,
.total_count,
.total_pages,
.current_page < .total_pages
}
}
.new(, ).serializable_hash[]
# app/controllers/application_controller.rb
class ApplicationController < ActionController::API
include ActionController::HttpAuthentication::Token::ControllerMethods
before_action :authenticate_user!
rescue_from ActiveRecord::RecordNotFound, with: :not_found
rescue_from ActiveRecord::RecordInvalid, with: :unprocessable_entity
private
def authenticate_user!
authenticate_or_request_with_http_token do |token, _options|
@current_user = JsonWebToken.decode(token)
end
end
def current_user
@current_user
end
def authorize_admin!
render_forbidden unless current_user.admin?
end
def not_found(exception)
render json: { error: { code: 'NOT_FOUND', message: exception.message } }, status: :not_found
end
def unprocessable_entity(exception)
render { { , exception.record.errors } },
render { { , } },
<
before_action , [, ]
before_action , [, , ]
users = .active.search(params[])
users = users.where( params[]) params[].present?
users = users.page(params[]).per(params[] || )
render .new(users, ).as_json
render .new(, ).serializable_hash
user = .new(user_params)
user.save!
render .new(user).serializable_hash,
.update!(user_params)
render .new().serializable_hash
.destroy
head
render .new(current_user, ).serializable_hash
= .find(params[])
params.().permit(, , , , )
<
skip_before_action , [, ]
user = .new(register_params)
user.save!
token = .encode( user.id)
render { .new(user).serializable_hash, token },
user = .find_by( params[]&.downcase)
user&.authenticate(params[]) && user.is_active?
token = .encode( user.id)
render { .new(user).serializable_hash, token }
render { { , } },
params.().permit(, , )
# app/services/application_service.rb
class ApplicationService
def self.call(...)
new(...).call
end
end
# app/services/users/create_user_service.rb
module Users
class CreateUserService < ApplicationService
def initialize(params)
@params = params
end
def call
user = User.new(@params)
user.save!
SendWelcomeEmailJob.perform_later(user.id)
Result.success(user: user)
rescue ActiveRecord::RecordInvalid => e
Result.failure(errors: e.record.errors)
end
end
end
# app/services/organizations/create_organization_service.rb
module Organizations
class CreateOrganizationService < ApplicationService
def initialize(owner:, params:)
@owner = owner
@params = params
end
.transaction
organization = .create!(.merge( ))
.create!( , organization, )
.success( organization)
=> e
.failure( e.record.errors)
,
()
= success
= data
= errors
!
.success(data = {})
new( , data)
.failure()
new( , errors)
# lib/json_web_token.rb
class JsonWebToken
SECRET_KEY = Rails.application.credentials.secret_key_base
def self.encode(payload, exp = 24.hours.from_now)
payload[:exp] = exp.to_i
JWT.encode(payload, SECRET_KEY)
end
def self.decode(token)
decoded = JWT.decode(token, SECRET_KEY)[0]
User.find(decoded['user_id'])
rescue JWT::DecodeError, ActiveRecord::RecordNotFound
nil
end
end
# app/jobs/application_job.rb
class ApplicationJob < ActiveJob::Base
queue_as :default
retry_on StandardError, wait: :exponentially_longer, attempts: 3
discard_on ActiveJob::DeserializationError
end
# app/jobs/send_welcome_email_job.rb
class SendWelcomeEmailJob < ApplicationJob
queue_as :mailers
def perform(user_id)
user = User.find(user_id)
UserMailer.welcome_email(user).deliver_now
end
end
# spec/models/user_spec.rb
require 'rails_helper'
RSpec.describe User, type: :model do
describe 'validations' do
subject { build(:user) }
it { should validate_presence_of(:email) }
it { should validate_uniqueness_of(:email).case_insensitive }
it { should validate_presence_of(:name) }
end
describe 'associations' do
it { should have_many(:memberships).dependent(:destroy) }
it { should have_many(:organizations).through(:memberships) }
end
describe 'scopes' do
describe '.active' do
it 'returns only active users' do
active_user = create(:user, is_active: true)
inactive_user = create(:user, is_active: false)
expect(User.active).to include(active_user)
expect(User.active).not_to include(inactive_user)
end
end
describe '.search' do
it 'searches by name and email' do
user = create(:user, name: 'John Doe', )
expect(.search()).to (user)
expect(.search()).not_to (user)
describe
it
admin = build(, )
expect(admin.admin?).to be
.describe ,
let() { create(, ) }
let() { { => } }
describe
before { create_list(, ) }
it
get , auth_headers
expect(response).to have_http_status()
expect(json_response[]).to be_an()
expect(json_response[]).to (, )
it
user = create()
headers = { => }
get , headers
expect(response).to have_http_status()
describe
let() { { { , , } } }
it
expect {
post , valid_params, auth_headers
}.to change(, ).by()
expect(response).to have_http_status()
.parse(response.body)
.define
factory
sequence() { || }
name { .name }
password { }
role { }
is_active { }
trait
role { }
# config/initializers/rack_attack.rb
class Rack::Attack
throttle('requests by ip', limit: 100, period: 1.minute) do |request|
request.ip
end
throttle('login attempts', limit: 5, period: 1.minute) do |request|
if request.path == '/api/v1/auth/login' && request.post?
request.ip
end
end
end
# app/controllers/api/v1/organizations_controller.rb
def show
@organization = Rails.cache.fetch("organization:#{params[:id]}", expires_in: 5.minutes) do
Organization.includes(:owner, :members).find(params[:id])
end
render json: OrganizationSerializer.new(@organization).serializable_hash
end