Skip to content

Commit

Permalink
Ensure shortcuts inside resources also generates helpers.
Browse files Browse the repository at this point in the history
  • Loading branch information
josevalim committed Aug 24, 2010
1 parent edba51c commit 4a90ecb
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 52 deletions.
87 changes: 39 additions & 48 deletions actionpack/lib/action_dispatch/routing/mapper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,9 @@ def constraint_args(constraint, request)
class Mapping #:nodoc:
IGNORE_OPTIONS = [:to, :as, :via, :on, :constraints, :defaults, :only, :except, :anchor, :shallow, :shallow_path, :shallow_prefix]

def initialize(set, scope, args)
@set, @scope = set, scope
@path, @options = extract_path_and_options(args)
def initialize(set, scope, path, options)
@set, @scope, @options = set, scope, options
@path = normalize_path(path)
normalize_options!
end

Expand All @@ -54,31 +54,16 @@ def to_route
end

private
def extract_path_and_options(args)
options = args.extract_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
else
path = args.first
end

if path.match(':controller')
raise ArgumentError, ":controller segment is not allowed within a namespace block" if @scope[:module]

# Add a default constraint for :controller path segments that matches namespaced
# controllers with default routes like :controller/:action/:id(.:format), e.g:
# GET /admin/products/show/1
# => { :controller => 'admin/products', :action => 'show', :id => '1' }
options.reverse_merge!(:controller => /.+?/)
end

[ normalize_path(path), options ]
end

def normalize_options!
path_without_format = @path.sub(/\(\.:format\)$/, '')
@options = (@scope[:options] || {}).merge(@options)

if @scope[:as] && !@options[:as].blank?
@options[:as] = "#{@scope[:as]}_#{@options[:as]}"
elsif @scope[:as] && @options[:as] == ""
@options[:as] = @scope[:as].to_s
end

if using_match_shorthand?(path_without_format, @options)
to_shorthand = @options[:to].blank?
Expand All @@ -89,19 +74,26 @@ def normalize_options!
@options.merge!(default_controller_and_action(to_shorthand))
end

# match "account" => "account#index"
def using_to_shorthand?(args, options)
args.empty? && options.present?
end

# match "account/overview"
def using_match_shorthand?(path, options)
path && options.except(:via, :anchor, :to, :as).empty? && path =~ %r{^/[\w\/]+$}
end

def normalize_path(path)
raise ArgumentError, "path is required" if @scope[:path].blank? && path.blank?
Mapper.normalize_path("#{@scope[:path]}/#{path}")
path = Mapper.normalize_path("#{@scope[:path]}/#{path}")

if path.match(':controller')
raise ArgumentError, ":controller segment is not allowed within a namespace block" if @scope[:module]

# Add a default constraint for :controller path segments that matches namespaced
# controllers with default routes like :controller/:action/:id(.:format), e.g:
# GET /admin/products/show/1
# => { :controller => 'admin/products', :action => 'show', :id => '1' }
@options.reverse_merge!(:controller => /.+?/)
end

path
end

def app
Expand Down Expand Up @@ -233,8 +225,8 @@ def root(options = {})
match '/', options.reverse_merge(:as => :root)
end

def match(*args)
mapping = Mapping.new(@set, @scope, args).to_route
def match(path, options=nil)
mapping = Mapping.new(@set, @scope, path, options || {}).to_route
@set.add_route(*mapping)
self
end
Expand Down Expand Up @@ -389,21 +381,6 @@ def defaults(defaults = {})
scope(:defaults => defaults) { yield }
end

def match(*args)
options = args.extract_options!

options = (@scope[:options] || {}).merge(options)

if @scope[:as] && !options[:as].blank?
options[:as] = "#{@scope[:as]}_#{options[:as]}"
elsif @scope[:as] && options[:as] == ""
options[:as] = @scope[:as].to_s
end

args.push(options)
super(*args)
end

private
def scope_options
@scope_options ||= private_methods.grep(/^merge_(.+)_scope$/) { $1.to_sym }
Expand Down Expand Up @@ -957,10 +934,24 @@ def name_for_action(action, as=nil)
end
end

module Shorthand
def match(*args)
if args.size == 1 && args.last.is_a?(Hash)
options = args.pop
path, to = options.find { |name, value| name.is_a?(String) }
options.merge!(:to => to).delete(path)
super(path, options)
else
super
end
end
end

include Base
include HttpHelpers
include Scoping
include Resources
include Shorthand
end
end
end
8 changes: 4 additions & 4 deletions actionpack/test/dispatch/routing_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -203,9 +203,9 @@ def self.matches?(request)
end

resources :customers do
get "recent" => "customers#recent", :as => :recent, :on => :collection
get "profile" => "customers#profile", :as => :profile, :on => :member
post "preview" => "customers#preview", :as => :preview, :on => :new
get "recent" => "customers#recent", :on => :collection
get "profile" => "customers#profile", :on => :member
post "preview" => "customers#preview", :as => :another_preview, :on => :new
resource :avatar do
get "thumbnail(.:format)" => "avatars#thumbnail", :as => :thumbnail, :on => :member
end
Expand Down Expand Up @@ -1564,7 +1564,7 @@ def test_custom_resource_routes_are_scoped
with_test_routes do
assert_equal '/customers/recent', recent_customers_path
assert_equal '/customers/1/profile', profile_customer_path(:id => '1')
assert_equal '/customers/new/preview', preview_new_customer_path
assert_equal '/customers/new/preview', another_preview_new_customer_path
assert_equal '/customers/1/avatar/thumbnail.jpg', thumbnail_customer_avatar_path(:customer_id => '1', :format => :jpg)
assert_equal '/customers/1/invoices/outstanding', outstanding_customer_invoices_path(:customer_id => '1')
assert_equal '/customers/1/invoices/2/print', print_customer_invoice_path(:customer_id => '1', :id => '2')
Expand Down

0 comments on commit 4a90ecb

Please sign in to comment.