diff options
Diffstat (limited to 'actionpack/lib/action_dispatch')
4 files changed, 104 insertions, 35 deletions
diff --git a/actionpack/lib/action_dispatch/middleware/show_exceptions.rb b/actionpack/lib/action_dispatch/middleware/show_exceptions.rb index f9e81a02d3..8a2d8cd077 100644 --- a/actionpack/lib/action_dispatch/middleware/show_exceptions.rb +++ b/actionpack/lib/action_dispatch/middleware/show_exceptions.rb @@ -6,7 +6,7 @@ module ActionDispatch # This middleware rescues any exception returned by the application and renders # nice exception pages if it's being rescued locally. class ShowExceptions - LOCALHOST = ['127.0.0.1', '::1'].freeze + LOCALHOST = [/^127\.0\.0\.\d{1,3}$/, "::1", /^0:0:0:0:0:0:0:1(%.*)?$/].freeze RESCUES_TEMPLATE_PATH = File.join(File.dirname(__FILE__), 'templates') @@ -114,7 +114,7 @@ module ActionDispatch # True if the request came from localhost, 127.0.0.1. def local_request?(request) - LOCALHOST.any?{ |local_ip| request.remote_addr == local_ip && request.remote_ip == local_ip } + LOCALHOST.any? { |local_ip| local_ip === request.remote_addr && local_ip === request.remote_ip } end def status_code(exception) diff --git a/actionpack/lib/action_dispatch/routing/mapper.rb b/actionpack/lib/action_dispatch/routing/mapper.rb index ae4417b56c..e91a72cbe5 100644 --- a/actionpack/lib/action_dispatch/routing/mapper.rb +++ b/actionpack/lib/action_dispatch/routing/mapper.rb @@ -350,6 +350,10 @@ module ActionDispatch scope(:constraints => constraints) { yield } end + def shallow + scope(:shallow => true) { yield } + end + def defaults(defaults = {}) scope(:defaults => defaults) { yield } end @@ -374,12 +378,21 @@ module ActionDispatch @scope_options ||= private_methods.grep(/^merge_(.+)_scope$/) { $1.to_sym } end + def merge_shallow_scope(parent, child) + parent or child + end + def merge_path_scope(parent, child) - Mapper.normalize_path("#{parent}/#{child}") + parent_path = (@scope[:shallow] and child.eql?(':id')) ? parent.split('/').last : parent + Mapper.normalize_path "#{parent_path}/#{child}" end def merge_name_prefix_scope(parent, child) - parent ? "#{parent}_#{child}" : child + if @scope[:shallow] + child + else + parent ? "#{parent}_#{child}" : child + end end def merge_module_scope(parent, child) @@ -463,6 +476,10 @@ module ActionDispatch name.to_s.singularize end + def member_prefix + ':id' + end + def member_name singular end @@ -509,11 +526,19 @@ module ActionDispatch end end + def nested_prefix + id_segment + end + def nested_options options = { :name_prefix => member_name } options["#{singular}_id".to_sym] = id_constraint if id_constraint? options end + + def shallow? + options[:shallow] + end end class SingletonResource < Resource #:nodoc: @@ -532,9 +557,21 @@ module ActionDispatch end end + def member_prefix + '' + end + def member_name name end + + def nested_prefix + '' + end + + def nested_options + { :name_prefix => member_name } + end end def initialize(*args) #:nodoc: @@ -544,6 +581,7 @@ module ActionDispatch def resource(*resources, &block) options = resources.extract_options! + options = (@scope[:options] || {}).merge(options) if apply_common_behavior_for(:resource, resources, options, &block) return self @@ -554,17 +592,17 @@ module ActionDispatch scope(:path => resource.path, :controller => resource.controller) do with_scope_level(:resource, resource) do - scope(:name_prefix => resource.name.to_s, :as => "") do - yield if block_given? - end + yield if block_given? - scope(resource.options) do - get :show if resource.actions.include?(:show) - post :create if resource.actions.include?(:create) - put :update if resource.actions.include?(:update) - delete :destroy if resource.actions.include?(:destroy) - get :new, :as => resource.name if resource.actions.include?(:new) - get :edit, :as => resource.name if resource.actions.include?(:edit) + with_scope_level(:member) do + scope(resource.options) do + get :show if resource.actions.include?(:show) + post :create if resource.actions.include?(:create) + put :update if resource.actions.include?(:update) + delete :destroy if resource.actions.include?(:destroy) + get :new, :as => resource.name if resource.actions.include?(:new) + get :edit, :as => resource.name if resource.actions.include?(:edit) + end end end end @@ -574,6 +612,7 @@ module ActionDispatch def resources(*resources, &block) options = resources.extract_options! + options = (@scope[:options] || {}).merge(options) if apply_common_behavior_for(:resources, resources, options, &block) return self @@ -581,8 +620,12 @@ module ActionDispatch resource = Resource.new(resources.pop, options) - scope(:path => resource.path, :controller => resource.controller) do + scope(:path => resource.path, :controller => resource.controller, :shallow => resource.shallow?) do with_scope_level(:resources, resource) do + if @scope[:shallow] && @scope[:name_prefix] + @scope[:path] = "/#{@scope[:name_prefix].pluralize}/:#{@scope[:name_prefix]}_id/#{resource.path}" + end + yield if block_given? with_scope_level(:collection) do @@ -596,6 +639,8 @@ module ActionDispatch with_scope_level(:member) do scope(':id') do scope(resource.options) do + @scope[:name_prefix] = nil if @scope[:shallow] + get :show if resource.actions.include?(:show) put :update if resource.actions.include?(:update) delete :destroy if resource.actions.include?(:destroy) @@ -622,31 +667,36 @@ module ActionDispatch end def member - unless [:resources, :resource].include?(@scope[:scope_level]) - raise ArgumentError, "You can't use member action outside resources and resource scope." + unless resource_scope? + raise ArgumentError, "can't use member outside resource(s) scope" end - case @scope[:scope_level] - when :resources - with_scope_level(:member) do - scope(':id', :name_prefix => parent_resource.member_name, :as => "") do - yield - end + with_scope_level(:member) do + scope(parent_resource.member_prefix, :name_prefix => parent_resource.member_name, :as => "") do + yield end - when :resource - with_scope_level(:member) do + end + end + + def new + unless resource_scope? + raise ArgumentError, "can't use new outside resource(s) scope" + end + + with_scope_level(:new) do + scope(new_scope_prefix, :name_prefix => parent_resource.member_name, :as => "") do yield end end end def nested - unless @scope[:scope_level] == :resources - raise ArgumentError, "can't use nested outside resources scope" + unless resource_scope? + raise ArgumentError, "can't use nested outside resource(s) scope" end with_scope_level(:nested) do - scope(parent_resource.id_segment, parent_resource.nested_options) do + scope(parent_resource.nested_prefix, parent_resource.nested_options) do yield end end @@ -678,7 +728,7 @@ module ActionDispatch @scope[:path] = old_path end else - with_exclusive_name_prefix(action) do + with_exclusive_name_prefix(action_name_prefix(action, options)) do return match("#{action_path(action, path_names)}(.:format)", options.reverse_merge(:to => action)) end end @@ -691,10 +741,16 @@ module ActionDispatch return collection { match(*args) } when :member return member { match(*args) } + when :new + return new { match(*args) } + end + + if @scope[:scope_level] == :resource + return member { match(*args) } end - if @scope[:scope_level] == :resources - raise ArgumentError, "can't define route directly in resources scope" + if resource_scope? + raise ArgumentError, "can't define route directly in resource(s) scope" end super @@ -716,6 +772,10 @@ module ActionDispatch path_names[name.to_sym] || name.to_s end + def action_name_prefix(action, options = {}) + (options[:on] == :new || @scope[:scope_level] == :new) ? "#{action}_new" : action + end + def apply_common_behavior_for(method, resources, options, &block) if resources.length > 1 resources.each { |r| send(method, r, options, &block) } @@ -729,7 +789,7 @@ module ActionDispatch return true end - if @scope[:scope_level] == :resources + if resource_scope? nested do send(method, resources.pop, options, &block) end @@ -739,6 +799,14 @@ module ActionDispatch false end + def new_scope_prefix + @scope[:path_names][:new] || 'new' + end + + def resource_scope? + [:resource, :resources].include?(@scope[:scope_level]) + end + def with_exclusive_name_prefix(prefix) begin old_name_prefix = @scope[:name_prefix] diff --git a/actionpack/lib/action_dispatch/routing/route_set.rb b/actionpack/lib/action_dispatch/routing/route_set.rb index 750912b251..57a73dde75 100644 --- a/actionpack/lib/action_dispatch/routing/route_set.rb +++ b/actionpack/lib/action_dispatch/routing/route_set.rb @@ -68,6 +68,10 @@ module ActionDispatch clear! end + def helper_names + self.module.instance_methods.map(&:to_s) + end + def clear! @routes = {} @helpers = [] @@ -176,7 +180,6 @@ module ActionDispatch url_for(options) end - protected :#{selector} END_EVAL helpers << selector end diff --git a/actionpack/lib/action_dispatch/testing/assertions/selector.rb b/actionpack/lib/action_dispatch/testing/assertions/selector.rb index 9deabf5b3c..0e82b41590 100644 --- a/actionpack/lib/action_dispatch/testing/assertions/selector.rb +++ b/actionpack/lib/action_dispatch/testing/assertions/selector.rb @@ -267,14 +267,12 @@ module ActionDispatch if match_with = equals[:text] matches.delete_if do |match| text = "" - text.force_encoding(match_with.encoding) if text.respond_to?(:force_encoding) stack = match.children.reverse while node = stack.pop if node.tag? stack.concat node.children.reverse else content = node.content - content.force_encoding(match_with.encoding) if content.respond_to?(:force_encoding) text << content end end |