aboutsummaryrefslogtreecommitdiffstats
path: root/actionpack/lib/action_dispatch/routing
diff options
context:
space:
mode:
Diffstat (limited to 'actionpack/lib/action_dispatch/routing')
-rw-r--r--actionpack/lib/action_dispatch/routing/mapper.rb157
-rw-r--r--actionpack/lib/action_dispatch/routing/route_set.rb41
2 files changed, 125 insertions, 73 deletions
diff --git a/actionpack/lib/action_dispatch/routing/mapper.rb b/actionpack/lib/action_dispatch/routing/mapper.rb
index db1e3198b3..02a27110e4 100644
--- a/actionpack/lib/action_dispatch/routing/mapper.rb
+++ b/actionpack/lib/action_dispatch/routing/mapper.rb
@@ -54,6 +54,7 @@ module ActionDispatch
def initialize(set, scope, path, options)
@set, @scope = set, scope
+ @segment_keys = nil
@options = (@scope[:options] || {}).merge(options)
@path = normalize_path(path)
normalize_options!
@@ -213,7 +214,9 @@ module ActionDispatch
end
def segment_keys
- @segment_keys ||= Journey::Path::Pattern.new(
+ return @segment_keys if @segment_keys
+
+ @segment_keys = Journey::Path::Pattern.new(
Journey::Router::Strexp.compile(@path, requirements, SEPARATORS)
).names
end
@@ -325,7 +328,7 @@ module ActionDispatch
# +call+ or a string representing a controller's action.
#
# match 'path', :to => 'controller#action'
- # match 'path', :to => lambda { [200, {}, "Success!"] }
+ # match 'path', :to => lambda { |env| [200, {}, "Success!"] }
# match 'path', :to => RackApp
#
# [:on]
@@ -462,9 +465,9 @@ module ActionDispatch
#
# Example:
#
- # get 'bacon', :to => 'food#bacon'
+ # get 'bacon', :to => 'food#bacon'
def get(*args, &block)
- map_method(:get, *args, &block)
+ map_method(:get, args, &block)
end
# Define a route that only recognizes HTTP POST.
@@ -472,9 +475,19 @@ module ActionDispatch
#
# Example:
#
- # post 'bacon', :to => 'food#bacon'
+ # post 'bacon', :to => 'food#bacon'
def post(*args, &block)
- map_method(:post, *args, &block)
+ map_method(:post, args, &block)
+ end
+
+ # Define a route that only recognizes HTTP PATCH.
+ # For supported arguments, see <tt>Base#match</tt>.
+ #
+ # Example:
+ #
+ # patch 'bacon', :to => 'food#bacon'
+ def patch(*args, &block)
+ map_method(:patch, args, &block)
end
# Define a route that only recognizes HTTP PUT.
@@ -482,27 +495,26 @@ module ActionDispatch
#
# Example:
#
- # put 'bacon', :to => 'food#bacon'
+ # put 'bacon', :to => 'food#bacon'
def put(*args, &block)
- map_method(:put, *args, &block)
+ map_method(:put, args, &block)
end
- # Define a route that only recognizes HTTP PUT.
+ # Define a route that only recognizes HTTP DELETE.
# For supported arguments, see <tt>Base#match</tt>.
#
# Example:
#
- # delete 'broccoli', :to => 'food#broccoli'
+ # delete 'broccoli', :to => 'food#broccoli'
def delete(*args, &block)
- map_method(:delete, *args, &block)
+ map_method(:delete, args, &block)
end
private
- def map_method(method, *args, &block)
+ def map_method(method, args, &block)
options = args.extract_options!
options[:via] = method
- args.push(options)
- match(*args, &block)
+ match(*args, options, &block)
self
end
end
@@ -520,13 +532,13 @@ module ActionDispatch
# This will create a number of routes for each of the posts and comments
# controller. For <tt>Admin::PostsController</tt>, Rails will create:
#
- # GET /admin/posts
- # GET /admin/posts/new
- # POST /admin/posts
- # GET /admin/posts/1
- # GET /admin/posts/1/edit
- # PUT /admin/posts/1
- # DELETE /admin/posts/1
+ # GET /admin/posts
+ # GET /admin/posts/new
+ # POST /admin/posts
+ # GET /admin/posts/1
+ # GET /admin/posts/1/edit
+ # PATCH/PUT /admin/posts/1
+ # DELETE /admin/posts/1
#
# If you want to route /posts (without the prefix /admin) to
# <tt>Admin::PostsController</tt>, you could use
@@ -554,13 +566,13 @@ module ActionDispatch
# not use scope. In the last case, the following paths map to
# +PostsController+:
#
- # GET /admin/posts
- # GET /admin/posts/new
- # POST /admin/posts
- # GET /admin/posts/1
- # GET /admin/posts/1/edit
- # PUT /admin/posts/1
- # DELETE /admin/posts/1
+ # GET /admin/posts
+ # GET /admin/posts/new
+ # POST /admin/posts
+ # GET /admin/posts/1
+ # GET /admin/posts/1/edit
+ # PATCH/PUT /admin/posts/1
+ # DELETE /admin/posts/1
module Scoping
# Scopes a set of routes to the given default options.
#
@@ -649,13 +661,13 @@ module ActionDispatch
#
# This generates the following routes:
#
- # admin_posts GET /admin/posts(.:format) admin/posts#index
- # admin_posts POST /admin/posts(.:format) admin/posts#create
- # new_admin_post GET /admin/posts/new(.:format) admin/posts#new
- # edit_admin_post GET /admin/posts/:id/edit(.:format) admin/posts#edit
- # admin_post GET /admin/posts/:id(.:format) admin/posts#show
- # admin_post PUT /admin/posts/:id(.:format) admin/posts#update
- # admin_post DELETE /admin/posts/:id(.:format) admin/posts#destroy
+ # admin_posts GET /admin/posts(.:format) admin/posts#index
+ # admin_posts POST /admin/posts(.:format) admin/posts#create
+ # new_admin_post GET /admin/posts/new(.:format) admin/posts#new
+ # edit_admin_post GET /admin/posts/:id/edit(.:format) admin/posts#edit
+ # admin_post GET /admin/posts/:id(.:format) admin/posts#show
+ # admin_post PATCH/PUT /admin/posts/:id(.:format) admin/posts#update
+ # admin_post DELETE /admin/posts/:id(.:format) admin/posts#destroy
#
# === Options
#
@@ -970,12 +982,12 @@ module ActionDispatch
# the +GeoCoders+ controller (note that the controller is named after
# the plural):
#
- # GET /geocoder/new
- # POST /geocoder
- # GET /geocoder
- # GET /geocoder/edit
- # PUT /geocoder
- # DELETE /geocoder
+ # GET /geocoder/new
+ # POST /geocoder
+ # GET /geocoder
+ # GET /geocoder/edit
+ # PATCH/PUT /geocoder
+ # DELETE /geocoder
#
# === Options
# Takes same options as +resources+.
@@ -998,9 +1010,12 @@ module ActionDispatch
end if parent_resource.actions.include?(:new)
member do
- get :edit if parent_resource.actions.include?(:edit)
- get :show if parent_resource.actions.include?(:show)
- put :update if parent_resource.actions.include?(:update)
+ get :edit if parent_resource.actions.include?(:edit)
+ get :show if parent_resource.actions.include?(:show)
+ if parent_resource.actions.include?(:update)
+ patch :update
+ put :update
+ end
delete :destroy if parent_resource.actions.include?(:destroy)
end
end
@@ -1018,13 +1033,13 @@ module ActionDispatch
# creates seven different routes in your application, all mapping to
# the +Photos+ controller:
#
- # GET /photos
- # GET /photos/new
- # POST /photos
- # GET /photos/:id
- # GET /photos/:id/edit
- # PUT /photos/:id
- # DELETE /photos/:id
+ # GET /photos
+ # GET /photos/new
+ # POST /photos
+ # GET /photos/:id
+ # GET /photos/:id/edit
+ # PATCH/PUT /photos/:id
+ # DELETE /photos/:id
#
# Resources can also be nested infinitely by using this block syntax:
#
@@ -1034,13 +1049,13 @@ module ActionDispatch
#
# This generates the following comments routes:
#
- # GET /photos/:photo_id/comments
- # GET /photos/:photo_id/comments/new
- # POST /photos/:photo_id/comments
- # GET /photos/:photo_id/comments/:id
- # GET /photos/:photo_id/comments/:id/edit
- # PUT /photos/:photo_id/comments/:id
- # DELETE /photos/:photo_id/comments/:id
+ # GET /photos/:photo_id/comments
+ # GET /photos/:photo_id/comments/new
+ # POST /photos/:photo_id/comments
+ # GET /photos/:photo_id/comments/:id
+ # GET /photos/:photo_id/comments/:id/edit
+ # PATCH/PUT /photos/:photo_id/comments/:id
+ # DELETE /photos/:photo_id/comments/:id
#
# === Options
# Takes same options as <tt>Base#match</tt> as well as:
@@ -1102,13 +1117,13 @@ module ActionDispatch
#
# The +comments+ resource here will have the following routes generated for it:
#
- # post_comments GET /posts/:post_id/comments(.:format)
- # post_comments POST /posts/:post_id/comments(.:format)
- # new_post_comment GET /posts/:post_id/comments/new(.:format)
- # edit_comment GET /sekret/comments/:id/edit(.:format)
- # comment GET /sekret/comments/:id(.:format)
- # comment PUT /sekret/comments/:id(.:format)
- # comment DELETE /sekret/comments/:id(.:format)
+ # post_comments GET /posts/:post_id/comments(.:format)
+ # post_comments POST /posts/:post_id/comments(.:format)
+ # new_post_comment GET /posts/:post_id/comments/new(.:format)
+ # edit_comment GET /sekret/comments/:id/edit(.:format)
+ # comment GET /sekret/comments/:id(.:format)
+ # comment PATCH/PUT /sekret/comments/:id(.:format)
+ # comment DELETE /sekret/comments/:id(.:format)
#
# === Examples
#
@@ -1137,9 +1152,12 @@ module ActionDispatch
end if parent_resource.actions.include?(:new)
member do
- get :edit if parent_resource.actions.include?(:edit)
- get :show if parent_resource.actions.include?(:show)
- put :update if parent_resource.actions.include?(:update)
+ get :edit if parent_resource.actions.include?(:edit)
+ get :show if parent_resource.actions.include?(:show)
+ if parent_resource.actions.include?(:update)
+ patch :update
+ put :update
+ end
delete :destroy if parent_resource.actions.include?(:destroy)
end
end
@@ -1247,6 +1265,9 @@ module ActionDispatch
parent_resource.instance_of?(Resource) && @scope[:shallow]
end
+ # match 'path' => 'controller#action'
+ # match 'path', to: 'controller#action'
+ # match 'path', 'otherpath', on: :member, via: :get
def match(path, *rest)
if rest.empty? && Hash === path
options = path
diff --git a/actionpack/lib/action_dispatch/routing/route_set.rb b/actionpack/lib/action_dispatch/routing/route_set.rb
index 2c21887220..57c6972078 100644
--- a/actionpack/lib/action_dispatch/routing/route_set.rb
+++ b/actionpack/lib/action_dispatch/routing/route_set.rb
@@ -9,6 +9,12 @@ require 'action_controller/metal/exceptions'
module ActionDispatch
module Routing
class RouteSet #:nodoc:
+ # Since the router holds references to many parts of the system
+ # like engines, controllers and the application itself, inspecting
+ # the route set can actually be really slow, therefore we default
+ # alias inspect to to_s.
+ alias inspect to_s
+
PARAMETERS_KEY = 'action_dispatch.request.path_parameters'
class Dispatcher #:nodoc:
@@ -31,6 +37,7 @@ module ActionDispatch
end
def prepare_params!(params)
+ normalize_controller!(params)
merge_default_action!(params)
split_glob_param!(params) if @glob_param
end
@@ -66,6 +73,10 @@ module ActionDispatch
controller.action(action).call(env)
end
+ def normalize_controller!(params)
+ params[:controller] = params[:controller].underscore if params.key?(:controller)
+ end
+
def merge_default_action!(params)
params[:action] ||= 'index'
end
@@ -246,8 +257,7 @@ module ActionDispatch
def eval_block(block)
if block.arity == 1
raise "You are using the old router DSL which has been removed in Rails 3.1. " <<
- "Please check how to update your routes file at: http://www.engineyard.com/blog/2010/the-lowdown-on-routes-in-rails-3/ " <<
- "or add the rails_legacy_mapper gem to your Gemfile"
+ "Please check how to update your routes file at: http://www.engineyard.com/blog/2010/the-lowdown-on-routes-in-rails-3/"
end
mapper = Mapper.new(self)
if default_scope
@@ -360,7 +370,26 @@ module ActionDispatch
SEPARATORS,
anchor)
- Journey::Path::Pattern.new(strexp)
+ pattern = Journey::Path::Pattern.new(strexp)
+
+ builder = Journey::GTG::Builder.new pattern.spec
+
+ # Get all the symbol nodes followed by literals that are not the
+ # dummy node.
+ symbols = pattern.spec.grep(Journey::Nodes::Symbol).find_all { |n|
+ builder.followpos(n).first.literal?
+ }
+
+ # Get all the symbol nodes preceded by literals.
+ symbols.concat pattern.spec.find_all(&:literal?).map { |n|
+ builder.followpos(n).first
+ }.find_all(&:symbol?)
+
+ symbols.each { |x|
+ x.regexp = /(?:#{Regexp.union(x.regexp, '-')})+/
+ }
+
+ pattern
end
private :build_path
@@ -463,7 +492,7 @@ module ActionDispatch
# if the current controller is "foo/bar/baz" and :controller => "baz/bat"
# is specified, the controller becomes "foo/baz/bat"
def use_relative_controller!
- if !named_route && different_controller?
+ if !named_route && different_controller? && !controller.start_with?("/")
old_parts = current_controller.split('/')
size = controller.count("/") + 1
parts = old_parts[0...-size] << controller
@@ -548,6 +577,7 @@ module ActionDispatch
path_addition, params = generate(path_options, path_segments || {})
path << path_addition
+ params.merge!(options[:params] || {})
ActionDispatch::Http::URL.url_for(options.merge!({
:path => path,
@@ -579,7 +609,8 @@ module ActionDispatch
params[key] = URI.parser.unescape(value)
end
end
-
+ old_params = env[::ActionDispatch::Routing::RouteSet::PARAMETERS_KEY]
+ env[::ActionDispatch::Routing::RouteSet::PARAMETERS_KEY] = (old_params || {}).merge(params)
dispatcher = route.app
while dispatcher.is_a?(Mapper::Constraints) && dispatcher.matches?(env) do
dispatcher = dispatcher.app