Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Railsサーバ起動の裏側

 Railsサーバ起動の裏側

ヒカラボさんのイベントで発表したスライドです

Shinichi Maeshima

February 27, 2018
Tweet

More Decks by Shinichi Maeshima

Other Decks in Programming

Transcript

  1. Railsサーバ起動の
    裏側
    前島 真一(@willnet)

    View Slide

  2. Shinichi Maeshima
    !
    "
    #
    @netwillnet
    @willnet
    http://blog.willnet.in
    Organizer
    Rails Consultant

    View Slide

  3. 具体的には何してる人
    なの
    • 技術やシステム設計に関する質問に答える
    • コードレビュー
    • 社内勉強会の開催
    • ペアプロ
    • などなど(採用の相談とか技術以外のことも時々やって
    る)

    View Slide

  4. つまり
    • Railsの知見を会社に提供するおしごと

    View Slide

  5. 知見のうちの一つを
    お話します

    View Slide

  6. みんな大好き
    Ruby on Rails
    • Railsのお作法(レール)に乗ってるだけで、意識せずにべ
    んり技術を使えていて最高
    • 例えばセキュリティ的には
    • HTMLの自動エスケープ
    • CSRFチェック用のトークンを自動で追加
    • レスポンスヘッダに自動でセキュアになるやつを追加

    View Slide

  7. しかし
    • 魔法のようなプロダクトであるけれど、何も考えずブラッ
    クボックスとして扱っているとある日死ぬ
    • 何も考えずに などとす
    ると…

    View Slide

  8. 裏側を理解する事が
    大事

    View Slide

  9. ./bin/rails s の裏側

    View Slide

  10. bin/rails
    #!/usr/bin/env ruby
    begin
    load File.expand_path('../spring', __FILE__)
    rescue LoadError => e
    raise unless e.message.include?('spring')
    end
    APP_PATH = File.expand_path('../config/application', __dir__)
    require_relative '../config/boot'
    require 'rails/commands'

    View Slide

  11. config/boot.rb
    ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__)
    require 'bundler/setup' # Set up gems listed in the Gemfile.

    View Slide

  12. bundler/setup
    • Gemfileに書かれているgemへのLOAD_PATHを追加する
    • この後からgemのrequireができるようになる

    View Slide

  13. railties/lib/rails/
    commands.rb
    require "rails/command"
    aliases = {
    "g" => "generate",
    "d" => "destroy",
    "c" => "console",
    "s" => "server",
    "db" => "dbconsole",
    "r" => "runner",
    "t" => "test"
    }
    command = ARGV.shift
    command = aliases[command] || command
    Rails::Command.invoke command, ARGV

    View Slide

  14. lib/rails/commands/
    server/server_command.rb
    def perform
    set_application_directory!
    Rails::Server.new(server_options).tap do |server|
    require APP_PATH
    Dir.chdir(Rails.application.root)
    server.start
    end
    end

    View Slide

  15. APP_PATHはbin/railsで
    定義してた
    #!/usr/bin/env ruby
    begin
    load File.expand_path('../spring', __FILE__)
    rescue LoadError => e
    raise unless e.message.include?('spring')
    end
    APP_PATH = File.expand_path('../config/application', __dir__)
    require_relative '../config/boot'
    require 'rails/commands'

    View Slide

  16. config/applicaiton.rb
    require_relative 'boot'
    require 'rails/all'
    Bundler.require(*Rails.groups)
    module Hikalab
    class Application < Rails::Application
    config.load_defaults 5.1
    end
    end

    View Slide

  17. railties/lib/rails/
    all.rb
    require "rails"
    %w(
    active_record/railtie
    active_storage/engine
    action_controller/railtie
    action_view/railtie
    action_mailer/railtie
    active_job/railtie
    action_cable/engine
    rails/test_unit/railtie
    sprockets/railtie
    ).each do |railtie|
    begin
    require railtie
    rescue LoadError
    end
    end

    View Slide

  18. railties/lib/rails.rb
    module Rails
    class << self
    @application = @app_class = nil
    attr_writer :application
    def application
    @application ||= (app_class.instance if app_class)
    end
    # The Configuration instance used to configure the Rails environment
    def configuration
    application.config
    end
    def root
    application && application.config.root
    end
    def env
    @_env ||= ActiveSupport::StringInquirer.new(
    ENV["RAILS_ENV"].presence || ENV["RACK_ENV"].presence || “development"
    )
    end
    end
    end

    View Slide

  19. activerecord/lib/
    active_record/railtie.rb
    module ActiveRecord
    class Railtie < Rails::Railtie
    initializer "active_record.initialize_timezone" do
    ActiveSupport.on_load(:active_record) do
    self.time_zone_aware_attributes = true
    self.default_timezone = :utc
    end
    end
    initializer "active_record.logger" do
    ActiveSupport.on_load(:active_record) { self.logger ||= ::Rails.logger }
    end
    initializer "active_record.check_schema_cache_dump" do
    # ...
    end
    end
    end

    View Slide

  20. initializer do…end
    • Railsの初期設定を登録してあとで遅延実行するためのし
    くみ

    View Slide

  21. config/applicaiton.rb
    require_relative 'boot'
    require 'rails/all'
    Bundler.require(*Rails.groups)
    module Hikalab
    class Application < Rails::Application
    config.load_defaults 5.1
    end
    end

    View Slide

  22. Bundler.require
    • Gemfileに書かれたgemをrequireする

    View Slide

  23. サーバが立ち上がるとどうなるか
    • Rack::Serverは慣習的にconfig.ruという設定ファイルを
    読んで立ち上がる

    View Slide

  24. config.ru
    require_relative 'config/environment'
    run Rails.application

    View Slide

  25. config/environment.rb
    require_relative 'application'
    Rails.application.initialize!

    View Slide

  26. Rails.application.initialize!
    • ↑みたいなやつを実行する
    • config/initializers/*.rb を実行する
    initializer "active_record.initialize_timezone" do
    ActiveSupport.on_load(:active_record) do
    self.time_zone_aware_attributes = true
    self.default_timezone = :utc
    end
    end

    View Slide

  27. 時間足りないので
    一旦ここまで

    View Slide

  28. Railsのブートのまとめ
    • Gemfileのgemをrequireできるようにする
    • Railsの設定に必要なものだけ先にロードする(ただし評
    価は後)
    • Gemfileのgemをrequireする
    • 初期化処理をする

    View Slide

  29. これを知っていると
    どういうときに
    嬉しいか

    View Slide

  30. ハマリポイントを
    回避できる(ことがある)
    • gemの読み込み順番に起因するエラー
    • 設定の読み込み順番に起因するエラー
    • Rackミドルウェアの順番に起因する(ry

    View Slide

  31. 読み込み順に関連した事例
    http://y-yagi.tumblr.com/post/150899354290/rails

    View Slide

  32. まとめ

    View Slide

  33. この機能べんり!
    だけではなくて

    View Slide

  34. 裏側を理解する事が
    大事

    View Slide

  35. お互い頑張りましょう

    View Slide