From 44a3009ff068bf080de6764a8c884fbf0ceb920e Mon Sep 17 00:00:00 2001 From: Tom Stuart Date: Wed, 12 Nov 2008 11:00:17 +0000 Subject: Add :only/:except options to map.resources This allows people with huge numbers of resource routes to cut down on the memory consumption caused by the generated code. Signed-off-by: Michael Koziarski [#1215 state:committed] --- actionpack/lib/action_controller/resources.rb | 122 ++++++++++++++++++-------- 1 file changed, 85 insertions(+), 37 deletions(-) (limited to 'actionpack/lib/action_controller/resources.rb') diff --git a/actionpack/lib/action_controller/resources.rb b/actionpack/lib/action_controller/resources.rb index 872b0dab3d..de529e23ff 100644 --- a/actionpack/lib/action_controller/resources.rb +++ b/actionpack/lib/action_controller/resources.rb @@ -42,7 +42,11 @@ module ActionController # # Read more about REST at http://en.wikipedia.org/wiki/Representational_State_Transfer module Resources + INHERITABLE_OPTIONS = :namespace, :shallow, :only, :except + class Resource #:nodoc: + DEFAULT_ACTIONS = :index, :create, :new, :edit, :show, :update, :destroy + attr_reader :collection_methods, :member_methods, :new_methods attr_reader :path_prefix, :name_prefix, :path_segment attr_reader :plural, :singular @@ -57,6 +61,7 @@ module ActionController arrange_actions add_default_actions + set_allowed_actions set_prefixes end @@ -113,6 +118,10 @@ module ActionController @singular.to_s == @plural.to_s end + def has_action?(action) + !DEFAULT_ACTIONS.include?(action) || action_allowed?(action) + end + protected def arrange_actions @collection_methods = arrange_actions_by_methods(options.delete(:collection)) @@ -125,6 +134,30 @@ module ActionController add_default_action(new_methods, :get, :new) end + def set_allowed_actions + only, except = @options.values_at(:only, :except) + @allowed_actions ||= {} + + if only == :all || except == :none + only = nil + except = [] + elsif only == :none || except == :all + only = [] + except = nil + end + + if only + @allowed_actions[:only] = Array(only).map(&:to_sym) + elsif except + @allowed_actions[:except] = Array(except).map(&:to_sym) + end + end + + def action_allowed?(action) + only, except = @allowed_actions.values_at(:only, :except) + (!only || only.include?(action)) && (!except || !except.include?(action)) + end + def set_prefixes @path_prefix = options.delete(:path_prefix) @name_prefix = options.delete(:name_prefix) @@ -353,6 +386,25 @@ module ActionController # # map.resources :users, :has_many => { :posts => :comments }, :shallow => true # + # * :only and :except - Specify which of the seven default actions should be routed to. + # + # :only and :except may be set to :all, :none, an action name or a + # list of action names. By default, routes are generated for all seven actions. + # + # For example: + # + # map.resources :posts, :only => [:index, :show] do |post| + # post.resources :comments, :except => [:update, :destroy] + # end + # # --> GET /posts (maps to the PostsController#index action) + # # --> POST /posts (fails) + # # --> GET /posts/1 (maps to the PostsController#show action) + # # --> DELETE /posts/1 (fails) + # # --> POST /posts/1/comments (maps to the CommentsController#create action) + # # --> PUT /posts/1/comments/1 (fails) + # + # The :only and :except options are inherited by any nested resource(s). + # # If map.resources is called with multiple resources, they all get the same options applied. # # Examples: @@ -478,7 +530,7 @@ module ActionController map_associations(resource, options) if block_given? - with_options(:path_prefix => resource.nesting_path_prefix, :name_prefix => resource.nesting_name_prefix, :namespace => options[:namespace], :shallow => options[:shallow], &block) + with_options(options.slice(*INHERITABLE_OPTIONS).merge(:path_prefix => resource.nesting_path_prefix, :name_prefix => resource.nesting_name_prefix), &block) end end end @@ -495,7 +547,7 @@ module ActionController map_associations(resource, options) if block_given? - with_options(:path_prefix => resource.nesting_path_prefix, :name_prefix => resource.nesting_name_prefix, :namespace => options[:namespace], :shallow => options[:shallow], &block) + with_options(options.slice(*INHERITABLE_OPTIONS).merge(:path_prefix => resource.nesting_path_prefix, :name_prefix => resource.nesting_name_prefix), &block) end end end @@ -507,7 +559,7 @@ module ActionController name_prefix = "#{options.delete(:name_prefix)}#{resource.nesting_name_prefix}" Array(options[:has_one]).each do |association| - resource(association, :path_prefix => path_prefix, :name_prefix => name_prefix, :namespace => options[:namespace], :shallow => options[:shallow]) + resource(association, options.slice(*INHERITABLE_OPTIONS).merge(:path_prefix => path_prefix, :name_prefix => name_prefix)) end end @@ -522,7 +574,7 @@ module ActionController map_has_many_associations(resource, association, options) end when Symbol, String - resources(associations, :path_prefix => resource.nesting_path_prefix, :name_prefix => resource.nesting_name_prefix, :namespace => options[:namespace], :shallow => options[:shallow], :has_many => options[:has_many]) + resources(associations, options.slice(*INHERITABLE_OPTIONS).merge(:path_prefix => resource.nesting_path_prefix, :name_prefix => resource.nesting_name_prefix, :has_many => options[:has_many])) else end end @@ -531,41 +583,39 @@ module ActionController resource.collection_methods.each do |method, actions| actions.each do |action| [method].flatten.each do |m| - action_options = action_options_for(action, resource, m) - map_named_routes(map, "#{action}_#{resource.name_prefix}#{resource.plural}", "#{resource.path}#{resource.action_separator}#{action}", action_options) + map_resource_routes(map, resource, action, "#{resource.path}#{resource.action_separator}#{action}", "#{action}_#{resource.name_prefix}#{resource.plural}", m) end end end end def map_default_collection_actions(map, resource) - index_action_options = action_options_for("index", resource) index_route_name = "#{resource.name_prefix}#{resource.plural}" if resource.uncountable? index_route_name << "_index" end - map_named_routes(map, index_route_name, resource.path, index_action_options) - - create_action_options = action_options_for("create", resource) - map_unnamed_routes(map, resource.path, create_action_options) + map_resource_routes(map, resource, :index, resource.path, index_route_name) + map_resource_routes(map, resource, :create, resource.path) end def map_default_singleton_actions(map, resource) - create_action_options = action_options_for("create", resource) - map_unnamed_routes(map, resource.path, create_action_options) + map_resource_routes(map, resource, :create, resource.path) end def map_new_actions(map, resource) resource.new_methods.each do |method, actions| actions.each do |action| - action_options = action_options_for(action, resource, method) - if action == :new - map_named_routes(map, "new_#{resource.name_prefix}#{resource.singular}", resource.new_path, action_options) - else - map_named_routes(map, "#{action}_new_#{resource.name_prefix}#{resource.singular}", "#{resource.new_path}#{resource.action_separator}#{action}", action_options) + route_path = resource.new_path + route_name = "new_#{resource.name_prefix}#{resource.singular}" + + unless action == :new + route_path = "#{route_path}#{resource.action_separator}#{action}" + route_name = "#{action}_#{route_name}" end + + map_resource_routes(map, resource, action, route_path, route_name, method) end end end @@ -574,34 +624,32 @@ module ActionController resource.member_methods.each do |method, actions| actions.each do |action| [method].flatten.each do |m| - action_options = action_options_for(action, resource, m) - action_path = resource.options[:path_names][action] if resource.options[:path_names].is_a?(Hash) action_path ||= Base.resources_path_names[action] || action - map_named_routes(map, "#{action}_#{resource.shallow_name_prefix}#{resource.singular}", "#{resource.member_path}#{resource.action_separator}#{action_path}", action_options) + map_resource_routes(map, resource, action, "#{resource.member_path}#{resource.action_separator}#{action_path}", "#{action}_#{resource.shallow_name_prefix}#{resource.singular}", m) end end end - show_action_options = action_options_for("show", resource) - map_named_routes(map, "#{resource.shallow_name_prefix}#{resource.singular}", resource.member_path, show_action_options) - - update_action_options = action_options_for("update", resource) - map_unnamed_routes(map, resource.member_path, update_action_options) - - destroy_action_options = action_options_for("destroy", resource) - map_unnamed_routes(map, resource.member_path, destroy_action_options) + map_resource_routes(map, resource, :show, resource.member_path, "#{resource.shallow_name_prefix}#{resource.singular}") + map_resource_routes(map, resource, :update, resource.member_path) + map_resource_routes(map, resource, :destroy, resource.member_path) end - def map_unnamed_routes(map, path_without_format, options) - map.connect(path_without_format, options) - map.connect("#{path_without_format}.:format", options) - end - - def map_named_routes(map, name, path_without_format, options) - map.named_route(name, path_without_format, options) - map.named_route("formatted_#{name}", "#{path_without_format}.:format", options) + def map_resource_routes(map, resource, action, route_path, route_name = nil, method = nil) + if resource.has_action?(action) + action_options = action_options_for(action, resource, method) + formatted_route_path = "#{route_path}.:format" + + if route_name + map.named_route(route_name, route_path, action_options) + map.named_route("formatted_#{route_name}", formatted_route_path, action_options) + else + map.connect(route_path, action_options) + map.connect(formatted_route_path, action_options) + end + end end def add_conditions_for(conditions, method) -- cgit v1.2.3 From 4c0921024471c0463d67f8b8fb6a115a94d343aa Mon Sep 17 00:00:00 2001 From: Tom Stuart Date: Thu, 13 Nov 2008 14:31:36 +0000 Subject: Fix map.resources to always generate named routes if they're needed Signed-off-by: Michael Koziarski --- actionpack/lib/action_controller/resources.rb | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'actionpack/lib/action_controller/resources.rb') diff --git a/actionpack/lib/action_controller/resources.rb b/actionpack/lib/action_controller/resources.rb index de529e23ff..d6cc4aa418 100644 --- a/actionpack/lib/action_controller/resources.rb +++ b/actionpack/lib/action_controller/resources.rb @@ -597,11 +597,11 @@ module ActionController end map_resource_routes(map, resource, :index, resource.path, index_route_name) - map_resource_routes(map, resource, :create, resource.path) + map_resource_routes(map, resource, :create, resource.path, index_route_name) end def map_default_singleton_actions(map, resource) - map_resource_routes(map, resource, :create, resource.path) + map_resource_routes(map, resource, :create, resource.path, "#{resource.shallow_name_prefix}#{resource.singular}") end def map_new_actions(map, resource) @@ -632,9 +632,10 @@ module ActionController end end - map_resource_routes(map, resource, :show, resource.member_path, "#{resource.shallow_name_prefix}#{resource.singular}") - map_resource_routes(map, resource, :update, resource.member_path) - map_resource_routes(map, resource, :destroy, resource.member_path) + route_path = "#{resource.shallow_name_prefix}#{resource.singular}" + map_resource_routes(map, resource, :show, resource.member_path, route_path) + map_resource_routes(map, resource, :update, resource.member_path, route_path) + map_resource_routes(map, resource, :destroy, resource.member_path, route_path) end def map_resource_routes(map, resource, action, route_path, route_name = nil, method = nil) @@ -642,7 +643,7 @@ module ActionController action_options = action_options_for(action, resource, method) formatted_route_path = "#{route_path}.:format" - if route_name + if route_name && @set.named_routes[route_name.to_sym].nil? map.named_route(route_name, route_path, action_options) map.named_route("formatted_#{route_name}", formatted_route_path, action_options) else -- cgit v1.2.3 From 2ecec6052f7f290252a9fd9cc27ec804c7aad36c Mon Sep 17 00:00:00 2001 From: Tom Stuart Date: Thu, 13 Nov 2008 20:00:11 +0000 Subject: Make inheritance of map.resources :only/:except options behave more predictably Signed-off-by: Michael Koziarski --- actionpack/lib/action_controller/resources.rb | 33 ++++++++++++--------------- 1 file changed, 14 insertions(+), 19 deletions(-) (limited to 'actionpack/lib/action_controller/resources.rb') diff --git a/actionpack/lib/action_controller/resources.rb b/actionpack/lib/action_controller/resources.rb index d6cc4aa418..7700b9d4d0 100644 --- a/actionpack/lib/action_controller/resources.rb +++ b/actionpack/lib/action_controller/resources.rb @@ -42,7 +42,7 @@ module ActionController # # Read more about REST at http://en.wikipedia.org/wiki/Representational_State_Transfer module Resources - INHERITABLE_OPTIONS = :namespace, :shallow, :only, :except + INHERITABLE_OPTIONS = :namespace, :shallow, :actions class Resource #:nodoc: DEFAULT_ACTIONS = :index, :create, :new, :edit, :show, :update, :destroy @@ -119,7 +119,7 @@ module ActionController end def has_action?(action) - !DEFAULT_ACTIONS.include?(action) || action_allowed?(action) + !DEFAULT_ACTIONS.include?(action) || @options[:actions].nil? || @options[:actions].include?(action) end protected @@ -135,29 +135,24 @@ module ActionController end def set_allowed_actions - only, except = @options.values_at(:only, :except) - @allowed_actions ||= {} + only = @options.delete(:only) + except = @options.delete(:except) - if only == :all || except == :none - only = nil - except = [] + if only && except + raise ArgumentError, 'Please supply either :only or :except, not both.' + elsif only == :all || except == :none + options[:actions] = DEFAULT_ACTIONS elsif only == :none || except == :all - only = [] - except = nil - end - - if only - @allowed_actions[:only] = Array(only).map(&:to_sym) + options[:actions] = [] + elsif only + options[:actions] = DEFAULT_ACTIONS & Array(only).map(&:to_sym) elsif except - @allowed_actions[:except] = Array(except).map(&:to_sym) + options[:actions] = DEFAULT_ACTIONS - Array(except).map(&:to_sym) + else + # leave options[:actions] alone end end - def action_allowed?(action) - only, except = @allowed_actions.values_at(:only, :except) - (!only || only.include?(action)) && (!except || !except.include?(action)) - end - def set_prefixes @path_prefix = options.delete(:path_prefix) @name_prefix = options.delete(:name_prefix) -- cgit v1.2.3 From 31ce92f7b5784bc5b6a441e88cd734c7b8b1c58f Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Sun, 23 Nov 2008 16:35:13 -0600 Subject: Use autoload instead of explicit requires for ActionController --- actionpack/lib/action_controller/resources.rb | 4 ---- 1 file changed, 4 deletions(-) (limited to 'actionpack/lib/action_controller/resources.rb') diff --git a/actionpack/lib/action_controller/resources.rb b/actionpack/lib/action_controller/resources.rb index 7700b9d4d0..b5ea764911 100644 --- a/actionpack/lib/action_controller/resources.rb +++ b/actionpack/lib/action_controller/resources.rb @@ -669,7 +669,3 @@ module ActionController end end end - -class ActionController::Routing::RouteSet::Mapper - include ActionController::Resources -end -- cgit v1.2.3 From eac16d0ee1f9a46e686503196e3920e2113ccc0a Mon Sep 17 00:00:00 2001 From: Geoff Garside Date: Tue, 18 Nov 2008 15:14:55 +0000 Subject: Reorder the way in which map.resource routes are added to the set. This prevents the singular named route from hitting :create instead of :show. Signed-off-by: Michael Koziarski --- actionpack/lib/action_controller/resources.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'actionpack/lib/action_controller/resources.rb') diff --git a/actionpack/lib/action_controller/resources.rb b/actionpack/lib/action_controller/resources.rb index b5ea764911..c170528af1 100644 --- a/actionpack/lib/action_controller/resources.rb +++ b/actionpack/lib/action_controller/resources.rb @@ -535,9 +535,9 @@ module ActionController with_options :controller => resource.controller do |map| map_collection_actions(map, resource) - map_default_singleton_actions(map, resource) map_new_actions(map, resource) map_member_actions(map, resource) + map_default_singleton_actions(map, resource) map_associations(resource, options) -- cgit v1.2.3 From fef6c32afe2276dffa0347e25808a86e7a101af1 Mon Sep 17 00:00:00 2001 From: Aaron Batalion Date: Mon, 24 Nov 2008 02:24:19 -0500 Subject: Added optimal formatted routes to rails, deprecating the formatted_* methods, and reducing routes creation by 50% [#1359 state:committed] Signed-off-by: David Heinemeier Hansson --- actionpack/lib/action_controller/resources.rb | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'actionpack/lib/action_controller/resources.rb') diff --git a/actionpack/lib/action_controller/resources.rb b/actionpack/lib/action_controller/resources.rb index c170528af1..b6cfe2dd68 100644 --- a/actionpack/lib/action_controller/resources.rb +++ b/actionpack/lib/action_controller/resources.rb @@ -639,10 +639,8 @@ module ActionController formatted_route_path = "#{route_path}.:format" if route_name && @set.named_routes[route_name.to_sym].nil? - map.named_route(route_name, route_path, action_options) - map.named_route("formatted_#{route_name}", formatted_route_path, action_options) + map.named_route(route_name, formatted_route_path, action_options) else - map.connect(route_path, action_options) map.connect(formatted_route_path, action_options) end end -- cgit v1.2.3