`
hideto
  • 浏览: 2666316 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

Rails源码研究之ActionController:二,routing

    博客分类:
  • Ruby
阅读更多
满城尽带黄金甲,源码尽在routing.rb:
module ActionController
  module Routing

    class Route
      attr_accessor :segments, :requirements, :conditions
    end

    class RouteBuilder
      def build(path, options)
        path = "/#{path}" unless path[0] == ?/
        path = "#{path}/" unless path[-1] == ?/
        segments = segments_for_route_path(path)
        defaults, requirements, conditions = divide_route_options(segments, options)
        requirements = assign_route_options(segments, defaults, requirements)
        route = Route.new
        route.segments = segments
        route.requirements = requirements
        route.conditions = conditions
        if !route.significant_keys.include?(:action) && !route.requirements[:action]
          route.requirements[:action] = "index"
          route.significant_keys << :action
        end
        if !route.significant_keys.include?(:controller)
          raise ArgumentError, "Illegal route: the :controller must be specified!"
        end
        route
      end
    end

    class RouteSet

      class Mapper
        def initialize(set)
          @set = set
        end
        def connect(path, options = {})
          @set.add_route(path, options)
        end
        def root(*args, &proc)
          super unless args.length >= 1 && proc.nil?
          @set.add_named_route("root", *args)
        end
        def method_missing(route_name, *args, &proc)
          super unless args.length >= 1 && proc.nil?
          @set.add_named_route(route_name, *args)
        end
      end
      
      class NamedRouteCollection
        include Enumerable
        attr_reader :routes, :helpers
        def initialize
          clear!
        end
        def clear!
          @routes = {}
          @helpers = []
          @module ||= Module.new
          @module.instance_methods.each do |selector|
            @module.send :remove_method, selector
          end
        end
        def add(name, route)
          routes[name.to_sym] = route
          define_named_route_methods(name, route)
        end
        def install(destinations = [ActionController::Base, ActionView::Base])
          Array(destinations).each { |dest| dest.send :include, @module }
        end
        private
          def define_named_route_methods(name, route)
            {:url => {:only_path => false}, :path => {:only_path => true}}.each do |kind, opts|
              hash = route.defaults.merge(:use_route => name).merge(opts)
              define_hash_access route, name, kind, hash
              define_url_helper route, name, kind, hash
            end
          end
          def define_url_helper(route, name, kind, options)
            selector = url_helper_name(name, kind)
            segment_keys = route.segments.collect do |segment|
              segment.key if segment.respond_to? :key
            end.compact
            hash_access_method = hash_access_name(name, kind)
            @module.send :module_eval, <<-end_eval
              def #{selector}(*args)
                opts = if args.empty? || Hash === args.first
                  args.first || {}
                else
                  args.zip(#{segment_keys.inspect}).inject({}) do |h, (v, k)|
                    h[k] = v
                    h
                  end
                end
                url_for(#{hash_access_method}(opts))
              end
            end_eval
            @module.send(:protected, selector)
            helpers << selector
          end
          def url_helper_name(name, kind = :url)
            :"#{name}_#{kind}"
          end
      end

      attr_accessor :routes, :named_routes

      def initialize
        self.routes = []
        self.named_routes = NamedRouteCollection.new
      end

      def builder
        @builder ||= RouteBuilder.new
      end

      def draw
        clear!
        yield Mapper.new(self)
        named_routes.install
      end

      def clear!
        routes.clear
        named_routes.clear
        @combined_regexp = nil
        @routes_by_controller = nil
      end

      def add_route(path, options = {})
        route = builder.build(path, options)
        routes << route
        route
      end
  
      def add_named_route(name, path, options = {})
        named_routes[name] = add_route(path, options)
      end

    end

    Routes = RouteSet.new
  end
end


该文件就是大名鼎鼎的RAILS_ROOT/config/routes.rb文件里的程序逻辑的源代码出处
让我们看看ActionController::Routing::Routes.draw do |map|到底是怎样工作的:
1) Routes = RouteSet.new,draw方法当然也是调用的RouteSet对象的draw方法
2) draw方法则yield Mapper.new(self),即RouteSet将方法调用继续传递给它的内部类Mapper
3) Mapper类定义了两个方法: connect和method_missing
connect就是我们在传说中的routes.rb文件中用来定义URL routing的map.connect
method_missing则调用了@set.add_named_route,即RouteSet类的add_named_route方法
4)RouteSet定义了routes和named_routes这两个实例变量,分别用来存放connect route和named_route
5)add_named_route方法中调用了add_route方法中的RouteBuilder.build方法来构造一个route
而NamedRouteCollection定义了add方法,其中调用了define_named_route_methods -> define_url_helper
其中定义了#{route_name}_url和#{route_name}_path方法,而且使用了UrlWriter模块的url_for方法

我们还要注意几点:
1,routes有priority,routes.rb文件里从上到下routing规则的priority为从高到低
2,map.root方法在Rails 2.0中用来作为map.connect ''的shortcut,实际上是@set.add_named_route("root", *args),我们可以使用root_url和root_path方法
3,将*path这种route rule放在routes.rb文件的最后,用来做Route globbing,即前面的routes规则都没匹配时,使用该规则来匹配,如:
map.wildcard "*wildcard", :controller => "website", :action => "not_found"
分享到:
评论

相关推荐

    Rails的精简版本Rails::API.zip

    Rails::API 移除了 ActionView 和其他一些渲染功能,不关心Web前端的开发者可更容易、快速地开发应用程序,因此运行速度比正常的 Rails 应用程序要快。 Rails::API 可以用来创建只提供API服务(API-Only)的 Rails ...

    live-stream:Rails 4 ActionController Live Stream 演示简单的聊天应用程序

    使用 Rails 4 的简单聊天应用程序 - ActionController::Live 应用组件: 1 . 使用 Rails 4 ActionController::Live 的聊天应用程序 2 . 基本 LDAP 身份验证 3 . Redis 服务器集成 4 . 彪马服务器 1 . Rails 4 ...

    Rails中应用Ext.tree:以中国的省市地区三级联动选择为例

    在Ruby on Rails(Rails)框架中,开发人员经常需要实现各种用户交互功能,例如三级联动选择,这在处理如中国省市区这样的地理数据时尤其常见。这篇博客文章“Rails中应用Ext.tree:以中国的省市地区三级联动选择为...

    Rails进行敏捷Web开发(所有版本的源码rails3.0-4.0)

    1. Rails 3.0: Rails 3是重大升级,引入了ActionController::Metal,这是一个轻量级的控制器,用于提高性能。同时,它引入了多路由引擎支持,如Rack中间件,使得与其他Web服务器的集成更加容易。此外,ActiveRecord...

    rails-exporter-源码.rar

    《Rails Exporter 源码解析》 Rails Exporter 是一个用于 Rails 应用程序的开源工具,主要用于数据导出功能。源码分析将帮助我们深入理解其内部工作原理,以便更好地利用它来优化我们的应用。 一、Rails 框架基础 ...

    Rails项目源代码

    这个Rails项目提供了学习和研究Web开发的机会,特别是对于Ruby on Rails新手,可以通过阅读和理解源代码来提升技能,了解实际应用中Rails的用法。同时,对于有经验的开发者,这个项目也可以作为一个起点,进行二次...

    ruby on rails 教程源码

    Ruby on Rails,简称Rails,是基于Ruby语言的开源Web应用框架,它遵循MVC(Model-View-Controller)架构模式,旨在使开发过程更加简洁高效。这个“ruby on rails 教程源码”很可能是为了辅助学习者深入理解Rails的...

    Rails 4 in Action, Second Edition.pdf

    为了帮助读者更好地理解和应用所学知识,**Rails 4 in Action, 第二版** 包含了一系列案例研究和实战项目,例如: - **电子商务网站开发**:从零开始构建一个完整的电子商务平台,涵盖商品管理、订单处理等功能。 -...

    Rails相关电子书汇总二

    标题 "Rails相关电子书汇总二" 提供的信息表明,这个压缩包包含的资源主要与Ruby on Rails框架有关,特别是从“Rubyisms in Rails”的书名来看,我们可以期待它深入探讨了Ruby语言在Rails框架中的独特用法和特性。...

    Rails 3 in Action

    《Rails 3 in Action》是2011年由Ryan Bigg撰写的一本关于Ruby on Rails框架的权威指南,专门针对当时最新的Rails 3.1版本进行了深入解析。这本书旨在帮助开发者充分利用Rails 3.1的强大功能,提升Web应用开发的效率...

    rails-controller-testing:将`assigns`和`assert_template`带回到您的Rails测试中

    Rails :: Controller :: Testing 这个gem将assigns给控制器测试的内容以及assert_template带回assigns控制器和集成测试的内容。 这些方法已中。 安装 将此行添加到您的应用程序的Gemfile中: gem 'rails-...

    《Ruby On Rails》 源码 下载、导入、运行

    本书源码 博文链接:https://msnvip.iteye.com/blog/139752

    bhl_rails_solr-源码.rar

    《深入解析bhl_rails_solr源码》 在当今的Web开发领域,Rails框架以其高效、简洁的设计理念,深受开发者喜爱。同时,Solr作为一款强大的全文搜索引擎,被广泛应用于各类复杂的数据检索场景。当这两者结合时,便诞生...

    基于ruby on rails开发示例源码

    Rails的许多特性,如ActiveRecord(ORM)、ActiveModel、ActionController和ActionView,都是为了支持这种分层架构。 压缩包中的`seanatnci-rails_space-53c56b4`可能是一个具体的Rails项目仓库,包含以下关键组成...

    Web开发敏捷之道--应用Rails进行敏捷Web开发 之 Depot代码。

    标题中的“Web开发敏捷之道--应用Rails进行敏捷Web开发 之 Depot代码”表明这是一个关于使用Ruby on Rails框架进行敏捷Web开发的示例项目,名为Depot。Ruby on Rails(简称Rails)是一个开源的Web应用程序框架,它...

    rails 2.2.2 API

    13. **测试(Testing)**:Rails 提供了全面的测试支持,包括单元测试(Test::Unit)、集成测试( ActionController::IntegrationTest)和行为驱动开发(RSpec)。 14. **配置(Configuration)**:Rails 应用可以...

    ruby on rails社区网站开发源码

    通过研究这个源码,你可以深入理解Rails的工作原理,学习如何设计和实现社区网站的核心功能,如用户注册、论坛讨论、个人资料管理等。同时,这也是一个绝佳的机会去实践敏捷开发和TDD(测试驱动开发)原则,提升你的...

Global site tag (gtag.js) - Google Analytics