# Data flow — rails/rails

> Canonical page: https://codevetter.com/unpack/rails/data-flow

# Data flow — rails/rails

Scanned commit be63fd9b4449505b90038acb9d51c88c02694e7e (2026-09-21). Generated by codevetter codevetter 1.12.0 on 2026-09-22.

Three boundaries dominate. HTTP enters as a Rack env, passes DefaultMiddlewareStack, and is recognized by Journey into a controller action whose callbacks and render produce a Rack triple. Records enter through Active Record attribute hashes, are validated and callback-wrapped, then inserted or updated on a leased connection. Secrets enter as ENV or a key file, are decrypted with AES-128-GCM, and feed secret_key_base, which signs and encrypts cookies and messages. Jobs, uploads, and filtered logs are side channels off those paths.
- RouteSet#call builds a request, normalizes path_info with Journey::Router::Utils.normalize_path, and calls @router.serve. Journey::Router#serve yields each match to route.app.serve and returns the response unless the X_CASCADE header is pass; otherwise it returns 404. — [actionpack/lib/action_dispatch/routing/route_set.rb#L905-L909](https://github.com/rails/rails/blob/be63fd9b4449505b90038acb9d51c88c02694e7e/actionpack/lib/action_dispatch/routing/route_set.rb#L905-L909) [actionpack/lib/action_dispatch/journey/router.rb#L30-L40](https://github.com/rails/rails/blob/be63fd9b4449505b90038acb9d51c88c02694e7e/actionpack/lib/action_dispatch/journey/router.rb#L30-L40)
- RouteSet::Dispatcher#serve reads path parameters, instantiates the controller response, and calls controller.dispatch. On RoutingError it re-raises only when @raise_on_name_error is set; otherwise it returns a 404 cascade triple. — [actionpack/lib/action_dispatch/routing/route_set.rb#L46-L66](https://github.com/rails/rails/blob/be63fd9b4449505b90038acb9d51c88c02694e7e/actionpack/lib/action_dispatch/routing/route_set.rb#L46-L66)
- ActionController::Metal#dispatch assigns the request and response, calls process(name), commits the flash, and returns to_a. AbstractController::Base#process sets @_action_name, raises ActionNotFound when _find_action_name fails, and calls process_action. Callbacks#process_action wraps super in run_callbacks(:process_action). — [actionpack/lib/action_controller/metal.rb#L282-L288](https://github.com/rails/rails/blob/be63fd9b4449505b90038acb9d51c88c02694e7e/actionpack/lib/action_controller/metal.rb#L282-L288) [actionpack/lib/abstract_controller/base.rb#L146-L156](https://github.com/rails/rails/blob/be63fd9b4449505b90038acb9d51c88c02694e7e/actionpack/lib/abstract_controller/base.rb#L146-L156) [actionpack/lib/abstract_controller/callbacks.rb#L263-L269](https://github.com/rails/rails/blob/be63fd9b4449505b90038acb9d51c88c02694e7e/actionpack/lib/abstract_controller/callbacks.rb#L263-L269)
- Journey path captures are CGI.unescapeURIComponent'd when they contain % and then forced to UTF-8 before being merged with route defaults. recognize_path separately binary-encodes and URI-unescapes string params and raises RoutingError when the controller constant is missing. — [actionpack/lib/action_dispatch/journey/router.rb#L66-L83](https://github.com/rails/rails/blob/be63fd9b4449505b90038acb9d51c88c02694e7e/actionpack/lib/action_dispatch/journey/router.rb#L66-L83) [actionpack/lib/action_dispatch/routing/route_set.rb#L911-L949](https://github.com/rails/rails/blob/be63fd9b4449505b90038acb9d51c88c02694e7e/actionpack/lib/action_dispatch/routing/route_set.rb#L911-L949)
- Persistence#save calls create_or_update and returns false on RecordInvalid. create_or_update raises if the record is readonly, returns false if destroyed, and chooses _create_record or _update_record. _create_record filters attributes_for_create, opens with_connection, calls _insert_record with _returning_columns_for_insert, writes returned columns, and clears @new_record. — [activerecord/lib/active_record/persistence.rb#L358-L361](https://github.com/rails/rails/blob/be63fd9b4449505b90038acb9d51c88c02694e7e/activerecord/lib/active_record/persistence.rb#L358-L361) [activerecord/lib/active_record/persistence.rb#L928-L980](https://github.com/rails/rails/blob/be63fd9b4449505b90038acb9d51c88c02694e7e/activerecord/lib/active_record/persistence.rb#L928-L980)
- ActiveRecord::Base.establish_connection resolves a symbol or hash via resolve_config_for_connection and delegates to connection_handler.establish_connection with owner_name, current_role, and current_shard. connects_to accepts database: or shards: but not both, and only on Base or abstract classes. ConnectionPool#lease_connection checks out a connection once per thread and marks the lease sticky. — [activerecord/lib/active_record/connection_handling.rb#L50-L86](https://github.com/rails/rails/blob/be63fd9b4449505b90038acb9d51c88c02694e7e/activerecord/lib/active_record/connection_handling.rb#L50-L86) [activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb#L352-L362](https://github.com/rails/rails/blob/be63fd9b4449505b90038acb9d51c88c02694e7e/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb#L352-L362)
- secret_key_base prefers ENV[SECRET_KEY_BASE_DUMMY] (a generated local secret), then ENV[SECRET_KEY_BASE], then credentials.secret_key_base, then a generated secret when Rails.env.local?. A missing non-local secret raises ArgumentError naming bin/rails credentials:edit. Application#key_generator memoizes an ActiveSupport::CachingKeyGenerator per secret, used for MessageVerifier and MessageEncryptor including cookies. — [railties/lib/rails/application/configuration.rb#L557-L578](https://github.com/rails/rails/blob/be63fd9b4449505b90038acb9d51c88c02694e7e/railties/lib/rails/application/configuration.rb#L557-L578) [railties/lib/rails/application.rb#L490-L510](https://github.com/rails/rails/blob/be63fd9b4449505b90038acb9d51c88c02694e7e/railties/lib/rails/application.rb#L490-L510)
- ActiveSupport::EncryptedFile uses cipher aes-128-gcm. #key reads the env var named by env_key, then the key file, then raises MissingKeyError if raise_if_missing_key. #read decrypts content_path.binread. generate_key is SecureRandom.hex of MessageEncryptor.key_len, and a key of any other length raises InvalidKeyLengthError. — [activesupport/lib/active_support/encrypted_file.rb#L30-L78](https://github.com/rails/rails/blob/be63fd9b4449505b90038acb9d51c88c02694e7e/activesupport/lib/active_support/encrypted_file.rb#L30-L78)
- Application#creds returns ActiveSupport::CombinedConfiguration. In development the lookup order is envs, then dotenv, then encrypted credentials; in other environments dotenv is omitted. The documented API is creds.require and creds.option. — [railties/lib/rails/application.rb#L513-L536](https://github.com/rails/rails/blob/be63fd9b4449505b90038acb9d51c88c02694e7e/railties/lib/rails/application.rb#L513-L536)
- ActiveJob::Enqueuing::ClassMethods#perform_later instantiates the job and calls enqueue. The class attribute enqueue_after_transaction_commit defaults to false in the module, but load_defaults 8.2 sets active_job.enqueue_after_transaction_commit = true so new 8.2 apps defer enqueue until the outermost transaction commits. — [activejob/lib/active_job/enqueuing.rb#L13-L58](https://github.com/rails/rails/blob/be63fd9b4449505b90038acb9d51c88c02694e7e/activejob/lib/active_job/enqueuing.rb#L13-L58) [railties/lib/rails/application/configuration.rb#L397-L399](https://github.com/rails/rails/blob/be63fd9b4449505b90038acb9d51c88c02694e7e/railties/lib/rails/application/configuration.rb#L397-L399)
- ActionDispatch::Http::FilterParameters#filtered_parameters runs ActiveSupport::ParameterFilter over the request parameters and substitutes matches with the mask [FILTERED]. ParseError yields an empty hash so a bad body does not leak into logs via the filter path. — [actionpack/lib/action_dispatch/http/filter_parameters.rb#L9-L39](https://github.com/rails/rails/blob/be63fd9b4449505b90038acb9d51c88c02694e7e/actionpack/lib/action_dispatch/http/filter_parameters.rb#L9-L39) [activesupport/lib/active_support/parameter_filter.rb#L44-L89](https://github.com/rails/rails/blob/be63fd9b4449505b90038acb9d51c88c02694e7e/activesupport/lib/active_support/parameter_filter.rb#L44-L89)
- sanitize_sql_for_conditions sends Arrays through sanitize_sql_array and quotes bound values, but returns a bare String unchanged. The comment states the helper is not schema-aware and that MySQL numeric binds are quoted as strings. — [activerecord/lib/active_record/sanitization.rb#L8-L39](https://github.com/rails/rails/blob/be63fd9b4449505b90038acb9d51c88c02694e7e/activerecord/lib/active_record/sanitization.rb#L8-L39)
- An upload enters ActiveStorage::Service#upload(key, io, checksum:) and, when a checksum is given, must raise ActiveStorage::IntegrityError on mismatch. Disk, S3, GCS, and Mirror are selected by the service: key in the configuration passed to Service.configure, not by a hardcoded global. — [activestorage/lib/active_storage/service.rb#L14-L73](https://github.com/rails/rails/blob/be63fd9b4449505b90038acb9d51c88c02694e7e/activestorage/lib/active_storage/service.rb#L14-L73) [activestorage/lib/active_storage/service/configurator.rb#L15-L19](https://github.com/rails/rails/blob/be63fd9b4449505b90038acb9d51c88c02694e7e/activestorage/lib/active_storage/service/configurator.rb#L15-L19)

Every claim links to its cited files at the pinned commit. Citations identify source evidence; they do not establish runtime correctness. Independent CodeVetter scan — not reviewed by upstream maintainers.

## Public product links

- [CodeVetter](https://codevetter.com/)
- [Download](https://codevetter.com/download)
- [Documentation](https://codevetter.com/docs/)
- [Source](https://github.com/Codevetter/codevetter)
