aboutsummaryrefslogtreecommitdiffstats
path: root/actionpack/lib/action_dispatch/routing/mapper.rb
diff options
context:
space:
mode:
Diffstat (limited to 'actionpack/lib/action_dispatch/routing/mapper.rb')
-rw-r--r--actionpack/lib/action_dispatch/routing/mapper.rb76
1 files changed, 66 insertions, 10 deletions
diff --git a/actionpack/lib/action_dispatch/routing/mapper.rb b/actionpack/lib/action_dispatch/routing/mapper.rb
index 02a27110e4..1a1a054985 100644
--- a/actionpack/lib/action_dispatch/routing/mapper.rb
+++ b/actionpack/lib/action_dispatch/routing/mapper.rb
@@ -1,6 +1,7 @@
require 'active_support/core_ext/hash/except'
+require 'active_support/core_ext/hash/reverse_merge'
require 'active_support/core_ext/object/blank'
-require 'active_support/core_ext/object/inclusion'
+require 'active_support/core_ext/enumerable'
require 'active_support/inflector'
require 'action_dispatch/routing/redirection'
@@ -58,6 +59,16 @@ module ActionDispatch
@options = (@scope[:options] || {}).merge(options)
@path = normalize_path(path)
normalize_options!
+
+ via_all = @options.delete(:via) if @options[:via] == :all
+
+ if !via_all && request_method_condition.empty?
+ msg = "You should not use the `match` method in your router without specifying an HTTP method.\n" \
+ "If you want to expose your action to GET, use `get` in the router:\n\n" \
+ " Instead of: match \"controller#action\"\n" \
+ " Do: get \"controller#action\""
+ raise msg
+ end
end
def to_route
@@ -244,7 +255,7 @@ module ActionDispatch
end
def self.normalize_name(name)
- normalize_path(name)[1..-1].gsub("/", "_")
+ normalize_path(name)[1..-1].tr("/", "_")
end
module Base
@@ -254,11 +265,16 @@ module ActionDispatch
#
# For options, see +match+, as +root+ uses it internally.
#
+ # You can also pass a string which will expand
+ #
+ # root 'pages#main'
+ #
# You should put the root route at the top of <tt>config/routes.rb</tt>,
# because this means it will be matched first. As this is the most popular route
# of most Rails applications, this is beneficial.
def root(options = {})
- match '/', { :as => :root }.merge(options)
+ options = { :to => options } if options.is_a?(String)
+ match '/', { :as => :root, :via => :get }.merge(options)
end
# Matches a url pattern to one or more routes. Any symbols in a pattern
@@ -411,7 +427,7 @@ module ActionDispatch
options[:as] ||= app_name(app)
- match(path, options.merge(:to => app, :anchor => false, :format => false))
+ match(path, options.merge(:to => app, :anchor => false, :format => false, :via => :all))
define_generate_prefix(app, options[:as])
self
@@ -436,7 +452,7 @@ module ActionDispatch
app.railtie_name
else
class_name = app.class.is_a?(Class) ? app.name : app.class.name
- ActiveSupport::Inflector.underscore(class_name).gsub("/", "_")
+ ActiveSupport::Inflector.underscore(class_name).tr("/", "_")
end
end
@@ -446,7 +462,11 @@ module ActionDispatch
_route = @set.named_routes.routes[name.to_sym]
_routes = @set
app.routes.define_mounted_helper(name)
- app.routes.class_eval do
+ app.routes.singleton_class.class_eval do
+ define_method :mounted? do
+ true
+ end
+
define_method :_generate_prefix do |options|
prefix_options = options.slice(*_route.segment_keys)
# we must actually delete prefix segment keys to avoid passing them to next url_for
@@ -871,17 +891,18 @@ module ActionDispatch
# CANONICAL_ACTIONS holds all actions that does not need a prefix or
# a path appended since they fit properly in their scope level.
VALID_ON_OPTIONS = [:new, :collection, :member]
- RESOURCE_OPTIONS = [:as, :controller, :path, :only, :except]
+ RESOURCE_OPTIONS = [:as, :controller, :path, :only, :except, :param]
CANONICAL_ACTIONS = %w(index create new show update destroy)
class Resource #:nodoc:
- attr_reader :controller, :path, :options
+ attr_reader :controller, :path, :options, :param
def initialize(entities, options = {})
@name = entities.to_s
@path = (options[:path] || @name).to_s
@controller = (options[:controller] || @name).to_s
@as = options[:as]
+ @param = options[:param] || :id
@options = options
end
@@ -926,7 +947,7 @@ module ActionDispatch
alias :collection_scope :path
def member_scope
- "#{path}/:id"
+ "#{path}/:#{param}"
end
def new_scope(new_path)
@@ -934,7 +955,7 @@ module ActionDispatch
end
def nested_scope
- "#{path}/:#{singular}_id"
+ "#{path}/:#{singular}_#{param}"
end
end
@@ -1125,6 +1146,25 @@ module ActionDispatch
# comment PATCH/PUT /sekret/comments/:id(.:format)
# comment DELETE /sekret/comments/:id(.:format)
#
+ # [:shallow_prefix]
+ # Prefixes nested shallow route names with specified prefix.
+ #
+ # scope :shallow_prefix => "sekret" do
+ # resources :posts do
+ # resources :comments, :shallow => true
+ # end
+ # end
+ #
+ # 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_sekret_comment GET /comments/:id/edit(.:format)
+ # sekret_comment GET /comments/:id(.:format)
+ # sekret_comment PATCH/PUT /comments/:id(.:format)
+ # sekret_comment DELETE /comments/:id(.:format)
+ #
# === Examples
#
# # routes call <tt>Admin::PostsController</tt>
@@ -1265,6 +1305,21 @@ module ActionDispatch
parent_resource.instance_of?(Resource) && @scope[:shallow]
end
+ def draw(name)
+ path = @draw_paths.find do |_path|
+ _path.join("#{name}.rb").file?
+ end
+
+ unless path
+ msg = "Your router tried to #draw the external file #{name}.rb,\n" \
+ "but the file was not found in:\n\n"
+ msg += @draw_paths.map { |_path| " * #{_path}" }.join("\n")
+ raise msg
+ end
+
+ instance_eval(path.join("#{name}.rb").read)
+ end
+
# match 'path' => 'controller#action'
# match 'path', to: 'controller#action'
# match 'path', 'otherpath', on: :member, via: :get
@@ -1514,6 +1569,7 @@ module ActionDispatch
def initialize(set) #:nodoc:
@set = set
+ @draw_paths = set.draw_paths
@scope = { :path_names => @set.resources_path_names }
end