CodeVetter · Repo Unpack · Extension points
rails/rails
Rails is extended by subclassing Railtie or Engine, by dropping files that match command and generator globs, and by registering adapters. The frameworks that ship in this repo are themselves just those plugins. New queue adapters are explicitly not an accepted extension; password algorithms, storage services, database protocol names, and middleware are.
- Rails::Railtie is the extension base. Subclasses are loaded when the gem is required if Rails::Railtie is defined. The initializer macro accepts before and after. Railties can also set config.app_generators, config.to_prepare, rake_tasks, generators, and a server block that runs when the Rails server starts.
- Rails::Engine subclasses Railtie and is what makes a gem load app/ models, controllers, helpers, config/routes.rb, config/locales, and lib/tasks. Rails::Application is an engine. Isolated engines are how Action Cable, Active Storage, Action Mailbox, and Action Text are mounted.
- Rails::Command.find_by_namespace searches load paths for rails/commands and commands, files named *_command.rb, and namespaces with an optional rails: prefix. Adding a command is a new file matching that glob plus a class inheriting Rails::Command::Base, not a hand-edited registry hash.
- Rails::Generators uses the same pattern for *_generator.rb under rails/generators and generators, with fallbacks when the first lookup misses. invoke is the entry for generate, destroy, and update. after_generate callbacks see files recorded by add_generated_file.
- ActiveJob::QueueAdapters.lookup(name) does const_get of the camelized name plus Adapter. A non-symbol adapter is accepted by queue_adapter= when it implements enqueue and enqueue_at. The same file says pull requests for new adapters are not accepted.
- Active Job argument types are extended with serializer classes under activejob/lib/active_job/serializers (date, time, duration, range, symbol, BigDecimal, ActionController::Parameters, module, and GlobalID via the documented Identification interface).
- A new Active Storage backend subclasses Service, implements upload, download, download_chunk, and compose, and is selected when Configurator#resolve require's active_storage/service/<underscore>_service and constantizes <Name>Service. MirrorService is the built-in example of build receiving the configurator so it can construct children.
- ActiveRecord.protocol_adapters is an ActiveSupport::InheritableOptions hash used only to map DATABASE_URL protocols onto adapter names. The documented extension is ActiveRecord.protocol_adapters.mysql = "mysql2" or a custom protocol string pointing at an external adapter.
- Password hashing is a registry: ActiveModel::SecurePassword.register_algorithm(name, algorithm_class). :bcrypt and :argon2 are registered at load. has_secure_password algorithm: :name calls lookup_algorithm and instantiates the class; an unknown symbol raises ArgumentError.
- Middleware is inserted either in DefaultMiddlewareStack#build_stack or from a railtie initializer via app.middleware.use. Session stores are resolved through ActionDispatch::Session.resolve_store when config.session_store is a Symbol. :disabled skips session middleware.
- Versioned behavior is the case statement in Application::Configuration#load_defaults. The in-file comment is the extension procedure: add an accessor preserving old behavior, branch on the flag, set the new default only in the next version arm, mirror it in new_framework_defaults, and update the configuring guide. Unknown versions raise.
- Action Cable subscription adapters for Redis and PostgreSQL are listed in Zeitwerk::Loader.do_not_eager_load so they load only when configured. Connection#connect and #disconnect are the empty hooks an app overrides for authentication and presence.
- Engines draw routes by reopening Rails.application.routes.draw, which is how Action Mailbox and Active Storage install their endpoints without the app editing config/routes.rb. Development-only framework routes are appended later by Finisher#add_internal_routes.