Rails チュートリアル 1章 勉強メモ16
Rails チュートリアルの勉強メモ
- 前回までのあらすじ
- hello メソッドにたどり着くまでをみている
- イマココ --> #58 Puma::Configuration::ConfigMiddleware.call(env#Hash) at $HOME/.rbenv/versions/2.6.2/lib/ruby/gems/2.6.0/gems/puma-3.12.1/lib/puma/configuration.rb:227
hello メソッドにたどり着くまで
railties-5.1.7/lib/rails/engine.rb @ line 522 Rails::Engine#call: 520: def call(env) 521: req = build_request env => 522: app.call req.env 523: end
- rails の中に入った
- app は前回の@app の中の Rack::Sendfile 部分
req は ActionDispatch::Request
- req.env は多分 env と同じ
rack-2.0.7/lib/rack/sendfile.rb @ line 111 Rack::Sendfile#call
- Rack は Ruby の WEBサーバーアプリ
Sendfile
- X-Sendfile は Apache で Nginx は X-Accel-Redirect らしい
- 微妙に違う?
- ファイルシステムの一部をプライベートURL階層にマップする必要がある
- ↓わかりやすかった
X-SendFile、X-Accel-Redirectの使い方 | 純規の暇人趣味ブログ
- コードに戻る
110: def call(env) => 111: status, headers, body = @app.call(env) 112: if body.respond_to?(:to_path) 113: case type = variation(env) 114: when 'X-Accel-Redirect' 115: path = ::File.expand_path(body.to_path) 116: if url = map_accel_path(env, path)
- この @app は ActionDispatch::Static
ActionDispatch
- actionpack-5.1.7/lib/action_dispatch/middleware/static.rb
- このミドルウェアは、responseでディスクからファイルの本文の内容を返す
- ルートディレクトリにあるファイルのみをレンダリングできる
- request はこのミドルウェアを使用してディレクトリトラバーサルを生成できない
- ディレクトリトラバーサルは .. などを使って通常はアクセスできないファイルやディレクトリ(フォルダ)の内容を取得する手法。
- GETおよびHEADリクエストのみがファイルを返す
actionpack-5.1.7/lib/action_dispatch/middleware/static.rb @ line 125 ActionDispatch::Static#call: 114: def call(env) 115: req = Rack::Request.new env 116: 117: if req.get? || req.head? 118: path = req.path_info.chomp("/".freeze) 119: if match = @file_handler.match?(path) 120: req.path_info = match 121: return @file_handler.serve(req) 122: end 123: end 124: => 125: @app.call(req.env) 126: end
- req は Rack::Request (env の内容が入ってる
- req.get? || req.head? (リクエストがgetかheadか
- 今回は GET なので true
- req.path_info は "/" なので path は ""
- match? はファイルへのパスを取得する
- public 以下のファイルの存在を確認するために Static クラスで利用される
[87] pry(#<ActionDispatch::Static>)> @file_handler.match?("robots.txt") => "robots.txt" [88] pry(#<ActionDispatch::Static>)> @file_handler.match?("404") => "404.html" [89] pry(#<ActionDispatch::Static>)> @file_handler.match?("200") => nil
- 今回は path は "" なので nil を返す
- @app.call(req.env)
- また次の call へ・・・
ActionDispatch::Executor#call
- ActionDispatch は Rack のミドルウェア
actionpack-5.1.7/lib/action_dispatch/middleware/executor.rb @ line 12 ActionDispatch::Executor#call: 9: def call(env) 10: state = @executor.run! 11: begin => 12: response = @app.call(env) 13: returned = response << ::Rack::BodyProxy.new(response.pop) { state.complete! } 14: ensure 15: state.complete! unless returned 16: end 17: end
- state は状態が入ってるんだろう
- response = @app.call(env)
- 次のapp.call
ActiveSupport::Cache::Strategy::LocalCache::Middleware#call
- このクラスはミドルウェアのローカルストレージをラップします。らしい
activesupport-5.1.7/lib/active_support/cache/strategy/local_cache_middleware.rb @ line 27 ActiveSupport::Cache::Strategy::LocalCache::Middleware#call: 25: def call(env) 26: LocalCacheRegistry.set_cache_for(local_cache_key, LocalStore.new) => 27: response = @app.call(env) 28: response[2] = ::Rack::BodyProxy.new(response[2]) do 29: LocalCacheRegistry.set_cache_for(local_cache_key, nil) 30: end 31: cleanup_on_body_close = true 32: response 33: rescue Rack::Utils::InvalidParameterError 34: [400, {}, []] 35: ensure 36: LocalCacheRegistry.set_cache_for(local_cache_key, nil) unless 37: cleanup_on_body_close 38: end
- 次の@app.call
Rack::Runtime#call
- リクエストの応答時間を秒単位で示す X-Runtime を設定するらしい
- アプリケーションの前に配置して処理時間を確認したり、すべてのミドルウェアの前に置いて、それらの時間を含めることもできる。らしい
rack-2.0.7/lib/rack/runtime.rb @ line 22 Rack::Runtime#call: 20: def call(env) 21: start_time = Utils.clock_time => 22: status, headers, body = @app.call(env) 23: request_time = Utils.clock_time - start_time 24: 25: unless headers.has_key?(@header_name) 26: headers[@header_name] = FORMAT_STRING % request_time 27: end 28: 29: [status, headers, body] 30: end
- start_timeを入れて、@app.callへ
- @app を pry で見てみるとかなり重なっていて先が遠そう
Rack::MethodOverride#call
rack-2.0.7/lib/rack/method_override.rb @ line 22 Rack::MethodOverride#call: 13: def call(env) 14: if allowed_methods.include?(env[REQUEST_METHOD]) 20: end 21: => 22: @app.call(env) 23: end
- ALLOWED_METHODS = %w[POST] なのでスルー
ActionDispatch::RequestId#call
- request_id をセットして app.call
ActionDispatch::RemoteIp#call
- リモートIPを取り、app.call
Sprockets::Rails::QuietAssets#call
- env['PATH_INFO'] =~ @assets_regex はマッチしないので次のapp.call
Rails::Rack::Logger#call
- ログを記録する
- Rails::Rack::Logger#call_app へ
- request のログをスタートして @app.call(env)
ActionDispatch::ShowExceptions#call
- 例外を拾う感じ?
- @app.call(env)
WebConsole::Middleware#call
- request.from_whitelisted_ip? は true だが、id_for_repl_session_update(request)、id_for_repl_session_stack_frame_change(request) は nil なので次の call_app(env)
- WebConsole::Middleware#call_app の中の @app.call(env)
ActionDispatch::DebugExceptions#call
ActionDispatch::Executor#call
- state = @executor.run! して @app.call(env)
- state が何かよくわからない
ActionDispatch::Callbacks#call
- run_callbacks :call
- callbacks.empty? なので @app.call(env)
ActiveRecord::Migration::CheckPending#call
- config.active_record.migration_error が設定されているとチェックが入る
- 未適用のマイグレーションを見つけるとこのエラーを投げるらしい
- 次の @app.call(env)
ActionDispatch::Cookies#call
- Cookie の何かだろうけどすぐに @app.call(env) なので次へ
Rack::Session::Abstract::Persisted#call
- context(env)
- session のオプションを配置して? app.call(req.env)
Rack::Head#call
Rack::ConditionalGet#call
- GET なので when "GET", "HEAD" に入る
- すぐに @app.call(env)
Rack::ETag#call
- ETag の何かだろうけどここもすぐに @app.call(env)
- ETag ってなんだろう
ActionDispatch::Routing::RouteSet#call
- @router.serve(req)
ActionDispatch::Journey::Router#serve
32: def serve(req) => 33: find_routes(req).each do |match, parameters, route| 34: set_params = req.path_parameters 35: path_info = req.path_info 36: script_name = req.script_name 37: 38: unless route.path.anchored
actionpack-5.1.7/lib/action_dispatch/journey/router.rb @ line 50 ActionDispatch::Journey::Router#serve: 45: val.dup.force_encoding(::Encoding::UTF_8) 46: } 47: 48: req.path_parameters = set_params.merge parameters 49: => 50: status, headers, body = route.app.serve(req) 51: 52: if "pass" == headers["X-Cascade"] 53: req.script_name = script_name 54: req.path_info = path_info 55: req.path_parameters = set_params
[139] pry(#<ActionDispatch::Journey::Router>)> match => #<ActionDispatch::Journey::Path::Pattern::MatchData:0x00007fd32815aa60 @match=#<MatchData "/">, @names=[], @offsets=[0]> [140] pry(#<ActionDispatch::Journey::Router>)> parameters => {:controller=>"application", :action=>"hello"} [141] pry(#<ActionDispatch::Journey::Router>)> route => #<ActionDispatch::Journey::Route:0x00007fd32c124218
- parameters に値を入れて route.app.serve(req)
ActionDispatch::Routing::RouteSet::Dispatcher#serve
- params などをセットして dispatch(controller, params[:action], req, res)
- dispatch では controller.dispatch(action, req, res) を実行
ActionController::Metal.dispatch
- ActionController :: Metal はシンプルなコントローラー
ActionController :: Base によって提供される追加の機能なしで有効なRackインターフェースを提供する
middleware_stack.any? は false なので new.dispatch(name, req, res)
- dispatch では request と response をセットして process(name)
- name は hello
ActionView::Rendering#process
actionview-5.1.7/lib/action_view/rendering.rb @ line 30 ActionView::Rendering#process: 28: def process(*) #:nodoc: 29: old_config, I18n.config = I18n.config, I18nProxy.new(I18n.config, lookup_context) => 30: super 31: ensure 32: I18n.config = old_config 33: end
- I18n ってなんだろう
- super の先で process_action(action_name, *args)
ActiveRecord::Railties::ControllerRuntime#process_action
activerecord-5.1.7/lib/active_record/railties/controller_runtime.rb @ line 22 ActiveRecord::Railties::ControllerRuntime#process_action: 17: def process_action(action, *args) 18: # We also need to reset the runtime before each action 19: # because of queries in middleware or in cases we are streaming 20: # and it won't be cleaned up by the method below. 21: ActiveRecord::LogSubscriber.reset_runtime => 22: super 23: end
- 各アクションの前にランタイムをリセットする必要があるらしい
- ActionController::ParamsWrapper#process_action
- _wrapper_enabled? は false なので super へ
- ActionController::Instrumentation#process_action
- ActionController::Rescue#process_action
- AbstractController::Callbacks#process_action
- ActiveSupport::Callbacks#run_callbacks
- AbstractController::Callbacks#process_action
- ActionController::Rendering#process_action AbstractController::Base#process_action
- 長かったので諦めました眠い・・・
actionpack-5.1.7/lib/abstract_controller/base.rb @ line 186 AbstractController::Base#process_action: 185: def process_action(method_name, *args) => 186: send_action(method_name, *args) 187: end
ActionController::BasicImplicitRender#send_action
actionpack-5.1.7/lib/action_controller/metal/basic_implicit_render.rb @ line 4 ActionController::BasicImplicitRender#send_action: 3: def send_action(method, *args) => 4: super.tap { default_render unless performed? } 5: end
- method は hello
workspace/Rails/environment/hello_app/app/controllers/application_controller.rb @ line 7 ApplicationController#hello: 5: def hello 6: binding.pry => 7: render html: "hello, world!" 8: end
actionpack-5.1.7/lib/action_controller/metal/instrumentation.rb @ line 42 ActionController::Instrumentation#render: 41: def render(*args) => 42: render_output = nil 43: self.view_runtime = cleanup_view_runtime do 44: Benchmark.ms { render_output = super } 45: end 46: render_output 47: end
actionpack-5.1.7/lib/action_controller/metal/rendering.rb @ line 35 ActionController::Rendering#render: 34: def render(*args) #:nodoc: => 35: raise ::AbstractController::DoubleRenderError if response_body 36: super 37: end
actionpack-5.1.7/lib/abstract_controller/rendering.rb @ line 24 AbstractController::Rendering#render: 22: def render(*args, &block) 23: options = _normalize_render(*args, &block) => 24: rendered_body = render_to_body(options) 25: if options[:html] 26: _set_html_content_type 27: else 28: _set_rendered_content_type rendered_format 29: end 30: self.response_body = rendered_body 31: end [1] pry(#<ApplicationController>)> options => {:html=>"hello, world!", :prefixes=>["application"], :template=>"hello"}