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
orinsert
とかの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
- defaults:
- 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)
- const_name:
- controller: controller_reference(controller_params)
- controller#action(action).call(env)
journey、やらなきゃいけないことが複雑でコードも複雑でめっちゃ疲れた追い切れない... JourneyHackingGuides ほしい...
次は named routes がどこの routes がどう呼ばれてるのか調べたい...