Ruby on Rails-2.0.2 source code analysis (3)-named route

Source: Internet
Author: User
Tags ruby on rails
  • Preface

In routing loading, I roughly introduced how to load the simplest route in rails. In this article, I will introduce how more complex named route and restful-related resources in the rails system are loaded. In order not to repeat too much pen and ink, this article will be carried out on the basis of the previous article. If you find that when reading this article separately, you are a little confused. I suggest you take a look at my previous article first: ruby on Rails-2.0.2 source code analysis (2)-loading Routing

  • Evolutionary routing-named route

First, all loading of the named route occurs in routing. RB. In fact, named route is no more advanced than normal route, rails eventually resolves the named route into a normal route and saves it in the routes array of the rouseset class (remember this guy? It is best to keep him in mind, because he will continue to play an important role in subsequent articles). The reason why I called him evolution is that since named route provides name, inside rails, A series of helper methods will be generated. When we use link_to, redirect_to, and other methods in the Controller or view, we do not need to specify the corresponding controller and action to simplify our code, no more. Let's take a look at the routes we are familiar. RB

Ruby code
  1. Actioncontroller: routing: routes. DrawDo| Map |
  2. Map. Purchase 'products/: ID/purchase ',: controller => 'catalog',: Action => 'purchase'
  3. ...
  4. End
ActionController::Routing::Routes.draw do |map|  map.purchase 'products/:id/purchase', :controller => 'catalog', :action => 'purchase'  ...end

Here, I define a named route for purchase (of course, you can use the connect method to define a normal route ). As mentioned in the previous article, the map object in the block is an mapper class instance. As you can imagine, in fact, the Mapper class does not define the purchase method (which name do you want to give your named route? Cuihua? Wangcai ?). Everything is handled through the method_missing method of the Mapper class. The Code is as follows:

Ruby code
  1. DefMethod_missing (route_name, * ARGs, & proc) #: nodoc:
  2. Super UnlessArgs. length> = 1 & Proc.Nil?
  3. @ Set. Add_named_route (route_name, * ARGs)
  4. End
def method_missing(route_name, *args, &proc) #:nodoc:  super unless args.length >= 1 && proc.nil?  @set.add_named_route(route_name, *args)end

If you have a good memory, remember that the @ set object is an instance of the routeset class, so here the Mapper class will name this route, all other parameters are passed to the add_named_route method of the routeset class.

Ruby code
  1. DefAdd_named_route (name, path, Options = {})
  2. # Todo-Is options ever used?
  3. Name = options [: name_prefix] + name. to_sIfOptions [: name_prefix]
  4. Named_routes [name. to_sym] = add_route (path, options)
  5. End
def add_named_route(name, path, options = {})  # TODO - is options EVER used?  name = options[:name_prefix] + name.to_s if options[:name_prefix]  named_routes[name.to_sym] = add_route(path, options)end

Here, we can see the add_route method we have already been familiar? This method does not need to be explained too much. rails will generate a normal route, store it in the routes array of routeset, return this route, and assign it to the named_routes object, this object is an instance of the namedroutecollection class. The following definitions are available in namedroutecollection:

 

Ruby code
  1. DefAdd (name, route)
  2. Routes [name. to_sym] = route
  3. Define_named_route_methods (name, route)
  4. End
  5. DefGet (name)
  6. Routes [name. to_sym]
  7. End
  8. Alias[] = Add
  9. Alias[] Get
def add(name, route)  routes[name.to_sym] = route  define_named_route_methods(name, route)enddef get(name)  routes[name.to_sym]endalias []=   addalias []    get

Therefore, the next step seems to be concerned about the add method. Here, the normal route is saved in the routes hash of the namedroutecollection class (note that it is distinguished from the routes array of the routeset ). Then, the named route begins to "evolve" ---- generate a series of helper methods by using the define_named_route_methods method.

Ruby code
  1. DefDefine_named_route_methods (name, route)
  2. {: URL =>{: only_path =>False},: Path => {: only_path =>True}}.Each Do| Kind, opts |
  3. Hash = route. defaults. Merge (: use_route => name). Merge (OPTs)
  4. Define_hash_access route, name, kind, hash
  5. Define_url_helper route, name, kind, hash
  6. End
  7. End
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  endend

Or you already know that named route has two types of helper Methods: name_url and name_path. From the above code, we can see the real implementation. Here, rails generates hash access and URL helper methods for URLs and paths respectively, and their implementation uses Ruby's powerful dynamic features. The specific implementation is as follows:

 

Ruby code
  1. DefDefine_hash_access (route, name, kind, options)
  2. Selector = hash_access_name (name, kind)
  3. @ Module. Module_eval <-end_eval # We use module_eval to avoid leaks
  4. Def# {Selector} (Options = nil)
  5. Options? # {Options. Inspect}. Merge (options): # {options. Inspect}
  6. End
  7. Protected: # {selector}
  8. End_eval
  9. Helpers <Selector
  10. End
  11. DefDefine_url_helper (route, name, kind, options)
  12. Selector = url_helper_name (name, kind)
  13. # The segment keys used for positional paramters
  14. Hash_access_method = hash_access_name (name, kind)
  15. @ Module. Module_eval <-end_eval # We use module_eval to avoid leaks
  16. Def# {Selector} (* ARGs)
  17. # {Generate_optimisation_block (route, kind )}
  18. Opts =IfArgs. Empty? | Hash = args. First
  19. Args. First | {}
  20. Else
  21. Options = args. Last. is_a? (Hash )? Args. Pop :{}
  22. ARGs = args.zip (# {route. segment_keys.inspect}). Inject ({}) Do | h, (v, k) |
  23. H [k] = V
  24. H
  25. End
  26. Options. Merge (ARGs)
  27. End
  28. Url_for (# {hash_access_method} (OPTs ))
  29. End
  30. Protected: # {selector}
  31. End_eval
  32. Helpers <Selector
  33. End
 def define_hash_access(route, name, kind, options)      selector = hash_access_name(name, kind)      @module.module_eval <<-end_eval # We use module_eval to avoid leaks        def #{selector}(options = nil)          options ? #{options.inspect}.merge(options) : #{options.inspect}        end        protected :#{selector}      end_eval      helpers << selector    end    def define_url_helper(route, name, kind, options)      selector = url_helper_name(name, kind)      # The segment keys used for positional paramters      hash_access_method = hash_access_name(name, kind)      @module.module_eval <<-end_eval # We use module_eval to avoid leaks        def #{selector}(*args)          #{generate_optimisation_block(route, kind)}          opts = if args.empty? || Hash === args.first            args.first || {}          else            options = args.last.is_a?(Hash) ? args.pop : {}            args = args.zip(#{route.segment_keys.inspect}).inject({}) do |h, (v, k)|              h[k] = v              h            end            options.merge(args)          end          url_for(#{hash_access_method}(opts))        end        protected :#{selector}      end_eval      helpers << selector    end

@ Module is an anonymous module in the namedroutecollection class. It dynamically adds this series of helper methods through the module_eval method and saves the method name in the helpers array, for later use by the Controller or view (link_to, redirect_to ). So far, the loading of the named route is complete. Very simple, isn't it?

 

This article from: http://woody-420420.javaeye.com/blog/174352

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.