GithubHelp home page GithubHelp logo

Rails Boot Process about dylanninin.com HOT 1 CLOSED

dylanninin avatar dylanninin commented on July 20, 2024
Rails Boot Process

from dylanninin.com.

Comments (1)

dylanninin avatar dylanninin commented on July 20, 2024

A Request/Response Process

        begin
          status, headers, body = app.call(env)
          begin
            send_headers request.out, status, headers
            send_body request.out, body
          ensure
            body.close  if body.respond_to? :close
          end
        ensure
          rack_input.close
          request.finish
        end
    # railties/lib/rails/engine.rb#L519
    # Define the Rack API for this engine.
    def call(env)
      req = build_request env
      app.call req.env
    end
  • build_request env: build HTTP request enviroment . https://github.com/rails/rails/blob/master/railties/lib/rails/engine.rb#L692

      def build_request(env)
        env.merge!(env_config)
        req = ActionDispatch::Request.new env
        req.routes = routes
        req.engine_script_name = req.script_name
        req
      end
    def initialize(env)
      super
      @method            = nil
      @request_method    = nil
      @remote_ip         = nil
      @original_fullpath = nil
      @fullpath          = nil
      @ip                = nil
    end
    
    def commit_cookie_jar! # :nodoc:
    end
    
    PASS_NOT_FOUND = Class.new { # :nodoc:
      def self.action(_); self; end
      def self.call(_); [404, {'X-Cascade' => 'pass'}, []]; end
    }
    
    def controller_class
      params = path_parameters
    
      if params.key?(:controller)
        controller_param = params[:controller].underscore
        params[:action] ||= 'index'
        const_name = "#{controller_param.camelize}Controller"
        ActiveSupport::Dependencies.constantize(const_name)
      else
        PASS_NOT_FOUND
      end
    end
    
    def key?(key)
      has_header? key
    end
  • app: the app stack. https://github.com/rails/rails/blob/master/railties/lib/rails/engine.rb#L502

      ...
      delegate :middleware, :root, :paths, to: :config
      delegate :engine_name, :isolated?, to: :class
      ...
      # Returns the underlying rack application for this engine.
      def app
        @app || @app_build_lock.synchronize {
          @app ||= begin
            stack = default_middleware_stack
            config.middleware = build_middleware.merge_into(stack)
            config.middleware.build(endpoint)
          end
        }
      end
    
      # Returns the endpoint for this engine. If none is registered,
      # defaults to an ActionDispatch::Routing::RouteSet.
      def endpoint
        self.class.endpoint || routes
      end
      ...
      def default_middleware_stack #:nodoc:
        ActionDispatch::MiddlewareStack.new
      end
    # Defines the routes for this engine. If a block is given to
    # routes, it is appended to the engine.
    def routes
      @routes ||= ActionDispatch::Routing::RouteSet.new_with_config(config)
      @routes.append(&Proc.new) if block_given?
      @routes
    end
  • ActionDispatch::Routing::RouteSet: https://github.com/rails/rails/blob/master/actionpack/lib/action_dispatch/routing/route_set.rb#L722

      ...
      def initialize(config = DEFAULT_CONFIG)
        self.named_routes = NamedRouteCollection.new
        self.resources_path_names = self.class.default_resources_path_names
        self.default_url_options = {}

        @config                     = config
        @append                     = []
        @prepend                    = []
        @disable_clear_and_finalize = false
        @finalized                  = false
        @env_key                    = "ROUTES_#{object_id}_SCRIPT_NAME".freeze

        @set    = Journey::Routes.new
        @router = Journey::Router.new @set
        @formatter = Journey::Formatter.new self
      end
       ...
      def call(env)
        req = make_request(env)
        req.path_info = Journey::Router::Utils.normalize_path(req.path_info)
        @router.serve(req)
      end
     ... 
    def serve(req)
        find_routes(req).each do |match, parameters, route|
          set_params  = req.path_parameters
          path_info   = req.path_info
          script_name = req.script_name

          unless route.path.anchored
            req.script_name = (script_name.to_s + match.to_s).chomp('/')
            req.path_info = match.post_match
            req.path_info = "/" + req.path_info unless req.path_info.start_with? "/"
          end

          req.path_parameters = set_params.merge parameters

          status, headers, body = route.app.serve(req)

          if 'pass' == headers['X-Cascade']
            req.script_name     = script_name
            req.path_info       = path_info
            req.path_parameters = set_params
            next
          end

          return [status, headers, body]
        end
        ...
        def custom_routes
          routes.custom_routes
        end
        ...
        def find_routes req
          routes = filter_routes(req.path_info).concat custom_routes.find_all { |r|
            r.path.match(req.path_info)
          }

          routes =
            if req.head?
              match_head_routes(routes, req)
            else
              match_routes(routes, req)
            end

          routes.sort_by!(&:precedence)

          routes.map! { |r|
            match_data  = r.path.match(req.path_info)
            path_parameters = r.defaults.dup
            match_data.names.zip(match_data.captures) { |name,val|
              path_parameters[name.to_sym] = Utils.unescape_uri(val) if val
            }
            [match_data, path_parameters, r]
          }
        end
        def initialize(set, ast, defaults, controller, default_action, modyoule, to, formatted, scope_constraints, blocks, via, options_constraints, anchor, options)
          @defaults = defaults
          @set = set

          @to                 = to
          @default_controller = controller
          @default_action     = default_action
          @ast                = ast
          @anchor             = anchor
          @via                = via
          @internal           = options[:internal]

          path_params = ast.find_all(&:symbol?).map(&:to_sym)

          options = add_wildcard_options(options, formatted, ast)

          options = normalize_options!(options, path_params, modyoule)

          split_options = constraints(options, path_params)

          constraints = scope_constraints.merge Hash[split_options[:constraints] || []]

          if options_constraints.is_a?(Hash)
            @defaults = Hash[options_constraints.find_all { |key, default|
              URL_OPTIONS.include?(key) && (String === default || Fixnum === default)
            }].merge @defaults
            @blocks = blocks
            constraints.merge! options_constraints
          else
            @blocks = blocks(options_constraints)
          end

          requirements, conditions = split_constraints path_params, constraints
          verify_regexp_requirements requirements.map(&:last).grep(Regexp)

          formats = normalize_format(formatted)

          @requirements = formats[:requirements].merge Hash[requirements]
          @conditions = Hash[conditions]
          @defaults = formats[:defaults].merge(@defaults).merge(normalize_defaults(options))

          @required_defaults = (split_options[:required_defaults] || []).map(&:first)
        end

        def make_route(name, precedence)
          route = Journey::Route.new(name,
                            application,
                            path,
                            conditions,
                            required_defaults,
                            defaults,
                            request_method,
                            precedence,
                            @internal)

          route
        end

        def application
          app(@blocks)
        end
          def app(blocks)
            if to.is_a?(Class) && to < ActionController::Metal
              Routing::RouteSet::StaticDispatcher.new to
            else
              if to.respond_to?(:call)
                Constraints.new(to, blocks, Constraints::CALL)
              elsif blocks.any?
                Constraints.new(dispatcher(defaults.key?(:controller)), blocks, Constraints::SERVE)
              else
                dispatcher(defaults.key?(:controller))
              end
            end
          end
      ...
      def draw(&block)
        clear! unless @disable_clear_and_finalize
        eval_block(block)
        finalize! unless @disable_clear_and_finalize
        nil
      end
      ...
      def eval_block(block)
        mapper = Mapper.new(self)
        if default_scope
          mapper.with_default_scope(default_scope, &block)
        else
          mapper.instance_exec(&block)
        end
      end
      private :eval_block
    # Makes the controller a Rack endpoint that runs the action in the given
    # +env+'s +action_dispatch.request.path_parameters+ key.
    def self.call(env)
      req = ActionDispatch::Request.new env
      action(req.path_parameters[:action]).call(env)
    end
    class << self; deprecate :call; end

    # Returns a Rack endpoint for the given action name.
    def self.action(name)
      if middleware_stack.any?
        middleware_stack.build(name) do |env|
          req = ActionDispatch::Request.new(env)
          res = make_response! req
          new.dispatch(name, req, res)
        end
      else
        lambda { |env|
          req = ActionDispatch::Request.new(env)
          res = make_response! req
          new.dispatch(name, req, res)
        }
      end
    end

    # Direct dispatch to the controller.  Instantiates the controller, then
    # executes the action named +name+.
    def self.dispatch(name, req, res)
      if middleware_stack.any?
        middleware_stack.build(name) { |env| new.dispatch(name, req, res) }.call req.env
      else
        new.dispatch(name, req, res)
      end
    end

from dylanninin.com.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.