おさかな日誌

魚類がプログラミング

Rails application の起動と実行メモ

rails コマンド

  • bin/rails
  • require "rails/cli"
  • rails/cli: require 'rails/app_rails_loader'
  • Rails::AppRailsLoader.exec_app_rails:
    • bundler のチェック
    • APP_PATH = Dir.pwd + config/application.rb
    • require File.expand_path('../boot', APP_PATH)
    • require 'rails/commands'
  • rails/commands: ARGVの操作と alias の設定
  • require 'rails/commands/commands_tasks'
    • help message の定義
    • command の dispatch
    • require APP_PATH: gem の require, Rails.application
  • Rails::CommandsTasks.new(ARGV).run_command!(command): runner とかの実体を呼んで実行する
  • exec_app_rails: 正常に command が終了したら rails/cli まで戻る
  • if ARGV.first == 'plugin': require 'rails/commands/plugin' - plugin generate
  • else: require 'rails/commands/application' - application generate

Rails.application#call は実際にどうやってなにが呼ばれるのか

ActionController::Base#action(action).call(env) が呼ばれるまでを追ってみた。

雑にまとめると、通常の routing では

  • Rails::Application#call
  • ActionDispatch::MiddlewareStack#call
  • ActionDispatch::Routing::RouteSet#cal
  • ActionDispatch::Journey::Router#call
  • ActionDispatch::Jouney::Route#app.call
  • Routing::RouteSet::Dispatcher#call
  • SomeController.action(action).call

となる。以下乱雑なメモ

  • Rails::Application#call: super
  • Rails::Engine#call: #app.call(env)
  • Rails::Engine#app:
    • config.middleware = config.middleware.merge_into(default_middleware_stack)
    • config.middleware.build(endpoint)
  • #config: Application::Configuration.new(find_root_with_flag("config.ru", Dir.pwd)) & config= もある
  • Rails::Application#config: #app_middleware
  • Rails:::Railtie#app_middleware: @@app_middleware ||= Rails::Configuration::MiddlewareStackProxy.new
  • MiddlewareStackProxy#merge_into: #default_middleware_stack
  • Rails::Application#default_middleware_stack: DefaultMiddlewareStack.new, #buidl_stack
    • #build_stack: ActionDispatch::MiddlewareStack.new.tap {}
  • ActionDispatch::MiddlewareStack#build(endpoint):
    • Rails::Engine#endpoint: self.class.endpoint || routes
    • Rails::Engine#routes: ActionDispatch::Routing::RouteSet.new
    • #build(app = ActionDispatch::Routing::RouteSet.new) no block: middlewares.freeze.reverse.inject(app) { |a, e| e.build(a) }
    • ActionDispatch::MiddlewareStack::Middleware#build: klass.new(app, *args, &block)
    • Middleware#klass: 各 middleware で .new(app, *args, &block) する。args, block は use or insert とかの args, block が来る。
    • 返り値は全ての rack middleware をチェーンした ActionDispatch::Routing::RouteSet (= Rails::Application.endpoint)。endpoint を任意の rack interface 互換のものにどこかで差し替えれば Raisl の routing を差し替えれるかもしれない。
  • ActionDispatch::Routing::RouteSet#call: @router.call(env)
    • @router: Journey::Router.new(Journey::Routes.new)
  • Journey::Router#call: find_routes(env).each {|route| status, headers, body = route.app.call(env) }
    • route: filter_routes
    • Journey::Router#filter_routes: routes#simulator
    • Journey::Routes#simulator: GTG::Simulator.new(GTG::Builder.new(ast).transition_table)
    • Simulater.new(string):
      • string: Gtg#transition_table
    • Simulater#simulate: state
      • state: TODO
  • ActionDispatch::Jouney::Route#app.call(env):
    • #app: Set by Mapper
      • Mapper#app: Constraints.new(endpoint, blocks, @set.request_class)
      • endpoint: (:to option (get '/', to: 'users#index') which responsd_to? :call) or (dispatcher)
      • Mapping#dispatcher: Routing::RouteSet::Dispatcher.new(:defaults => defaults)
        • defaults: defaults: { format: 'jpg' } otion
  • Routing::RouteSet::Dispatcher#call(env): rack app とかが指定されない場合これが呼ばれる
    • params: env['action_dispatch.request.path_parameters']
    • params['controller], params['action']: すでにセットされている
  • Dispatcher#dispatch(controller):
    • controller: controller_reference(controller_params)
      • const_name: @controller_class_names[controller_param] ||= "#{controller_param.camelize}Controller"
      • ActiveSupport::Dependencies.constantize(const_name)
  • controller#action(action).call(env)

journey、やらなきゃいけないことが複雑でコードも複雑でめっちゃ疲れた追い切れない... JourneyHackingGuides ほしい...

次は named routes がどこの routes がどう呼ばれてるのか調べたい...