| name | ruby-rules |
| description | Ruby coding rules: style, patterns, security, testing. Triggers: .rb, Gemfile, .gemspec, Rails, ActiveRecord, Sidekiq, RSpec, Sorbet, rubocop. |
| effort | medium |
| user-invocable | false |
| allowed-tools | Read |
Ruby Rules
These rules come from app/rules/ruby/ in ai-toolkit. They cover
the project's standards for coding style, frameworks, patterns,
security, and testing in Ruby. Apply them when writing or
reviewing Ruby code.
Ruby Coding Style
Naming
- PascalCase: classes, modules.
- snake_case: methods, variables, file names, directories.
- UPPER_SNAKE: constants (
MAX_RETRIES = 3).
- Prefix boolean methods with predicate:
empty?, valid?, admin?.
- Suffix dangerous methods with
!: save!, sort!, strip!.
- Use
_ prefix for intentionally unused variables: _unused.
Methods
- Keep methods short: 5-10 lines ideal. Extract helper methods.
- Use keyword arguments for methods with >2 parameters.
- Use default parameter values instead of checking for nil.
- Use
def method_name = expression (Ruby 3.0+) for one-liners.
- Prefer
each over for loops. Use block-style iteration.
- Return values implicitly (last expression). Use explicit
return only for early exit.
Blocks, Procs, Lambdas
- Use
{ } for single-line blocks. Use do...end for multi-line blocks.
- Use
&:method shorthand: names.map(&:upcase).
- Use lambdas for strict argument checking. Use procs for flexible arity.
- Use
yield for single-block methods. Use explicit &block for storing/forwarding.
Classes
- Use
attr_reader, attr_writer, attr_accessor for simple getters/setters.
- Use
Struct for simple data containers. Use Data.define (Ruby 3.2+) for immutable.
- Use modules for mixins:
include for instance methods, extend for class methods.
- Use
frozen_string_literal: true magic comment at the top of every file.
- Use
private / protected keywords to control method visibility.
Collections
- Use
map, select, reject, reduce, flat_map for transformations.
- Use
each_with_object over inject when accumulating into a mutable object.
- Use
dig for safe nested hash/array access: data.dig(:user, :address, :city).
- Use
Hash#fetch with default for explicit missing-key handling.
- Use
Enumerable#lazy for large collection processing.
Pattern Matching (Ruby 3+)
- Use
case/in for structural pattern matching on hashes and arrays.
- Use
=> pin operator to match against existing variables.
- Use
in pattern for conditional deconstruction in if statements.
- Use pattern matching for API response parsing and validation.
Formatting
- Use RuboCop for automated style enforcement.
- Use
.rubocop.yml committed to the repository for project conventions.
- Max line length: 120 characters.
- Two-space indentation. No tabs.
- Use trailing commas in multi-line arrays and hashes.
Ruby Frameworks
Rails (General)
- Follow Rails conventions: convention over configuration.
- Use
rails generate for scaffolding models, controllers, migrations.
- Use strong parameters:
params.require(:user).permit(:name, :email).
- Use concerns for shared controller/model behavior.
- Use
config/routes.rb with resourceful routing: resources :users.
- Use environment-specific configuration in
config/environments/.
ActiveRecord
- Use migrations for all schema changes. Never modify the database directly.
- Use
has_many, belongs_to, has_many :through for associations.
- Use scopes for reusable query chains:
scope :active, -> { where(active: true) }.
- Use
includes() for eager loading to prevent N+1 queries.
- Use
find_each for batch processing large record sets.
- Use
transaction blocks for atomic multi-record operations.
ActionController
- Keep controllers thin: max 7 RESTful actions per controller.
- Use
before_action for authentication and authorization checks.
- Use
respond_to for content negotiation (JSON, HTML).
- Use
rescue_from for centralized error handling in controllers.
- Use
render json: with serializers (e.g., ActiveModelSerializers, Blueprinter).
Background Jobs
- Use Sidekiq for Redis-backed background job processing.
- Use ActiveJob as the abstraction layer over queue backends.
- Use
perform_later for async execution. Use perform_now only in tests.
- Set
retry count and discard_on / retry_on for error handling.
- Use
Sidekiq::Cron or clockwork for scheduled recurring jobs.
Sinatra / Hanami
- Use Sinatra for lightweight APIs and microservices.
- Use Hanami for structured, modular Ruby web applications.
- Use Hanami actions (single-purpose) instead of fat controllers.
- Use Hanami repositories for data access abstraction.
API Mode
- Use
rails new --api for API-only applications (no views, sessions).
- Use
Jbuilder or Blueprinter for JSON serialization.
- Use
Rack::Attack for rate limiting and throttling.
- Use versioned API namespaces:
namespace :v1 do ... end.
- Use pagination with
kaminari or pagy for collection endpoints.
Hotwire / Turbo
- Use Turbo Frames for partial page updates without JavaScript.
- Use Turbo Streams for real-time server-pushed DOM updates.
- Use Stimulus for lightweight JavaScript behavior on HTML elements.
- Keep JavaScript minimal: let the server render HTML.
Ruby Patterns
Error Handling
- Rescue specific exceptions. Never bare
rescue (catches StandardError).
- Create domain exception hierarchies:
class AppError < StandardError; end.
- Use
raise with message and optional cause: raise AppError, "msg".
- Use
retry with a counter for transient failures.
- Use
ensure for cleanup. Use else for code that runs only on success.
Service Objects
- Use single-purpose service classes with a
call method.
- Use
Dry::Monads Result type for operation outcomes.
- Return
Success(value) or Failure(error) from service calls.
- Chain services with
bind / fmap for pipeline composition.
- Keep services stateless. Pass all data through method parameters.
Value Objects
- Use
Data.define (Ruby 3.2+) for immutable value objects.
- Use
Struct with keyword_init: true for lightweight data containers.
- Use
freeze on objects that should not be mutated after creation.
- Override
== and hash for value-based equality when needed.
Metaprogramming (Use Sparingly)
- Use
define_method over method_missing when possible.
- Always define
respond_to_missing? alongside method_missing.
- Use
class_attribute (Rails) for inheritable class-level configuration.
- Prefer explicit code over DSL magic for maintainability.
- Document metaprogrammed methods with YARD
@!method directives.
Concurrency
- Use
Concurrent::Future (concurrent-ruby) for parallel operations.
- Use
Concurrent::Promise for composable async chains.
- Use thread pools (
Concurrent::FixedThreadPool) for bounded concurrency.
- Use
Ractor (Ruby 3+) for true parallel execution without GVL.
- Use
Mutex and Queue for thread-safe shared state access.
Module Patterns
- Use
include for shared behavior (instance methods).
- Use
prepend for wrapping/overriding existing methods (decorating).
- Use
extend for adding class-level methods from a module.
- Use
Concern (ActiveSupport) for Rails modules with class methods.
- Keep modules focused: one responsibility per module.
Decorator Pattern
- Use
SimpleDelegator for transparent object wrapping.
- Use
Draper gem for view-layer decorators in Rails.
- Prefer composition (wrapping) over inheritance for adding behavior.
- Use
Module#prepend for method-level decoration without wrapper classes.
Anti-Patterns
- Monkey-patching core classes: use refinements or wrapper methods.
- Callbacks for business logic (Rails): use service objects.
- God objects: split into focused classes with single responsibility.
- N+1 queries: use
includes(), preload(), eager_load().
- Using
eval or send with user input: remote code execution risk.
Ruby Security
Mass Assignment
- Use strong parameters in controllers:
params.require(:user).permit(:name, :email).
- Never use
params.permit! or pass unsanitized params to create/update.
- Use
attr_readonly for fields that should never be updated after creation.
- Audit
update_columns and update_attribute usage (bypass validations).
SQL Injection
- Use ActiveRecord query interface with parameterized conditions.
- Use
where(name: value) hash syntax or where("name = ?", value) placeholders.
- Never interpolate user input into
where() strings: where("name = '#{input}'").
- Use
sanitize_sql_array if building raw SQL fragments is unavoidable.
- Audit all
find_by_sql, execute, and Arel.sql calls.
XSS Prevention
- Rails auto-escapes ERB output with
<%= %>. Never use raw() with user data.
- Use
sanitize() helper for allowing limited HTML tags.
- Set
Content-Security-Policy header in config/initializers/content_security_policy.rb.
- Use
content_tag helper for safe HTML generation.
- Mark strings as
html_safe only when content is guaranteed safe.
CSRF Protection
- Use
protect_from_forgery with: :exception in ApplicationController.
- Use
authenticity_token in all forms (Rails includes it by default).
- Use
X-CSRF-Token header for AJAX requests from JavaScript.
- Exempt only webhook endpoints from CSRF (with payload signature verification).
Authentication
- Use Devise or
has_secure_password for authentication.
- Use
bcrypt for password hashing (included with has_secure_password).
- Implement account lockout after N failed login attempts.
- Use
SecureRandom.urlsafe_base64 for generating tokens.
- Store sessions server-side (Redis/database) instead of cookie store in production.
Authorization
- Use Pundit or CanCanCan for authorization logic.
- Define policies per model:
class UserPolicy < ApplicationPolicy.
- Check ownership in policies, not just role membership.
- Use
authorize @resource in every controller action.
- Default deny: require explicit authorization for all actions.
Secrets Management
- Use
Rails.application.credentials for encrypted secrets.
- Use
EDITOR="vim" bin/rails credentials:edit to manage secrets.
- Use per-environment credentials:
credentials/production.yml.enc.
- Never commit
master.key or production.key to version control.
- Use environment variables for CI/CD and containerized deployments.
Dependency Security
- Run
bundle audit check --update for known vulnerability scanning.
- Use
Dependabot for automated dependency update PRs.
- Pin gem versions in
Gemfile. Review Gemfile.lock changes carefully.
- Use
bundler-audit in CI pipeline as a required check.
- Update Rails promptly when security patches are released.
Ruby Testing
Framework
- Use RSpec as the primary test framework.
- Use Minitest for lightweight, stdlib-based testing.
- Use FactoryBot for test data generation.
- Use WebMock or VCR for HTTP request stubbing.
File Naming
- RSpec:
spec/models/user_spec.rb mirroring app/models/user.rb.
- Minitest:
test/models/user_test.rb mirroring source structure.
- Support files:
spec/support/ for shared helpers and configurations.
- Use
spec/rails_helper.rb for Rails-specific RSpec configuration.
Structure (RSpec)
- Use
describe for the class/method under test. Use context for scenarios.
- Use
it for individual test cases with clear descriptions.
- Use
let for lazy-evaluated test data. Use let! for eager evaluation.
- Use
before / after blocks for setup and teardown.
- Use
subject for the primary object under test.
Matchers (RSpec)
- Use
expect(result).to eq(expected) for equality.
- Use
expect(result).to be_truthy, be_falsy, be_nil.
- Use
expect { action }.to raise_error(FooError) for exception testing.
- Use
expect { action }.to change { User.count }.by(1) for side effects.
- Use
expect(list).to include(item), contain_exactly(a, b, c).
- Use
expect(result).to match(hash_including(key: value)) for partial matching.
Mocking (RSpec)
- Use
instance_double(UserService) for verified doubles.
- Stub:
allow(mock).to receive(:find).with(1).and_return(user).
- Verify:
expect(mock).to have_received(:save).once.
- Use
receive_messages(method1: val1, method2: val2) for multi-stubbing.
- Use
class_double for stubbing class methods.
- Avoid stubbing the object under test. Stub only collaborators.
FactoryBot
- Define factories in
spec/factories/: FactoryBot.define { factory :user { ... } }.
- Use
create for persisted records. Use build for in-memory only.
- Use traits for variations:
create(:user, :admin).
- Use
build_stubbed for fast tests that do not need database.
- Use sequences for unique attributes:
sequence(:email) { |n| "user#{n}@test.com" }.
Rails Testing
- Use
request specs for API endpoint testing (RSpec).
- Use
system specs with Capybara for browser integration tests.
- Use
DatabaseCleaner or use_transactional_fixtures for test isolation.
- Use
travel_to for time-dependent test scenarios.
- Use
ActiveJob::TestHelper for testing background jobs inline.
Best Practices
- Test behavior, not implementation. Do not test private methods directly.
- Use
shared_examples for testing common behavior across classes.
- Use
aggregate_failures to collect multiple assertion failures.
- Keep tests fast: stub external services, use
build_stubbed.
- Run
bundle exec rspec --format documentation for readable output.