diff options
Diffstat (limited to 'actionpack/lib/action_dispatch/routing')
-rw-r--r-- | actionpack/lib/action_dispatch/routing/mapper.rb | 53 | ||||
-rw-r--r-- | actionpack/lib/action_dispatch/routing/route_set.rb | 26 | ||||
-rw-r--r-- | actionpack/lib/action_dispatch/routing/url_for.rb | 2 |
3 files changed, 58 insertions, 23 deletions
diff --git a/actionpack/lib/action_dispatch/routing/mapper.rb b/actionpack/lib/action_dispatch/routing/mapper.rb index f9b27a5a03..5a3868e1d4 100644 --- a/actionpack/lib/action_dispatch/routing/mapper.rb +++ b/actionpack/lib/action_dispatch/routing/mapper.rb @@ -32,6 +32,8 @@ module ActionDispatch end class Mapping + IGNORE_OPTIONS = [:to, :as, :controller, :action, :via, :on, :constraints, :defaults, :only, :except, :anchor] + def initialize(set, scope, args) @set, @scope = set, scope @path, @options = extract_path_and_options(args) @@ -45,18 +47,21 @@ module ActionDispatch def extract_path_and_options(args) options = args.extract_options! - case - when using_to_shorthand?(args, options) + if using_to_shorthand?(args, options) path, to = options.find { |name, value| name.is_a?(String) } options.merge!(:to => to).delete(path) if path - when using_match_shorthand?(args, options) - path = args.first - options = { :to => path.gsub("/", "#"), :as => path.gsub("/", "_") } else path = args.first end - [ normalize_path(path), options ] + path = normalize_path(path) + + if using_match_shorthand?(path, options) + options[:to] ||= path[1..-1].sub(%r{/([^/]*)$}, '#\1') + options[:as] ||= path[1..-1].gsub("/", "_") + end + + [ path, options ] end # match "account" => "account#index" @@ -65,14 +70,13 @@ module ActionDispatch end # match "account/overview" - def using_match_shorthand?(args, options) - args.present? && options.except(:via, :anchor).empty? && !args.first.include?(':') + def using_match_shorthand?(path, options) + path && options.except(:via, :anchor, :to, :as).empty? && path =~ %r{^/[\w\/]+$} end def normalize_path(path) - path = "#{@scope[:path]}/#{path}" - raise ArgumentError, "path is required" if path.empty? - Mapper.normalize_path(path) + raise ArgumentError, "path is required" if @scope[:path].blank? && path.blank? + Mapper.normalize_path("#{@scope[:path]}/#{path}") end def app @@ -94,7 +98,15 @@ module ActionDispatch end def defaults - @defaults ||= if to.respond_to?(:call) + @defaults ||= (@options[:defaults] || {}).tap do |defaults| + defaults.merge!(default_controller_and_action) + defaults.reverse_merge!(@scope[:defaults]) if @scope[:defaults] + @options.each { |k, v| defaults[k] = v unless v.is_a?(Regexp) || IGNORE_OPTIONS.include?(k.to_sym) } + end + end + + def default_controller_and_action + if to.respond_to?(:call) { } else defaults = case to @@ -144,8 +156,8 @@ module ActionDispatch def segment_keys @segment_keys ||= Rack::Mount::RegexpWithNamedGroups.new( - Rack::Mount::Strexp.compile(@path, requirements, SEPARATORS) - ).names + Rack::Mount::Strexp.compile(@path, requirements, SEPARATORS) + ).names end def to @@ -297,11 +309,14 @@ module ActionDispatch scope(:constraints => constraints) { yield } end + def defaults(defaults = {}) + scope(:defaults => defaults) { yield } + end + def match(*args) options = args.extract_options! options = (@scope[:options] || {}).merge(options) - options[:anchor] = true unless options.key?(:anchor) if @scope[:name_prefix] && !options[:as].blank? options[:as] = "#{@scope[:name_prefix]}_#{options[:as]}" @@ -342,6 +357,10 @@ module ActionDispatch merge_options_scope(parent, child) end + def merge_defaults_scope(parent, child) + merge_options_scope(parent, child) + end + def merge_blocks_scope(parent, child) (parent || []) + [child] end @@ -460,7 +479,7 @@ module ActionDispatch scope(:path => resource.name.to_s, :controller => resource.controller) do with_scope_level(:resource, resource) do - scope(:name_prefix => resource.name.to_s) do + scope(:name_prefix => resource.name.to_s, :as => "") do yield if block_given? end @@ -563,6 +582,8 @@ module ActionDispatch def match(*args) options = args.extract_options! + options[:anchor] = true unless options.key?(:anchor) + if args.length > 1 args.each { |path| match(path, options) } return self diff --git a/actionpack/lib/action_dispatch/routing/route_set.rb b/actionpack/lib/action_dispatch/routing/route_set.rb index 722be432c7..bb689beed9 100644 --- a/actionpack/lib/action_dispatch/routing/route_set.rb +++ b/actionpack/lib/action_dispatch/routing/route_set.rb @@ -65,7 +65,7 @@ module ActionDispatch # named routes. class NamedRouteCollection #:nodoc: include Enumerable - attr_reader :routes, :helpers + attr_reader :routes, :helpers, :module def initialize clear! @@ -179,6 +179,7 @@ module ActionDispatch url_for(options) end + protected :#{selector} END_EVAL helpers << selector end @@ -219,14 +220,16 @@ module ActionDispatch end def finalize! + return if @finalized + @finalized = true @set.add_route(NotFound) - install_helpers @set.freeze end def clear! # Clear the controller cache so we may discover new ones @controller_constraints = nil + @finalized = false routes.clear named_routes.clear @set = ::Rack::Mount::RouteSet.new(:parameters_key => PARAMETERS_KEY) @@ -239,21 +242,30 @@ module ActionDispatch def url_helpers @url_helpers ||= begin - router = self + routes = self - Module.new do + helpers = Module.new do extend ActiveSupport::Concern include UrlFor + @routes = routes + class << self + delegate :url_for, :to => '@routes' + end + extend routes.named_routes.module + # ROUTES TODO: install_helpers isn't great... can we make a module with the stuff that # we can include? # Yes plz - JP included do - router.install_helpers(self) + routes.install_helpers(self) + singleton_class.send(:define_method, :_router) { routes } end - define_method(:_router) { router } + define_method(:_router) { routes } end + + helpers end end @@ -406,6 +418,7 @@ module ActionDispatch RESERVED_OPTIONS = [:anchor, :params, :only_path, :host, :protocol, :port, :trailing_slash] def url_for(options) + finalize! options = default_url_options.merge(options || {}) handle_positional_args(options) @@ -437,6 +450,7 @@ module ActionDispatch end def call(env) + finalize! @set.call(env) end diff --git a/actionpack/lib/action_dispatch/routing/url_for.rb b/actionpack/lib/action_dispatch/routing/url_for.rb index ec78f53fa6..b8c02f402c 100644 --- a/actionpack/lib/action_dispatch/routing/url_for.rb +++ b/actionpack/lib/action_dispatch/routing/url_for.rb @@ -72,7 +72,7 @@ module ActionDispatch # you can do that by including ActionController::UrlFor in your class: # # class User < ActiveRecord::Base - # include ActionController::UrlFor + # include Rails.application.routes.url_helpers # # def base_uri # user_path(self) |