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
eachoverforloops. Use block-style iteration. - Return values implicitly (last expression). Use explicit
returnonly for early exit.
Blocks, Procs, Lambdas
- Use
{ }for single-line blocks. Usedo...endfor multi-line blocks. - Use
&:methodshorthand:names.map(&:upcase). - Use lambdas for strict argument checking. Use procs for flexible arity.
- Use
yieldfor single-block methods. Use explicit&blockfor storing/forwarding.
Classes
- Use
attr_reader,attr_writer,attr_accessorfor simple getters/setters. - Use
Structfor simple data containers. UseData.define(Ruby 3.2+) for immutable. - Use modules for mixins:
includefor instance methods,extendfor class methods. - Use
frozen_string_literal: truemagic comment at the top of every file. - Use
private/protectedkeywords to control method visibility.
Collections
- Use
map,select,reject,reduce,flat_mapfor transformations. - Use
each_with_objectoverinjectwhen accumulating into a mutable object. - Use
digfor safe nested hash/array access:data.dig(:user, :address, :city). - Use
Hash#fetchwith default for explicit missing-key handling. - Use
Enumerable#lazyfor large collection processing.
Pattern Matching (Ruby 3+)
- Use
case/infor structural pattern matching on hashes and arrays. - Use
=>pin operator to match against existing variables. - Use
inpattern for conditional deconstruction inifstatements. - Use pattern matching for API response parsing and validation.
Formatting
- Use RuboCop for automated style enforcement.
- Use
.rubocop.ymlcommitted 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 generatefor scaffolding models, controllers, migrations. - Use strong parameters:
params.require(:user).permit(:name, :email). - Use concerns for shared controller/model behavior.
- Use
config/routes.rbwith 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 :throughfor associations. - Use scopes for reusable query chains:
scope :active, -> { where(active: true) }. - Use
includes()for eager loading to prevent N+1 queries. - Use
find_eachfor batch processing large record sets. - Use
transactionblocks for atomic multi-record operations.
ActionController
- Keep controllers thin: max 7 RESTful actions per controller.
- Use
before_actionfor authentication and authorization checks. - Use
respond_tofor content negotiation (JSON, HTML). - Use
rescue_fromfor 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_laterfor async execution. Useperform_nowonly in tests. - Set
retrycount anddiscard_on/retry_onfor error handling. - Use
Sidekiq::Cronorclockworkfor 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 --apifor API-only applications (no views, sessions). - Use
JbuilderorBlueprinterfor JSON serialization. - Use
Rack::Attackfor rate limiting and throttling. - Use versioned API namespaces:
namespace :v1 do ... end. - Use pagination with
kaminariorpagyfor 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(catchesStandardError). - Create domain exception hierarchies:
class AppError < StandardError; end. - Use
raisewith message and optional cause:raise AppError, "msg". - Use
retrywith a counter for transient failures. - Use
ensurefor cleanup. Useelsefor code that runs only on success.
Service Objects
- Use single-purpose service classes with a
callmethod. - Use
Dry::MonadsResult type for operation outcomes. - Return
Success(value)orFailure(error)from service calls. - Chain services with
bind/fmapfor pipeline composition. - Keep services stateless. Pass all data through method parameters.
Value Objects
- Use
Data.define(Ruby 3.2+) for immutable value objects. - Use
Structwithkeyword_init: truefor lightweight data containers. - Use
freezeon objects that should not be mutated after creation. - Override
==andhashfor value-based equality when needed.
Metaprogramming (Use Sparingly)
- Use
define_methodovermethod_missingwhen possible. - Always define
respond_to_missing?alongsidemethod_missing. - Use
class_attribute(Rails) for inheritable class-level configuration. - Prefer explicit code over DSL magic for maintainability.
- Document metaprogrammed methods with YARD
@!methoddirectives.
Concurrency
- Use
Concurrent::Future(concurrent-ruby) for parallel operations. - Use
Concurrent::Promisefor composable async chains. - Use thread pools (
Concurrent::FixedThreadPool) for bounded concurrency. - Use
Ractor(Ruby 3+) for true parallel execution without GVL. - Use
MutexandQueuefor thread-safe shared state access.
Module Patterns
- Use
includefor shared behavior (instance methods). - Use
prependfor wrapping/overriding existing methods (decorating). - Use
extendfor 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
SimpleDelegatorfor transparent object wrapping. - Use
Drapergem for view-layer decorators in Rails. - Prefer composition (wrapping) over inheritance for adding behavior.
- Use
Module#prependfor 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
evalorsendwith 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 tocreate/update. - Use
attr_readonlyfor fields that should never be updated after creation. - Audit
update_columnsandupdate_attributeusage (bypass validations).
SQL Injection
- Use ActiveRecord query interface with parameterized conditions.
- Use
where(name: value)hash syntax orwhere("name = ?", value)placeholders. - Never interpolate user input into
where()strings:where("name = '#{input}'"). - Use
sanitize_sql_arrayif building raw SQL fragments is unavoidable. - Audit all
find_by_sql,execute, andArel.sqlcalls.
XSS Prevention
- Rails auto-escapes ERB output with
<%= %>. Never useraw()with user data. - Use
sanitize()helper for allowing limited HTML tags. - Set
Content-Security-Policyheader inconfig/initializers/content_security_policy.rb. - Use
content_taghelper for safe HTML generation. - Mark strings as
html_safeonly when content is guaranteed safe.
CSRF Protection
- Use
protect_from_forgery with: :exceptioninApplicationController. - Use
authenticity_tokenin all forms (Rails includes it by default). - Use
X-CSRF-Tokenheader for AJAX requests from JavaScript. - Exempt only webhook endpoints from CSRF (with payload signature verification).
Authentication
- Use Devise or
has_secure_passwordfor authentication. - Use
bcryptfor password hashing (included withhas_secure_password). - Implement account lockout after N failed login attempts.
- Use
SecureRandom.urlsafe_base64for 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 @resourcein every controller action. - Default deny: require explicit authorization for all actions.
Secrets Management
- Use
Rails.application.credentialsfor encrypted secrets. - Use
EDITOR="vim" bin/rails credentials:editto manage secrets. - Use per-environment credentials:
credentials/production.yml.enc. - Never commit
master.keyorproduction.keyto version control. - Use environment variables for CI/CD and containerized deployments.
Dependency Security
- Run
bundle audit check --updatefor known vulnerability scanning. - Use
Dependabotfor automated dependency update PRs. - Pin gem versions in
Gemfile. ReviewGemfile.lockchanges carefully. - Use
bundler-auditin 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.rbmirroringapp/models/user.rb. - Minitest:
test/models/user_test.rbmirroring source structure. - Support files:
spec/support/for shared helpers and configurations. - Use
spec/rails_helper.rbfor Rails-specific RSpec configuration.
Structure (RSpec)
- Use
describefor the class/method under test. Usecontextfor scenarios. - Use
itfor individual test cases with clear descriptions. - Use
letfor lazy-evaluated test data. Uselet!for eager evaluation. - Use
before/afterblocks for setup and teardown. - Use
subjectfor 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_doublefor stubbing class methods. - Avoid stubbing the object under test. Stub only collaborators.
FactoryBot
- Define factories in
spec/factories/:FactoryBot.define { factory :user { ... } }. - Use
createfor persisted records. Usebuildfor in-memory only. - Use traits for variations:
create(:user, :admin). - Use
build_stubbedfor fast tests that do not need database. - Use sequences for unique attributes:
sequence(:email) { |n| "user#{n}@test.com" }.
Rails Testing
- Use
request specsfor API endpoint testing (RSpec). - Use
system specswith Capybara for browser integration tests. - Use
DatabaseCleaneroruse_transactional_fixturesfor test isolation. - Use
travel_tofor time-dependent test scenarios. - Use
ActiveJob::TestHelperfor testing background jobs inline.
Best Practices
- Test behavior, not implementation. Do not test private methods directly.
- Use
shared_examplesfor testing common behavior across classes. - Use
aggregate_failuresto collect multiple assertion failures. - Keep tests fast: stub external services, use
build_stubbed. - Run
bundle exec rspec --format documentationfor readable output.