Router stores route definitions and finds the first route that matches the incoming request URL.
Then information from route is used by dispatcher to call action on the controller.
The most interesting method of Router (and heart of route matching machinery) is match method generated on the fly from routes definitions. It is called routes compilation. Generated match method body contains one if/elsif statement that picks the first matching route definition and sets values to named parameters of the route.
Compilation is synchronized by mutex.
match_before_compilation | -> | match |
match_before_compilation | -> | match |
around_match | [RW] |
A block that will be run around route matching. This block must yield in
order for the actual matching to happen.
:api: plugin |
named_routes | [RW] |
A hash containing all the named application routes. The names are absolute
(as in, all routes named in a namespace will contain the name of the
namespace).
:api: private |
resource_routes | [RW] |
A hash of all the application resource
routes. The key of the hash is an array with each element containing the
"path" for the resource for
example, given the following resource
routes:
resources :users do resources :comments end The show comment route will have a key of ["User", "Comment"] :api: private |
root_behavior | [RW] |
The starting point for route definition. Any route defined in a Merb::Router.prepare block will defined in
context of this behavior.
ExamplesMerb::Router.root_behavior = Merb::Router.root_bavior.match("/hello") In the previous example, all routes will have the path prefix /hello. It is important to note that this attribute must be set before any routes are defined in order for the behavior to be applied to the routes. :api: plugin |
routes | [RW] |
An array containing all the application routes in order of priority.
:api: private |
Add functionality to the router. This can be in the form of including a new module or directly defining new methods.
&block<Block>: | A block of code used to extend the route builder with. This can be including a module or directly defining some new methods that should be available to building routes. |
nil
Merb::Router.extensions do def domain(name, domain, options={}, &block) match(:domain => domain).namespace(name, :path => nil, &block) end end
In this case, a method ‘domain’ will be available to the route builder which will create namespaces around domains instead of path prefixes.
This can then be used as follows.
Merb::Router.prepare do domain(:admin, "my-admin.com") do # ... routes come here ... end end
:api: public
# File merb-core/lib/merb-core/dispatch/router.rb, line 310 310: def extensions(&block) 311: Router::Behavior.class_eval(&block) 312: end
Creates a route building context and evaluates the block in it. A copy of root_behavior (and instance of Behavior) is copied as the context.
first<Array>: | An array containing routes that should be prepended to the routes defined in the block. |
last<Array>: | An array containing routes that should be appended to the routes defined in the block. |
Merb::Router: | Returns self to allow chaining of methods. |
:api: public
# File merb-core/lib/merb-core/dispatch/router.rb, line 103 103: def prepare(first = [], last = [], &block) 104: @routes = [] 105: root_behavior._with_proxy(&block) 106: @routes = first + @routes + last 107: compile 108: self 109: end
Clears the routing table. Route generation and request matching won‘t work anymore until a new routing table is built.
:api: private
# File merb-core/lib/merb-core/dispatch/router.rb, line 115 115: def reset! 116: class << self 117: alias_method :match, :match_before_compilation 118: end 119: self.routes, self.named_routes, self.resource_routes = [], {}, {} 120: end
Generates a URL from the resource(s)
resources<Symbol,Object>: | The identifiers for the resource route to generate. These can either be symbols or objects. Symbols denote resource collection routes and objects denote the members. |
params<Hash>: | Any extra parameters needed to generate the route. |
String: | The generated URL |
:api: plugin
# File merb-core/lib/merb-core/dispatch/router.rb, line 255 255: def resource(*args) 256: defaults = args.pop 257: options = extract_options_from_args!(args) || {} 258: key = [] 259: params = [] 260: 261: args.each do |arg| 262: if arg.is_a?(Symbol) || arg.is_a?(String) 263: key << arg.to_s 264: else 265: key << arg.class.to_s 266: params << arg 267: end 268: end 269: 270: unless route = Merb::Router.resource_routes[key] 271: raise Merb::Router::GenerationError, "Resource route not found: #{args.inspect}" 272: end 273: 274: params << options 275: 276: route.generate(params, defaults, true) 277: end
Finds route matching URI of the request and returns a tuple of [route index, route params]. This method is called by the dispatcher and isn‘t as useful in applications.
request<Merb::Request>: | request to match. |
Array[Integer, Hash]: | Two-tuple: route index and route parameters. Route parameters are :controller, :action and all the named segments of the route. |
:api: private
# File merb-core/lib/merb-core/dispatch/router.rb, line 135 135: def route_for(request) 136: index, params = if @around_match 137: send(@around_match, request) { match(request) } 138: else 139: match(request) 140: end 141: route = routes[index] if index 142: if !route 143: raise ControllerExceptions::NotFound, 144: "No routes match the request: #{request.uri}" 145: end 146: [route, params] 147: end
There are three possible ways to use this method. First, if you have a named route, you can specify the route as the first parameter as a symbol and any paramters in a hash. Second, you can generate the default route by just passing the params hash, just passing the params hash. Finally, you can use the anonymous parameters. This allows you to specify the parameters to a named route in the order they appear in the router.
name<Symbol>: | The name of the route. |
args<Hash>: | Parameters for the route generation. |
args<Hash>: | Parameters for the route generation. This route will use the default route. |
name<Symbol>: | The name of the route. |
args<Array>: | An array of anonymous parameters to generate the route with. These parameters are assigned to the route parameters in the order that they are passed. |
String: | The generated URL. |
Named Route
match("/articles/:title").to(:controller => :articles, :action => :show).name("articles")
end
url(:articles, :title => "new_article")
Default Route
default_routes
end
url(:controller => "articles", :action => "new")
Anonymous Paramters
match("/articles/:year/:month/:title").to(:controller => :articles, :action => :show).name("articles")
end
url(:articles, 2008, 10, "test_article")
:api: plugin
# File merb-core/lib/merb-core/dispatch/router.rb, line 221 221: def url(name, *args) 222: if name.is_a?(Route) 223: route = name 224: else 225: unless name.is_a?(Symbol) 226: args.unshift(name) 227: name = :default 228: end 229: 230: unless route = Merb::Router.named_routes[name] 231: raise Merb::Router::GenerationError, "Named route not found: #{name}" 232: end 233: end 234: 235: defaults = args.pop 236: 237: route.generate(args, defaults) 238: end
Compiles the routes and creates the match method.
:api: private
# File merb-core/lib/merb-core/dispatch/router.rb, line 319 319: def compile 320: if routes.any? 321: begin 322: eval(compiled_statement, binding, "Generated Code for Router", 1) 323: rescue SyntaxError => e 324: puts "\nGenerated code failed:\n #{compiled_statement}" 325: raise e 326: end 327: else 328: reset! 329: end 330: end
Generates the method for evaluation defining a match method to match a request with the defined routes.
:api: private
# File merb-core/lib/merb-core/dispatch/router.rb, line 336 336: def compiled_statement 337: @compiler_mutex.synchronize do 338: condition_keys, if_statements = Set.new, "" 339: 340: routes.each_with_index do |route, i| 341: route.freeze 342: route.conditions.keys.each { |key| condition_keys << key } 343: if_statements << route.compiled_statement(i == 0) 344: end 345: 346: statement = "def match(request)\n" 347: statement << condition_keys.inject("") do |cached, key| 348: cached << " cached_#{key} = request.#{key}.to_s\n" 349: end 350: statement << if_statements 351: statement << " else\n" 352: statement << " [nil, {}]\n" 353: statement << " end\n" 354: statement << "end" 355: end 356: end