Railsソース研究のActionController:二,routing
満城は黄金の甲を持っていて、ソースはroutingにあります.rb:
このファイルは有名なRAILSです.ROOT/config/routes.rbファイルの中のプログラムロジックのソースコードの出典
ActionController::Routing::Routes.draw do|map|はいったいどのように働いているのか:
1) Routes = RouteSet.new,drawメソッドももちろん呼び出されるRouteSetオブジェクトのdrawメソッド
2)draw法はyield Mapper.新(self)、すなわちRouteSetはメソッド呼び出しをその内部クラスMapperに渡し続ける
3)Mapperクラスでは、connectとmethod_の2つのメソッドが定義されています.missing
connectは私たちが伝説のroutesです.rbファイルでURL routingを定義ためのmap.connect
method_missingは@setを呼び出した.add_named_route、すなわちRouteSetクラスのadd_named_义齿
4)RouteSetはroutesとnamed_を定義しているroutesという2つのインスタンス変数は、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ファイルの最後に、前のroutesルールが一致していない場合、Route globbingとして使用されます.たとえば、次のようにします.
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.新(self)、すなわちRouteSetはメソッド呼び出しをその内部クラスMapperに渡し続ける
3)Mapperクラスでは、connectとmethod_の2つのメソッドが定義されています.missing
connectは私たちが伝説のroutesです.rbファイルでURL routingを定義ためのmap.connect
method_missingは@setを呼び出した.add_named_route、すなわちRouteSetクラスのadd_named_义齿
4)RouteSetはroutesとnamed_を定義しているroutesという2つのインスタンス変数は、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ファイルの最後に、前のroutesルールが一致していない場合、Route globbingとして使用されます.たとえば、次のようにします.
map.wildcard "*wildcard", :controller => "website", :action => "not_found"