From 53b34e84762b7f2d6b641f99dadbb1eab42907ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Thu, 1 Jul 2010 17:07:48 +0200 Subject: Avoid calls to Rails::Application since this is not the official API. Your application should *always* reference your application const (as Blog::Application) and Rails.application should be used just internally. --- actionpack/lib/action_dispatch/routing.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_dispatch/routing.rb b/actionpack/lib/action_dispatch/routing.rb index 401d98b663..89007fab74 100644 --- a/actionpack/lib/action_dispatch/routing.rb +++ b/actionpack/lib/action_dispatch/routing.rb @@ -167,7 +167,7 @@ module ActionDispatch # # You can reload routes if you feel you must: # - # Rails::Application.reload_routes! + # Rails.application.reload_routes! # # This will clear all named routes and reload routes.rb if the file has been modified from # last load. To absolutely force reloading, use reload!. -- cgit v1.2.3 From a6913bf7eb614d9e5008cf4230104babfec7c6c4 Mon Sep 17 00:00:00 2001 From: Rizwan Reza Date: Thu, 1 Jul 2010 23:07:24 +0430 Subject: Added documentation for usage of associative resources with form_for --- actionpack/lib/action_view/helpers/form_helper.rb | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_view/helpers/form_helper.rb b/actionpack/lib/action_view/helpers/form_helper.rb index d1b10a9281..6302491c2a 100644 --- a/actionpack/lib/action_view/helpers/form_helper.rb +++ b/actionpack/lib/action_view/helpers/form_helper.rb @@ -213,12 +213,22 @@ module ActionView # ... # <% end %> # - # And for namespaced routes, like +admin_post_url+: + # For namespaced routes, like +admin_post_url+: # # <%= form_for([:admin, @post]) do |f| %> # ... # <% end %> # + # If your resource has associations defined, for example, you want to add comments + # to the post given that the routes are set correctly: + # + # <%= form_for([@document, @comment]) do |f| %> + # ... + # <% end %> + # + # Where +@document = Document.find(params[:id])+ and + # +@comment = Comment.new+. + # # === Unobtrusive JavaScript # # Specifying: -- cgit v1.2.3 From f8720a04d129668c7554c1a7270fba5418510b47 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Thu, 1 Jul 2010 15:04:33 -0700 Subject: porting session.clear fix to master branch. [#5030 state:resolved] Signed-off-by: Jeremy Kemper --- .../middleware/session/abstract_store.rb | 5 +++++ .../test/dispatch/session/cookie_store_test.rb | 22 ++++++++++++++++++++++ 2 files changed, 27 insertions(+) (limited to 'actionpack') diff --git a/actionpack/lib/action_dispatch/middleware/session/abstract_store.rb b/actionpack/lib/action_dispatch/middleware/session/abstract_store.rb index 08bc80dbc2..64f4d1d532 100644 --- a/actionpack/lib/action_dispatch/middleware/session/abstract_store.rb +++ b/actionpack/lib/action_dispatch/middleware/session/abstract_store.rb @@ -64,6 +64,11 @@ module ActionDispatch super(key.to_s, value) end + def clear + load_for_write! + super + end + def to_hash load_for_read! h = {}.replace(self) diff --git a/actionpack/test/dispatch/session/cookie_store_test.rb b/actionpack/test/dispatch/session/cookie_store_test.rb index fd63f5ad5e..f0e01bfff0 100644 --- a/actionpack/test/dispatch/session/cookie_store_test.rb +++ b/actionpack/test/dispatch/session/cookie_store_test.rb @@ -30,6 +30,11 @@ class CookieStoreTest < ActionController::IntegrationTest render :text => "id: #{request.session_options[:id]}" end + def call_session_clear + session.clear + head :ok + end + def call_reset_session reset_session head :ok @@ -175,6 +180,23 @@ class CookieStoreTest < ActionController::IntegrationTest end end + def test_setting_session_value_after_session_clear + with_test_route_set do + get '/set_session_value' + assert_response :success + session_payload = response.body + assert_equal "_myapp_session=#{response.body}; path=/; HttpOnly", + headers['Set-Cookie'] + + get '/call_session_clear' + assert_response :success + + get '/get_session_value' + assert_response :success + assert_equal 'foo: nil', response.body + end + end + def test_persistent_session_id with_test_route_set do cookies[SessionKey] = SignedBar -- cgit v1.2.3 From f7ba614c2db31933cbc12eda87518de3eca0228c Mon Sep 17 00:00:00 2001 From: Piotr Sarnacki Date: Fri, 2 Jul 2010 00:29:20 +0200 Subject: Unify routes naming by renaming router to routes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: José Valim --- actionpack/lib/abstract_controller/rendering.rb | 4 ++-- actionpack/lib/action_controller/deprecated/base.rb | 2 +- actionpack/lib/action_controller/metal.rb | 2 +- actionpack/lib/action_controller/metal/url_for.rb | 8 ++++---- .../lib/action_dispatch/routing/deprecated_mapper.rb | 4 ++-- actionpack/lib/action_dispatch/routing/mapper.rb | 2 +- actionpack/lib/action_dispatch/routing/route_set.rb | 6 +++--- actionpack/lib/action_dispatch/routing/url_for.rb | 2 +- actionpack/lib/action_view/base.rb | 2 +- actionpack/lib/action_view/helpers/url_helper.rb | 2 +- actionpack/lib/action_view/test_case.rb | 10 +++++----- actionpack/test/abstract_unit.rb | 8 ++++---- actionpack/test/controller/url_for_test.rb | 2 +- actionpack/test/dispatch/url_generation_test.rb | 16 ++++++++-------- 14 files changed, 35 insertions(+), 35 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/abstract_controller/rendering.rb b/actionpack/lib/abstract_controller/rendering.rb index 6e3998aa21..b81d5954eb 100644 --- a/actionpack/lib/abstract_controller/rendering.rb +++ b/actionpack/lib/abstract_controller/rendering.rb @@ -50,8 +50,8 @@ module AbstractController if controller.respond_to?(:_helpers) include controller._helpers - if controller.respond_to?(:_router) - include controller._router.url_helpers + if controller.respond_to?(:_routes) + include controller._routes.url_helpers end # TODO: Fix RJS to not require this diff --git a/actionpack/lib/action_controller/deprecated/base.rb b/actionpack/lib/action_controller/deprecated/base.rb index 3975afcaf0..16b67b8ee7 100644 --- a/actionpack/lib/action_controller/deprecated/base.rb +++ b/actionpack/lib/action_controller/deprecated/base.rb @@ -96,7 +96,7 @@ module ActionController def resource_action_separator=(val) ActiveSupport::Deprecation.warn "ActionController::Base.resource_action_separator is deprecated and only " \ - "works with the deprecated router DSL." + "works with the deprecated routes DSL." @resource_action_separator = val end diff --git a/actionpack/lib/action_controller/metal.rb b/actionpack/lib/action_controller/metal.rb index 2281c500c5..8166d31719 100644 --- a/actionpack/lib/action_controller/metal.rb +++ b/actionpack/lib/action_controller/metal.rb @@ -47,7 +47,7 @@ module ActionController # # In AbstractController, dispatching is triggered directly by calling #process on a new controller. # ActionController::Metal provides an #action method that returns a valid Rack application for a - # given action. Other rack builders, such as Rack::Builder, Rack::URLMap, and the Rails router, + # given action. Other rack builders, such as Rack::Builder, Rack::URLMap, and the Rails routes, # can dispatch directly to the action returned by FooController.action(:index). class Metal < AbstractController::Base abstract! diff --git a/actionpack/lib/action_controller/metal/url_for.rb b/actionpack/lib/action_controller/metal/url_for.rb index c465035ca1..0c1e2fbe80 100644 --- a/actionpack/lib/action_controller/metal/url_for.rb +++ b/actionpack/lib/action_controller/metal/url_for.rb @@ -12,17 +12,17 @@ module ActionController ).merge(:script_name => request.script_name) end - def _router + def _routes raise "In order to use #url_for, you must include the helpers of a particular " \ - "router. For instance, `include Rails.application.routes.url_helpers" + "routes. For instance, `include Rails.application.routes.url_helpers" end module ClassMethods def action_methods @action_methods ||= begin - super - _router.named_routes.helper_names + super - _routes.named_routes.helper_names end end end end -end \ No newline at end of file +end diff --git a/actionpack/lib/action_dispatch/routing/deprecated_mapper.rb b/actionpack/lib/action_dispatch/routing/deprecated_mapper.rb index bc3f62fb48..9684b86ed4 100644 --- a/actionpack/lib/action_dispatch/routing/deprecated_mapper.rb +++ b/actionpack/lib/action_dispatch/routing/deprecated_mapper.rb @@ -30,8 +30,8 @@ module ActionDispatch class DeprecatedMapper #:nodoc: def initialize(set) #:nodoc: - ActiveSupport::Deprecation.warn "You are using the old router DSL which will be removed in Rails 3.1. " << - "Please check how to update your router file at: http://www.engineyard.com/blog/2010/the-lowdown-on-routes-in-rails-3/" + ActiveSupport::Deprecation.warn "You are using the old routes DSL which will be removed in Rails 3.1. " << + "Please check how to update your routes file at: http://www.engineyard.com/blog/2010/the-lowdown-on-routes-in-rails-3/" @set = set end diff --git a/actionpack/lib/action_dispatch/routing/mapper.rb b/actionpack/lib/action_dispatch/routing/mapper.rb index 0b4ba8c9f5..0d760ed23a 100644 --- a/actionpack/lib/action_dispatch/routing/mapper.rb +++ b/actionpack/lib/action_dispatch/routing/mapper.rb @@ -308,7 +308,7 @@ module ActionDispatch if name_prefix = options.delete(:name_prefix) options[:as] ||= name_prefix - ActiveSupport::Deprecation.warn ":name_prefix was deprecated in the new router syntax. Use :as instead.", caller + ActiveSupport::Deprecation.warn ":name_prefix was deprecated in the new routes syntax. Use :as instead.", caller end case args.first diff --git a/actionpack/lib/action_dispatch/routing/route_set.rb b/actionpack/lib/action_dispatch/routing/route_set.rb index 5ecad6bc04..7248ed03f6 100644 --- a/actionpack/lib/action_dispatch/routing/route_set.rb +++ b/actionpack/lib/action_dispatch/routing/route_set.rb @@ -268,10 +268,10 @@ module ActionDispatch # Yes plz - JP included do routes.install_helpers(self) - singleton_class.send(:define_method, :_router) { routes } + singleton_class.send(:define_method, :_routes) { routes } end - define_method(:_router) { routes } + define_method(:_routes) { routes } end helpers @@ -474,7 +474,7 @@ module ActionDispatch path_options = yield(path_options) if block_given? path = generate(path_options, path_segments || {}) - # ROUTES TODO: This can be called directly, so script_name should probably be set in the router + # ROUTES TODO: This can be called directly, so script_name should probably be set in routes rewritten_url << (options[:trailing_slash] ? path.sub(/\?|\z/) { "/" + $& } : path) rewritten_url << "##{Rack::Mount::Utils.escape_uri(options[:anchor].to_param.to_s)}" if options[:anchor] diff --git a/actionpack/lib/action_dispatch/routing/url_for.rb b/actionpack/lib/action_dispatch/routing/url_for.rb index db17615d92..980abd44df 100644 --- a/actionpack/lib/action_dispatch/routing/url_for.rb +++ b/actionpack/lib/action_dispatch/routing/url_for.rb @@ -128,7 +128,7 @@ module ActionDispatch when String options when nil, Hash - _router.url_for(url_options.merge((options || {}).symbolize_keys)) + _routes.url_for(url_options.merge((options || {}).symbolize_keys)) else polymorphic_url(options) end diff --git a/actionpack/lib/action_view/base.rb b/actionpack/lib/action_view/base.rb index 956c88a553..20a2e7c1f0 100644 --- a/actionpack/lib/action_view/base.rb +++ b/actionpack/lib/action_view/base.rb @@ -173,7 +173,7 @@ module ActionView #:nodoc: @@field_error_proc = Proc.new{ |html_tag, instance| "
#{html_tag}
".html_safe } class_attribute :helpers - class_attribute :_router + class_attribute :_routes class << self delegate :erb_trim_mode=, :to => 'ActionView::Template::Handlers::ERB' diff --git a/actionpack/lib/action_view/helpers/url_helper.rb b/actionpack/lib/action_view/helpers/url_helper.rb index b8d6dc22f2..0e3cc54fd1 100644 --- a/actionpack/lib/action_view/helpers/url_helper.rb +++ b/actionpack/lib/action_view/helpers/url_helper.rb @@ -12,7 +12,7 @@ module ActionView # and controllers. module UrlHelper # This helper may be included in any class that includes the - # URL helpers of a router (router.url_helpers). Some methods + # URL helpers of a routes (routes.url_helpers). Some methods # provided here will only work in the4 context of a request # (link_to_unless_current, for instance), which must be provided # as a method called #request on the context. diff --git a/actionpack/lib/action_view/test_case.rb b/actionpack/lib/action_view/test_case.rb index e5614c9e3b..56aebca957 100644 --- a/actionpack/lib/action_view/test_case.rb +++ b/actionpack/lib/action_view/test_case.rb @@ -151,7 +151,7 @@ module ActionView @view ||= begin view = ActionView::Base.new(ActionController::Base.view_paths, {}, @controller) view.singleton_class.send :include, _helpers - view.singleton_class.send :include, @controller._router.url_helpers + view.singleton_class.send :include, @controller._routes.url_helpers view.singleton_class.send :delegate, :alert, :notice, :to => "request.flash" view.extend(Locals) view.locals = self.locals @@ -192,13 +192,13 @@ module ActionView end end - def _router - @controller._router if @controller.respond_to?(:_router) + def _routes + @controller._routes if @controller.respond_to?(:_routes) end def method_missing(selector, *args) - if @controller.respond_to?(:_router) && - @controller._router.named_routes.helpers.include?(selector) + if @controller.respond_to?(:_routes) && + @controller._routes.named_routes.helpers.include?(selector) @controller.__send__(selector, *args) else super diff --git a/actionpack/test/abstract_unit.rb b/actionpack/test/abstract_unit.rb index c8477fb83f..89c4cb46a1 100644 --- a/actionpack/test/abstract_unit.rb +++ b/actionpack/test/abstract_unit.rb @@ -41,7 +41,7 @@ require 'pp' # require 'pp' early to prevent hidden_methods from not picking up module Rails end -# Monkey patch the old router initialization to be silenced. +# Monkey patch the old routes initialization to be silenced. class ActionDispatch::Routing::DeprecatedMapper def initialize_with_silencer(*args) ActiveSupport::Deprecation.silence { initialize_without_silencer(*args) } @@ -275,9 +275,9 @@ end class ActionController::Base def self.test_routes(&block) - router = ActionDispatch::Routing::RouteSet.new - router.draw(&block) - include router.url_helpers + routes = ActionDispatch::Routing::RouteSet.new + routes.draw(&block) + include routes.url_helpers end end diff --git a/actionpack/test/controller/url_for_test.rb b/actionpack/test/controller/url_for_test.rb index 4b30b0af36..71a4a43477 100644 --- a/actionpack/test/controller/url_for_test.rb +++ b/actionpack/test/controller/url_for_test.rb @@ -120,7 +120,7 @@ module AbstractController def test_relative_url_root_is_respected # ROUTES TODO: Tests should not have to pass :relative_url_root directly. This - # should probably come from the router. + # should probably come from routes. add_host! assert_equal('https://www.basecamphq.com/subdir/c/a/i', diff --git a/actionpack/test/dispatch/url_generation_test.rb b/actionpack/test/dispatch/url_generation_test.rb index 326b336a1a..f83651d583 100644 --- a/actionpack/test/dispatch/url_generation_test.rb +++ b/actionpack/test/dispatch/url_generation_test.rb @@ -2,24 +2,24 @@ require 'abstract_unit' module TestUrlGeneration class WithMountPoint < ActionDispatch::IntegrationTest - Router = ActionDispatch::Routing::RouteSet.new - Router.draw { match "/foo", :to => "my_route_generating#index", :as => :foo } + Routes = ActionDispatch::Routing::RouteSet.new + Routes.draw { match "/foo", :to => "my_route_generating#index", :as => :foo } class ::MyRouteGeneratingController < ActionController::Base - include Router.url_helpers + include Routes.url_helpers def index render :text => foo_path end end - include Router.url_helpers + include Routes.url_helpers - def _router - Router + def _routes + Routes end def app - Router + Routes end test "generating URLS normally" do @@ -30,7 +30,7 @@ module TestUrlGeneration assert_equal "/bar/foo", foo_path(:script_name => "/bar") end - test "the request's SCRIPT_NAME takes precedence over the router's" do + test "the request's SCRIPT_NAME takes precedence over the routes'" do get "/foo", {}, 'SCRIPT_NAME' => "/new" assert_equal "/new/foo", response.body end -- cgit v1.2.3 From 2ef8a2b403adcee21fe1a5bfadc125b24779cd53 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Thu, 1 Jul 2010 16:59:31 -0300 Subject: bump erubis version to 2.6.6 and thor version to 0.13.7 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: José Valim --- actionpack/actionpack.gemspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'actionpack') diff --git a/actionpack/actionpack.gemspec b/actionpack/actionpack.gemspec index b4311599a9..df0b5ac9a2 100644 --- a/actionpack/actionpack.gemspec +++ b/actionpack/actionpack.gemspec @@ -27,5 +27,5 @@ Gem::Specification.new do |s| s.add_dependency('rack-test', '~> 0.5.4') #s.add_dependency('rack-mount', '~> 0.6.6') s.add_dependency('tzinfo', '~> 0.3.16') - s.add_dependency('erubis', '~> 2.6.5') + s.add_dependency('erubis', '~> 2.6.6') end -- cgit v1.2.3 From 9e6e64873243ee707ecad3d523ceb0dbae0617cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Fri, 2 Jul 2010 19:13:00 +0200 Subject: Fix routes with :controller segment when namespaced [#5034 state:resolved] --- actionpack/lib/action_dispatch/routing/mapper.rb | 2 +- .../lib/action_dispatch/routing/route_set.rb | 50 ++++++++++++++-------- actionpack/test/abstract_unit.rb | 17 +++++--- actionpack/test/dispatch/routing_test.rb | 24 ++++++++--- 4 files changed, 63 insertions(+), 30 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_dispatch/routing/mapper.rb b/actionpack/lib/action_dispatch/routing/mapper.rb index 0d760ed23a..d71005a852 100644 --- a/actionpack/lib/action_dispatch/routing/mapper.rb +++ b/actionpack/lib/action_dispatch/routing/mapper.rb @@ -91,7 +91,7 @@ module ActionDispatch def app Constraints.new( - to.respond_to?(:call) ? to : Routing::RouteSet::Dispatcher.new(:defaults => defaults), + to.respond_to?(:call) ? to : Routing::RouteSet::Dispatcher.new(:defaults => defaults, :module => @scope[:module]), blocks, @set.request_class ) diff --git a/actionpack/lib/action_dispatch/routing/route_set.rb b/actionpack/lib/action_dispatch/routing/route_set.rb index 7248ed03f6..afa312889f 100644 --- a/actionpack/lib/action_dispatch/routing/route_set.rb +++ b/actionpack/lib/action_dispatch/routing/route_set.rb @@ -14,6 +14,7 @@ module ActionDispatch def initialize(options={}) @defaults = options[:defaults] @glob_param = options.delete(:glob) + @module = options.delete(:module) @controllers = {} end @@ -26,7 +27,7 @@ module ActionDispatch return [404, {'X-Cascade' => 'pass'}, []] end - controller.action(params[:action]).call(env) + dispatch(controller, params[:action], env) end def prepare_params!(params) @@ -34,29 +35,44 @@ module ActionDispatch split_glob_param!(params) if @glob_param end - def controller(params, raise_error=true) + # If this is a default_controller (i.e. a controller specified by the user) + # we should raise an error in case it's not found, because it usually means + # an user error. However, if the controller was retrieved through a dynamic + # segment, as in :controller(/:action), we should simply return nil and + # delegate the control back to Rack cascade. Besides, if this is not a default + # controller, it means we should respect the @scope[:module] parameter. + def controller(params, default_controller=true) if params && params.key?(:controller) - controller_param = params[:controller] - unless controller = @controllers[controller_param] - controller_name = "#{controller_param.camelize}Controller" - controller = @controllers[controller_param] = - ActiveSupport::Dependencies.ref(controller_name) - end - - controller.get + controller_param = @module && !default_controller ? + "#{@module}/#{params[:controller]}" : params[:controller] + controller_reference(controller_param) end rescue NameError => e - raise ActionController::RoutingError, e.message, e.backtrace if raise_error + raise ActionController::RoutingError, e.message, e.backtrace if default_controller end - private - def merge_default_action!(params) - params[:action] ||= 'index' - end + private - def split_glob_param!(params) - params[@glob_param] = params[@glob_param].split('/').map { |v| URI.unescape(v) } + def controller_reference(controller_param) + unless controller = @controllers[controller_param] + controller_name = "#{controller_param.camelize}Controller" + controller = @controllers[controller_param] = + ActiveSupport::Dependencies.ref(controller_name) end + controller.get + end + + def dispatch(controller, action, env) + controller.action(action).call(env) + end + + def merge_default_action!(params) + params[:action] ||= 'index' + end + + def split_glob_param!(params) + params[@glob_param] = params[@glob_param].split('/').map { |v| URI.unescape(v) } + end end # A NamedRouteCollection instance is a collection of named routes, and also diff --git a/actionpack/test/abstract_unit.rb b/actionpack/test/abstract_unit.rb index 89c4cb46a1..5be47f7c96 100644 --- a/actionpack/test/abstract_unit.rb +++ b/actionpack/test/abstract_unit.rb @@ -182,13 +182,16 @@ class ActionController::IntegrationTest < ActiveSupport::TestCase self.app = build_app - class StubDispatcher - def self.new(*args) - lambda { |env| - params = env['action_dispatch.request.path_parameters'] - controller, action = params[:controller], params[:action] - [200, {'Content-Type' => 'text/html'}, ["#{controller}##{action}"]] - } + # Stub Rails dispatcher so it does not get controller references and + # simply return the controller#action as Rack::Body. + class StubDispatcher < ::ActionDispatch::Routing::RouteSet::Dispatcher + protected + def controller_reference(controller_param) + controller_param + end + + def dispatch(controller, action, env) + [200, {'Content-Type' => 'text/html'}, ["#{controller}##{action}"]] end end diff --git a/actionpack/test/dispatch/routing_test.rb b/actionpack/test/dispatch/routing_test.rb index 26bd641cd6..1bfc92aa3d 100644 --- a/actionpack/test/dispatch/routing_test.rb +++ b/actionpack/test/dispatch/routing_test.rb @@ -310,11 +310,6 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest match '/' => 'mes#index' end - namespace :private do - root :to => redirect('/private/index') - match "index", :to => 'private#index' - end - get "(/:username)/followers" => "followers#index" get "/groups(/user/:username)" => "groups#index" get "(/user/:username)/photos" => "photos#index" @@ -348,6 +343,12 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest end end + namespace :private do + root :to => redirect('/private/index') + match "index", :to => 'private#index' + match ":controller(/:action(/:id))" + end + match '/:locale/*file.:format', :to => 'files#show', :file => /path\/to\/existing\/file/ end end @@ -470,6 +471,19 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest end end + def test_namespace_with_controller_segment + with_test_routes do + get '/private/foo' + assert_equal 'private/foo#index', @response.body + + get '/private/foo/bar' + assert_equal 'private/foo#bar', @response.body + + get '/private/foo/bar/1' + assert_equal 'private/foo#bar', @response.body + end + end + def test_session_singleton_resource with_test_routes do get '/session' -- cgit v1.2.3 From 54250a5bfe6992afaaca6357d3b414e6c49651ba Mon Sep 17 00:00:00 2001 From: Andrew White Date: Sat, 3 Jul 2010 08:14:17 +0100 Subject: Refactor recall parameter normalization [#5021 state:resolved] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: José Valim --- .../lib/action_dispatch/routing/route_set.rb | 22 +++++----------- actionpack/test/template/url_helper_test.rb | 29 ++++++++++++++++++++-- 2 files changed, 33 insertions(+), 18 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_dispatch/routing/route_set.rb b/actionpack/lib/action_dispatch/routing/route_set.rb index afa312889f..177a6db04e 100644 --- a/actionpack/lib/action_dispatch/routing/route_set.rb +++ b/actionpack/lib/action_dispatch/routing/route_set.rb @@ -318,7 +318,6 @@ module ActionDispatch @extras = extras normalize_options! - normalize_recall! normalize_controller_action_id! use_relative_controller! controller.sub!(%r{^/}, '') if controller @@ -335,7 +334,11 @@ module ActionDispatch def use_recall_for(key) if @recall[key] && (!@options.key?(key) || @options[key] == @recall[key]) - @options[key] = @recall.delete(key) + if named_route_exists? + @options[key] = @recall.delete(key) if segment_keys.include?(key) + else + @options[key] = @recall.delete(key) + end end end @@ -359,15 +362,6 @@ module ActionDispatch end end - def normalize_recall! - # If the target route is not a standard route then remove controller and action - # from the options otherwise they will appear in the url parameters - if block_or_proc_route_target? - recall.delete(:controller) unless segment_keys.include?(:controller) - recall.delete(:action) unless segment_keys.include?(:action) - end - end - # This pulls :controller, :action, and :id out of the recall. # The recall key is only used if there is no key in the options # or if the key in the options is identical. If any of @@ -440,12 +434,8 @@ module ActionDispatch named_route && set.named_routes[named_route] end - def block_or_proc_route_target? - named_route_exists? && !set.named_routes[named_route].app.is_a?(Dispatcher) - end - def segment_keys - named_route_exists? ? set.named_routes[named_route].segment_keys : [] + set.named_routes[named_route].segment_keys end end diff --git a/actionpack/test/template/url_helper_test.rb b/actionpack/test/template/url_helper_test.rb index 765beebfa3..048f96c9a9 100644 --- a/actionpack/test/template/url_helper_test.rb +++ b/actionpack/test/template/url_helper_test.rb @@ -406,6 +406,14 @@ end class UrlHelperControllerTest < ActionController::TestCase class UrlHelperController < ActionController::Base test_routes do |map| + match 'url_helper_controller_test/url_helper/show/:id', + :to => 'url_helper_controller_test/url_helper#show', + :as => :show + + match 'url_helper_controller_test/url_helper/profile/:name', + :to => 'url_helper_controller_test/url_helper#show', + :as => :profile + match 'url_helper_controller_test/url_helper/show_named_route', :to => 'url_helper_controller_test/url_helper#show_named_route', :as => :show_named_route @@ -418,6 +426,14 @@ class UrlHelperControllerTest < ActionController::TestCase :as => :normalize_recall_params end + def show + if params[:name] + render :inline => 'ok' + else + redirect_to profile_path(params[:id]) + end + end + def show_url_for render :inline => "<%= url_for :controller => 'url_helper_controller_test/url_helper', :action => 'show_url_for' %>" end @@ -484,15 +500,24 @@ class UrlHelperControllerTest < ActionController::TestCase assert_equal 'http://testtwo.host/url_helper_controller_test/url_helper/show_named_route', @response.body end - def test_recall_params_should_be_normalized_when_using_block_route + def test_recall_params_should_be_normalized get :normalize_recall_params assert_equal '/url_helper_controller_test/url_helper/normalize_recall_params', @response.body end - def test_recall_params_should_not_be_changed_when_using_normal_route + def test_recall_params_should_not_be_changed get :recall_params_not_changed assert_equal '/url_helper_controller_test/url_helper/show_url_for', @response.body end + + def test_recall_params_should_normalize_id + get :show, :id => '123' + assert_equal 302, @response.status + assert_equal 'http://test.host/url_helper_controller_test/url_helper/profile/123', @response.location + + get :show, :name => '123' + assert_equal 'ok', @response.body + end end class TasksController < ActionController::Base -- cgit v1.2.3 From 75b32a69a185e2e802934bc4000f6c0efbc5c2e7 Mon Sep 17 00:00:00 2001 From: Wincent Colaiuta Date: Sat, 3 Jul 2010 12:12:50 +0200 Subject: Fixes for "router" and "routes" terminology MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit f7ba614c2db improved the internal consistency of the different means of accessing routes, but it introduced some problems at the level of code comments and user-visible strings. This commit applies fixes on three levels: Firstly, we remove or replace grammatically invalid constructs such as "a routes" or "a particular routes". Secondly, we make sure that we always use "the router DSL" or "the router syntax", because this has always been the official terminology. Finally, we make sure that we only use "routes" when referring to the application-specific set of routes that are defined in the "config/routes.rb" file, we use "router" when referring on a more abstract level to "the code in Rails used to handle routing", and we use "routing" when we need an adjective to apply to nouns such as "url_helpers. Again this is consistent with historical practice and other places in the documentation. Note that this is not a sweep over the entire codebase to ensure consistent usage of language; it is just a revision of the changes introduced in commit f7ba614c2db. Signed-off-by: Wincent Colaiuta Signed-off-by: José Valim --- actionpack/lib/action_controller/deprecated/base.rb | 2 +- actionpack/lib/action_controller/metal.rb | 2 +- actionpack/lib/action_controller/metal/url_for.rb | 4 ++-- actionpack/lib/action_dispatch/routing/deprecated_mapper.rb | 2 +- actionpack/lib/action_dispatch/routing/mapper.rb | 2 +- actionpack/lib/action_dispatch/routing/route_set.rb | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/deprecated/base.rb b/actionpack/lib/action_controller/deprecated/base.rb index 16b67b8ee7..3975afcaf0 100644 --- a/actionpack/lib/action_controller/deprecated/base.rb +++ b/actionpack/lib/action_controller/deprecated/base.rb @@ -96,7 +96,7 @@ module ActionController def resource_action_separator=(val) ActiveSupport::Deprecation.warn "ActionController::Base.resource_action_separator is deprecated and only " \ - "works with the deprecated routes DSL." + "works with the deprecated router DSL." @resource_action_separator = val end diff --git a/actionpack/lib/action_controller/metal.rb b/actionpack/lib/action_controller/metal.rb index 8166d31719..2281c500c5 100644 --- a/actionpack/lib/action_controller/metal.rb +++ b/actionpack/lib/action_controller/metal.rb @@ -47,7 +47,7 @@ module ActionController # # In AbstractController, dispatching is triggered directly by calling #process on a new controller. # ActionController::Metal provides an #action method that returns a valid Rack application for a - # given action. Other rack builders, such as Rack::Builder, Rack::URLMap, and the Rails routes, + # given action. Other rack builders, such as Rack::Builder, Rack::URLMap, and the Rails router, # can dispatch directly to the action returned by FooController.action(:index). class Metal < AbstractController::Base abstract! diff --git a/actionpack/lib/action_controller/metal/url_for.rb b/actionpack/lib/action_controller/metal/url_for.rb index 0c1e2fbe80..a51fc5b8e4 100644 --- a/actionpack/lib/action_controller/metal/url_for.rb +++ b/actionpack/lib/action_controller/metal/url_for.rb @@ -13,8 +13,8 @@ module ActionController end def _routes - raise "In order to use #url_for, you must include the helpers of a particular " \ - "routes. For instance, `include Rails.application.routes.url_helpers" + raise "In order to use #url_for, you must include routing helpers explicitly. " \ + "For instance, `include Rails.application.routes.url_helpers" end module ClassMethods diff --git a/actionpack/lib/action_dispatch/routing/deprecated_mapper.rb b/actionpack/lib/action_dispatch/routing/deprecated_mapper.rb index 9684b86ed4..e122bdf232 100644 --- a/actionpack/lib/action_dispatch/routing/deprecated_mapper.rb +++ b/actionpack/lib/action_dispatch/routing/deprecated_mapper.rb @@ -30,7 +30,7 @@ module ActionDispatch class DeprecatedMapper #:nodoc: def initialize(set) #:nodoc: - ActiveSupport::Deprecation.warn "You are using the old routes DSL which will be removed in Rails 3.1. " << + ActiveSupport::Deprecation.warn "You are using the old router DSL which will be removed in Rails 3.1. " << "Please check how to update your routes file at: http://www.engineyard.com/blog/2010/the-lowdown-on-routes-in-rails-3/" @set = set end diff --git a/actionpack/lib/action_dispatch/routing/mapper.rb b/actionpack/lib/action_dispatch/routing/mapper.rb index d71005a852..64e12f960d 100644 --- a/actionpack/lib/action_dispatch/routing/mapper.rb +++ b/actionpack/lib/action_dispatch/routing/mapper.rb @@ -308,7 +308,7 @@ module ActionDispatch if name_prefix = options.delete(:name_prefix) options[:as] ||= name_prefix - ActiveSupport::Deprecation.warn ":name_prefix was deprecated in the new routes syntax. Use :as instead.", caller + ActiveSupport::Deprecation.warn ":name_prefix was deprecated in the new router syntax. Use :as instead.", caller end case args.first diff --git a/actionpack/lib/action_dispatch/routing/route_set.rb b/actionpack/lib/action_dispatch/routing/route_set.rb index 177a6db04e..24f9981f4b 100644 --- a/actionpack/lib/action_dispatch/routing/route_set.rb +++ b/actionpack/lib/action_dispatch/routing/route_set.rb @@ -480,7 +480,7 @@ module ActionDispatch path_options = yield(path_options) if block_given? path = generate(path_options, path_segments || {}) - # ROUTES TODO: This can be called directly, so script_name should probably be set in routes + # ROUTES TODO: This can be called directly, so script_name should probably be set in the routes rewritten_url << (options[:trailing_slash] ? path.sub(/\?|\z/) { "/" + $& } : path) rewritten_url << "##{Rack::Mount::Utils.escape_uri(options[:anchor].to_param.to_s)}" if options[:anchor] -- cgit v1.2.3 From c6843e23373c626ae49ad9fa253d4f7538d3434f Mon Sep 17 00:00:00 2001 From: Andrew White Date: Sun, 4 Jul 2010 06:52:52 +0100 Subject: Refactor resource options and scoping. Resource classes are now only responsible for controlling how they are named. All other options passed to resources are pushed out to the scope. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: José Valim --- actionpack/lib/action_dispatch/routing/mapper.rb | 163 +++++++++-------------- actionpack/test/dispatch/routing_test.rb | 83 +++++++++++- 2 files changed, 145 insertions(+), 101 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_dispatch/routing/mapper.rb b/actionpack/lib/action_dispatch/routing/mapper.rb index 64e12f960d..f44c10f533 100644 --- a/actionpack/lib/action_dispatch/routing/mapper.rb +++ b/actionpack/lib/action_dispatch/routing/mapper.rb @@ -444,7 +444,7 @@ module ActionDispatch # a path appended since they fit properly in their scope level. VALID_ON_OPTIONS = [:new, :collection, :member] CANONICAL_ACTIONS = [:index, :create, :new, :show, :update, :destroy] - MERGE_FROM_SCOPE_OPTIONS = [:shallow, :constraints] + RESOURCE_OPTIONS = [:as, :controller, :path] class Resource #:nodoc: DEFAULT_ACTIONS = [:index, :create, :new, :show, :update, :destroy, :edit] @@ -463,16 +463,6 @@ module ActionDispatch self.class::DEFAULT_ACTIONS end - def actions - if only = options[:only] - Array(only).map(&:to_sym) - elsif except = options[:except] - default_actions - Array(except).map(&:to_sym) - else - default_actions - end - end - def name @as || @name end @@ -489,68 +479,31 @@ module ActionDispatch singular end - alias_method :nested_name, :member_name - # Checks for uncountable plurals, and appends "_index" if they're. def collection_name singular == plural ? "#{plural}_index" : plural end - def shallow? - options[:shallow] ? true : false - end - - def constraints - options[:constraints] || {} - end - - def id_constraint? - options[:id] && options[:id].is_a?(Regexp) || constraints[:id] && constraints[:id].is_a?(Regexp) - end - - def id_constraint - options[:id] || constraints[:id] - end - - def collection_options - (options || {}).dup.tap do |opts| - opts.delete(:id) - opts[:constraints] = options[:constraints].dup if options[:constraints] - opts[:constraints].delete(:id) if options[:constraints].is_a?(Hash) - end - end - - def nested_path - "#{path}/:#{singular}_id" - end - - def nested_options - {}.tap do |opts| - opts[:as] = member_name - opts["#{singular}_id".to_sym] = id_constraint if id_constraint? - opts[:options] = { :shallow => shallow? } unless options[:shallow].nil? - end - end - def resource_scope - [{ :controller => controller }] + { :controller => controller } end def collection_scope - [path, collection_options] + path end def member_scope - ["#{path}/:id", options] + "#{path}/:id" end def new_scope(new_path) - ["#{path}/#{new_path}"] + "#{path}/#{new_path}" end def nested_scope - [nested_path, nested_options] + "#{path}/:#{singular}_id" end + end class SingletonResource < Resource #:nodoc: @@ -559,7 +512,7 @@ module ActionDispatch def initialize(entities, options) @name = entities.to_s @path = options.delete(:path) || @name - @controller = (options.delete(:controller) || @name.to_s.pluralize).to_s + @controller = (options.delete(:controller) || plural).to_s @as = options.delete(:as) @options = options end @@ -569,24 +522,10 @@ module ActionDispatch end alias :collection_name :member_name - def nested_path - path - end - - def nested_options - {}.tap do |opts| - opts[:as] = member_name - opts[:options] = { :shallow => shallow? } unless @options[:shallow].nil? - end - end - - def shallow? - false - end - def member_scope - [path, options] + path end + alias :nested_scope :member_scope end def initialize(*args) #:nodoc: @@ -610,17 +549,17 @@ module ActionDispatch collection_scope do post :create - end if parent_resource.actions.include?(:create) + end if resource_actions.include?(:create) new_scope do get :new - end if parent_resource.actions.include?(:new) + end if resource_actions.include?(:new) member_scope do - get :show if parent_resource.actions.include?(:show) - put :update if parent_resource.actions.include?(:update) - delete :destroy if parent_resource.actions.include?(:destroy) - get :edit if parent_resource.actions.include?(:edit) + get :show if resource_actions.include?(:show) + put :update if resource_actions.include?(:update) + delete :destroy if resource_actions.include?(:destroy) + get :edit if resource_actions.include?(:edit) end end @@ -638,19 +577,19 @@ module ActionDispatch yield if block_given? collection_scope do - get :index if parent_resource.actions.include?(:index) - post :create if parent_resource.actions.include?(:create) + get :index if resource_actions.include?(:index) + post :create if resource_actions.include?(:create) end new_scope do get :new - end if parent_resource.actions.include?(:new) + end if resource_actions.include?(:new) member_scope do - get :show if parent_resource.actions.include?(:show) - put :update if parent_resource.actions.include?(:update) - delete :destroy if parent_resource.actions.include?(:destroy) - get :edit if parent_resource.actions.include?(:edit) + get :show if resource_actions.include?(:show) + put :update if resource_actions.include?(:update) + delete :destroy if resource_actions.include?(:destroy) + get :edit if resource_actions.include?(:edit) end end @@ -693,18 +632,18 @@ module ActionDispatch end with_scope_level(:nested) do - if parent_resource.shallow? + if shallow? with_exclusive_scope do if @scope[:shallow_path].blank? - scope(*parent_resource.nested_scope) { yield } + scope(parent_resource.nested_scope, nested_options) { yield } else scope(@scope[:shallow_path], :as => @scope[:shallow_prefix]) do - scope(*parent_resource.nested_scope) { yield } + scope(parent_resource.nested_scope, nested_options) { yield } end end end else - scope(*parent_resource.nested_scope) { yield } + scope(parent_resource.nested_scope, nested_options) { yield } end end end @@ -723,6 +662,10 @@ module ActionDispatch end end + def shallow? + parent_resource.instance_of?(Resource) && @scope[:shallow] + end + def match(*args) options = args.extract_options!.dup options[:anchor] = true unless options.key?(:anchor) @@ -794,23 +737,30 @@ module ActionDispatch @scope[:scope_level_resource] end + def resource_actions + if only = @scope[:options][:only] + Array(only).map(&:to_sym) + elsif except = @scope[:options][:except] + parent_resource.default_actions - Array(except).map(&:to_sym) + else + parent_resource.default_actions + end + end + def apply_common_behavior_for(method, resources, options, &block) if resources.length > 1 resources.each { |r| send(method, r, options, &block) } return true end - if path_names = options.delete(:path_names) - scope(:path_names => path_names) do + scope_options = options.slice!(*RESOURCE_OPTIONS) + unless scope_options.empty? + scope(scope_options) do send(method, resources.pop, options, &block) end return true end - scope_options = @scope.slice(*MERGE_FROM_SCOPE_OPTIONS).delete_if{ |k,v| v.blank? } - options.reverse_merge!(scope_options) unless scope_options.empty? - options.reverse_merge!(@scope[:options]) unless @scope[:options].blank? - if resource_scope? nested do send(method, resources.pop, options, &block) @@ -853,7 +803,7 @@ module ActionDispatch def resource_scope(resource) with_scope_level(resource.is_a?(SingletonResource) ? :resource : :resources, resource) do - scope(*parent_resource.resource_scope) do + scope(parent_resource.resource_scope) do yield end end @@ -861,7 +811,7 @@ module ActionDispatch def new_scope with_scope_level(:new) do - scope(*parent_resource.new_scope(action_path(:new))) do + scope(parent_resource.new_scope(action_path(:new))) do yield end end @@ -869,7 +819,7 @@ module ActionDispatch def collection_scope with_scope_level(:collection) do - scope(*parent_resource.collection_scope) do + scope(parent_resource.collection_scope) do yield end end @@ -877,18 +827,33 @@ module ActionDispatch def member_scope with_scope_level(:member) do - scope(*parent_resource.member_scope) do + scope(parent_resource.member_scope) do yield end end end + def nested_options + {}.tap do |options| + options[:as] = parent_resource.member_name + options[:constraints] = { "#{parent_resource.singular}_id".to_sym => id_constraint } if id_constraint? + end + end + + def id_constraint? + @scope[:id].is_a?(Regexp) || (@scope[:constraints] && @scope[:constraints][:id].is_a?(Regexp)) + end + + def id_constraint + @scope[:id] || @scope[:constraints][:id] + end + def canonical_action?(action, flag) flag && CANONICAL_ACTIONS.include?(action) end def shallow_scoping? - parent_resource && parent_resource.shallow? && @scope[:scope_level] == :member + shallow? && @scope[:scope_level] == :member end def path_for_action(action, path) diff --git a/actionpack/test/dispatch/routing_test.rb b/actionpack/test/dispatch/routing_test.rb index 1bfc92aa3d..d56612d6ec 100644 --- a/actionpack/test/dispatch/routing_test.rb +++ b/actionpack/test/dispatch/routing_test.rb @@ -298,8 +298,8 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest resource :dashboard, :constraints => { :ip => /192\.168\.1\.\d{1,3}/ } + resource :token, :module => :api scope :module => :api do - resource :token resources :errors, :shallow => true do resources :notices end @@ -349,6 +349,22 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest match ":controller(/:action(/:id))" end + scope :only => :index do + resources :clubs do + resources :players, :only => [:show] + resource :chairman, :only => [:show] + end + end + + scope :except => [:new, :create, :edit, :update] do + resources :sectors do + resources :companies, :except => :destroy do + resources :divisions, :only => :index + end + resource :leader, :except => :destroy + end + end + match '/:locale/*file.:format', :to => 'files#show', :file => /path\/to\/existing\/file/ end end @@ -1254,7 +1270,7 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest assert_equal 'pass', @response.headers['X-Cascade'] get '/products/0001/images' assert_equal 'images#index', @response.body - get '/products/0001/images/1' + get '/products/0001/images/0001' assert_equal 'images#show', @response.body get '/dashboard', {}, {'REMOTE_ADDR' => '10.0.0.100'} @@ -1640,6 +1656,69 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest assert_equal 'Not Found', @response.body assert_raises(ActionController::RoutingError){ movie_trailer_path(:movie_id => '00001') } end + + def test_only_option_should_be_overwritten + get '/clubs' + assert_equal 'clubs#index', @response.body + assert_equal '/clubs', clubs_path + + get '/clubs/1' + assert_equal 'Not Found', @response.body + assert_raise(NameError) { club_path(:id => '1') } + + get '/clubs/1/players' + assert_equal 'Not Found', @response.body + assert_raise(NameError) { club_players_path(:club_id => '1') } + + get '/clubs/1/players/2' + assert_equal 'players#show', @response.body + assert_equal '/clubs/1/players/2', club_player_path(:club_id => '1', :id => '2') + + get '/clubs/1/chairman/new' + assert_equal 'Not Found', @response.body + assert_raise(NameError) { new_club_chairman_path(:club_id => '1') } + + get '/clubs/1/chairman' + assert_equal 'chairmen#show', @response.body + assert_equal '/clubs/1/chairman', club_chairman_path(:club_id => '1') + end + + def test_except_option_should_be_overwritten + get '/sectors' + assert_equal 'sectors#index', @response.body + assert_equal '/sectors', sectors_path + + get '/sectors/new' + assert_equal 'Not Found', @response.body + assert_raise(NameError) { new_sector_path } + + delete '/sectors/1' + assert_equal 'sectors#destroy', @response.body + + get '/sectors/1/companies/new' + assert_equal 'companies#new', @response.body + assert_equal '/sectors/1/companies/new', new_sector_company_path + + delete '/sectors/1/companies/1' + assert_equal 'Not Found', @response.body + + get '/sectors/1/leader/new' + assert_equal 'leaders#new', @response.body + assert_equal '/sectors/1/leader/new', new_sector_leader_path + + delete '/sectors/1/leader' + assert_equal 'Not Found', @response.body + end + + def test_only_option_should_overwrite_except_option + get '/sectors/1/companies/2/divisions' + assert_equal 'divisions#index', @response.body + assert_equal '/sectors/1/companies/2/divisions', sector_company_divisions_path + + get '/sectors/1/companies/2/divisions/3' + assert_equal 'Not Found', @response.body + assert_raise(NameError) { sector_company_division_path(:sector_id => '1', :company_id => '2', :id => '3') } + end end private -- cgit v1.2.3 From aa31a255c831808b42c28978a36ffa42ff03e68e Mon Sep 17 00:00:00 2001 From: Andrew White Date: Sun, 4 Jul 2010 17:35:34 +0100 Subject: Fix syntax of routing tests so they actually run MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: José Valim --- actionpack/test/dispatch/routing_test.rb | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) (limited to 'actionpack') diff --git a/actionpack/test/dispatch/routing_test.rb b/actionpack/test/dispatch/routing_test.rb index d56612d6ec..1eb5d32ec3 100644 --- a/actionpack/test/dispatch/routing_test.rb +++ b/actionpack/test/dispatch/routing_test.rb @@ -1656,19 +1656,21 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest assert_equal 'Not Found', @response.body assert_raises(ActionController::RoutingError){ movie_trailer_path(:movie_id => '00001') } end + end - def test_only_option_should_be_overwritten + def test_only_option_should_be_overwritten + with_test_routes do get '/clubs' assert_equal 'clubs#index', @response.body assert_equal '/clubs', clubs_path get '/clubs/1' assert_equal 'Not Found', @response.body - assert_raise(NameError) { club_path(:id => '1') } + assert_raise(NoMethodError) { club_path(:id => '1') } get '/clubs/1/players' assert_equal 'Not Found', @response.body - assert_raise(NameError) { club_players_path(:club_id => '1') } + assert_raise(NoMethodError) { club_players_path(:club_id => '1') } get '/clubs/1/players/2' assert_equal 'players#show', @response.body @@ -1676,48 +1678,52 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest get '/clubs/1/chairman/new' assert_equal 'Not Found', @response.body - assert_raise(NameError) { new_club_chairman_path(:club_id => '1') } + assert_raise(NoMethodError) { new_club_chairman_path(:club_id => '1') } get '/clubs/1/chairman' assert_equal 'chairmen#show', @response.body assert_equal '/clubs/1/chairman', club_chairman_path(:club_id => '1') end + end - def test_except_option_should_be_overwritten + def test_except_option_should_be_overwritten + with_test_routes do get '/sectors' assert_equal 'sectors#index', @response.body assert_equal '/sectors', sectors_path - get '/sectors/new' + get '/sectors/1/edit' assert_equal 'Not Found', @response.body - assert_raise(NameError) { new_sector_path } + assert_raise(NoMethodError) { edit_sector_path(:id => '1') } delete '/sectors/1' assert_equal 'sectors#destroy', @response.body get '/sectors/1/companies/new' assert_equal 'companies#new', @response.body - assert_equal '/sectors/1/companies/new', new_sector_company_path + assert_equal '/sectors/1/companies/new', new_sector_company_path(:sector_id => '1') delete '/sectors/1/companies/1' assert_equal 'Not Found', @response.body get '/sectors/1/leader/new' assert_equal 'leaders#new', @response.body - assert_equal '/sectors/1/leader/new', new_sector_leader_path + assert_equal '/sectors/1/leader/new', new_sector_leader_path(:sector_id => '1') delete '/sectors/1/leader' assert_equal 'Not Found', @response.body end + end - def test_only_option_should_overwrite_except_option + def test_only_option_should_overwrite_except_option + with_test_routes do get '/sectors/1/companies/2/divisions' assert_equal 'divisions#index', @response.body - assert_equal '/sectors/1/companies/2/divisions', sector_company_divisions_path + assert_equal '/sectors/1/companies/2/divisions', sector_company_divisions_path(:sector_id => '1', :company_id => '2') get '/sectors/1/companies/2/divisions/3' assert_equal 'Not Found', @response.body - assert_raise(NameError) { sector_company_division_path(:sector_id => '1', :company_id => '2', :id => '3') } + assert_raise(NoMethodError) { sector_company_division_path(:sector_id => '1', :company_id => '2', :id => '3') } end end -- cgit v1.2.3 From 7f7480f6fc1e88ce19bee8ac7f6fb2243343495e Mon Sep 17 00:00:00 2001 From: Patrik Stenmark Date: Sat, 15 May 2010 14:10:40 +0200 Subject: Adds tests for content negotiation change introduced in dc5300adb6d46252c26e Signed-off-by: wycats --- actionpack/test/controller/mime_responds_test.rb | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) (limited to 'actionpack') diff --git a/actionpack/test/controller/mime_responds_test.rb b/actionpack/test/controller/mime_responds_test.rb index d654338dba..b5ce391b61 100644 --- a/actionpack/test/controller/mime_responds_test.rb +++ b/actionpack/test/controller/mime_responds_test.rb @@ -36,6 +36,15 @@ class RespondToController < ActionController::Base type.all { render :text => "Nothing" } end end + + def json_xml_or_html + respond_to do |type| + type.json { render :text => 'JSON' } + type.xml { render :xml => 'XML' } + type.html { render :text => 'HTML' } + end + end + def forced_xml request.format = :xml @@ -364,6 +373,17 @@ class RespondToControllerTest < ActionController::TestCase get :handle_any_any assert_equal 'Whatever you ask for, I got it', @response.body end + + def test_browser_check_with_any_any + @request.accept = "application/json, application/xml" + get :json_xml_or_html + assert_equal 'JSON', @response.body + + @request.accept = "application/json, application/xml, */*" + get :json_xml_or_html + assert_equal 'HTML', @response.body + end + def test_rjs_type_skips_layout @request.accept = "text/javascript" -- cgit v1.2.3 From a5dda97602f2188a13cbcab5c7e9a5ba84ba876b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Mon, 5 Jul 2010 12:50:08 +0200 Subject: Define a convention for descendants and subclasses. The former should be symmetric with ancestors and include all children. However, it should not include self since ancestors + descendants should not have duplicated. The latter is symmetric to superclass in the sense it only includes direct children. By adopting a convention, we expect to have less conflict with other frameworks, as Datamapper. For this moment, to ensure ActiveModel::Validations can be used with Datamapper, we should always call ActiveSupport::DescendantsTracker.descendants(self) internally instead of self.descendants avoiding conflicts. --- actionpack/lib/action_controller/base.rb | 6 ------ actionpack/lib/action_controller/railtie.rb | 1 - actionpack/lib/action_dispatch/routing/deprecated_mapper.rb | 4 ++-- 3 files changed, 2 insertions(+), 9 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/base.rb b/actionpack/lib/action_controller/base.rb index a70ba0d2e3..1a2cbaab65 100644 --- a/actionpack/lib/action_controller/base.rb +++ b/actionpack/lib/action_controller/base.rb @@ -60,17 +60,11 @@ module ActionController include ActionController::Compatibility def self.inherited(klass) - ::ActionController::Base.subclasses << klass.to_s super klass.helper :all end - def self.subclasses - @subclasses ||= [] - end - config_accessor :asset_host, :asset_path - ActiveSupport.run_load_hooks(:action_controller, self) end end diff --git a/actionpack/lib/action_controller/railtie.rb b/actionpack/lib/action_controller/railtie.rb index 86395c4d93..9261422f0b 100644 --- a/actionpack/lib/action_controller/railtie.rb +++ b/actionpack/lib/action_controller/railtie.rb @@ -2,7 +2,6 @@ require "rails" require "action_controller" require "action_dispatch/railtie" require "action_view/railtie" -require "active_support/core_ext/class/subclasses" require "active_support/deprecation/proxy_wrappers" require "active_support/deprecation" diff --git a/actionpack/lib/action_dispatch/routing/deprecated_mapper.rb b/actionpack/lib/action_dispatch/routing/deprecated_mapper.rb index e122bdf232..05e8dfded6 100644 --- a/actionpack/lib/action_dispatch/routing/deprecated_mapper.rb +++ b/actionpack/lib/action_dispatch/routing/deprecated_mapper.rb @@ -19,8 +19,8 @@ module ActionDispatch def in_memory_controller_namespaces namespaces = Set.new - ActionController::Base.subclasses.each do |klass| - controller_name = klass.underscore + ActionController::Base.descendants.each do |klass| + controller_name = klass.name.underscore namespaces << controller_name.split('/')[0...-1].join('/') end namespaces.delete('') -- cgit v1.2.3 From 6671d9cdc1cc40a6cdd365902f76d4aca78a410c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Mon, 5 Jul 2010 21:44:49 +0200 Subject: RouteSet should also handle anonymous classes. --- actionpack/lib/action_dispatch/routing/deprecated_mapper.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_dispatch/routing/deprecated_mapper.rb b/actionpack/lib/action_dispatch/routing/deprecated_mapper.rb index 05e8dfded6..b3146a1c60 100644 --- a/actionpack/lib/action_dispatch/routing/deprecated_mapper.rb +++ b/actionpack/lib/action_dispatch/routing/deprecated_mapper.rb @@ -20,8 +20,8 @@ module ActionDispatch def in_memory_controller_namespaces namespaces = Set.new ActionController::Base.descendants.each do |klass| - controller_name = klass.name.underscore - namespaces << controller_name.split('/')[0...-1].join('/') + next if klass.anonymous? + namespaces << klass.name.underscore.split('/')[0...-1].join('/') end namespaces.delete('') namespaces -- cgit v1.2.3 From 8079484b118e6dc8ffe3575b50c3857acd5b1a6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Tue, 6 Jul 2010 00:39:13 +0200 Subject: Recognize should also work with route is wrapped in a constraint. --- actionpack/lib/action_dispatch/routing/mapper.rb | 2 ++ actionpack/lib/action_dispatch/routing/route_set.rb | 2 ++ actionpack/test/dispatch/routing_test.rb | 5 ++++- 3 files changed, 8 insertions(+), 1 deletion(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_dispatch/routing/mapper.rb b/actionpack/lib/action_dispatch/routing/mapper.rb index f44c10f533..6529cf6f31 100644 --- a/actionpack/lib/action_dispatch/routing/mapper.rb +++ b/actionpack/lib/action_dispatch/routing/mapper.rb @@ -13,6 +13,8 @@ module ActionDispatch end end + attr_reader :app + def initialize(app, constraints, request) @app, @constraints, @request = app, constraints, request end diff --git a/actionpack/lib/action_dispatch/routing/route_set.rb b/actionpack/lib/action_dispatch/routing/route_set.rb index 24f9981f4b..01a068a9f2 100644 --- a/actionpack/lib/action_dispatch/routing/route_set.rb +++ b/actionpack/lib/action_dispatch/routing/route_set.rb @@ -512,6 +512,8 @@ module ActionDispatch end dispatcher = route.app + dispatcher = dispatcher.app while dispatcher.is_a?(Mapper::Constraints) + if dispatcher.is_a?(Dispatcher) && dispatcher.controller(params, false) dispatcher.prepare_params!(params) return params diff --git a/actionpack/test/dispatch/routing_test.rb b/actionpack/test/dispatch/routing_test.rb index 1eb5d32ec3..463a62cd53 100644 --- a/actionpack/test/dispatch/routing_test.rb +++ b/actionpack/test/dispatch/routing_test.rb @@ -45,7 +45,10 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest match 'account/logout' => redirect("/logout"), :as => :logout_redirect match 'account/login', :to => redirect("/login") - match 'account/overview' + constraints(lambda { |req| true }) do + match 'account/overview' + end + match '/account/nested/overview' match 'sign_in' => "sessions#new" -- cgit v1.2.3 From f4be0041c605daad2406ec41fa7dfa4388af5f31 Mon Sep 17 00:00:00 2001 From: Andrew White Date: Tue, 6 Jul 2010 19:06:02 +0100 Subject: Refactor handling of :only and :except options. The rules are: MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. Don't inherit when specified as an option on a resource 2. Don't push into scope when specified as an option on a resource 2. Resources pull in :only or :except options from scope 3. Either :only or :except in nested scope overwrites parent scope [#5048 state:resolved] Signed-off-by: José Valim --- actionpack/lib/action_dispatch/routing/mapper.rb | 72 ++++--- actionpack/test/dispatch/routing_test.rb | 237 ++++++++++++++++++----- 2 files changed, 236 insertions(+), 73 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_dispatch/routing/mapper.rb b/actionpack/lib/action_dispatch/routing/mapper.rb index 6529cf6f31..aab272f565 100644 --- a/actionpack/lib/action_dispatch/routing/mapper.rb +++ b/actionpack/lib/action_dispatch/routing/mapper.rb @@ -433,12 +433,16 @@ module ActionDispatch end def merge_options_scope(parent, child) - (parent || {}).merge(child) + (parent || {}).except(*override_keys(child)).merge(child) end def merge_shallow_scope(parent, child) child ? true : false end + + def override_keys(child) + child.key?(:only) || child.key?(:except) ? [:only, :except] : [] + end end module Resources @@ -446,7 +450,7 @@ module ActionDispatch # a path appended since they fit properly in their scope level. VALID_ON_OPTIONS = [:new, :collection, :member] CANONICAL_ACTIONS = [:index, :create, :new, :show, :update, :destroy] - RESOURCE_OPTIONS = [:as, :controller, :path] + RESOURCE_OPTIONS = [:as, :controller, :path, :only, :except] class Resource #:nodoc: DEFAULT_ACTIONS = [:index, :create, :new, :show, :update, :destroy, :edit] @@ -465,6 +469,16 @@ module ActionDispatch self.class::DEFAULT_ACTIONS end + def actions + if only = @options[:only] + Array(only).map(&:to_sym) + elsif except = @options[:except] + default_actions - Array(except).map(&:to_sym) + else + default_actions + end + end + def name @as || @name end @@ -551,17 +565,17 @@ module ActionDispatch collection_scope do post :create - end if resource_actions.include?(:create) + end if parent_resource.actions.include?(:create) new_scope do get :new - end if resource_actions.include?(:new) + end if parent_resource.actions.include?(:new) member_scope do - get :show if resource_actions.include?(:show) - put :update if resource_actions.include?(:update) - delete :destroy if resource_actions.include?(:destroy) - get :edit if resource_actions.include?(:edit) + get :show if parent_resource.actions.include?(:show) + put :update if parent_resource.actions.include?(:update) + delete :destroy if parent_resource.actions.include?(:destroy) + get :edit if parent_resource.actions.include?(:edit) end end @@ -579,19 +593,19 @@ module ActionDispatch yield if block_given? collection_scope do - get :index if resource_actions.include?(:index) - post :create if resource_actions.include?(:create) + get :index if parent_resource.actions.include?(:index) + post :create if parent_resource.actions.include?(:create) end new_scope do get :new - end if resource_actions.include?(:new) + end if parent_resource.actions.include?(:new) member_scope do - get :show if resource_actions.include?(:show) - put :update if resource_actions.include?(:update) - delete :destroy if resource_actions.include?(:destroy) - get :edit if resource_actions.include?(:edit) + get :show if parent_resource.actions.include?(:show) + put :update if parent_resource.actions.include?(:update) + delete :destroy if parent_resource.actions.include?(:destroy) + get :edit if parent_resource.actions.include?(:edit) end end @@ -739,16 +753,6 @@ module ActionDispatch @scope[:scope_level_resource] end - def resource_actions - if only = @scope[:options][:only] - Array(only).map(&:to_sym) - elsif except = @scope[:options][:except] - parent_resource.default_actions - Array(except).map(&:to_sym) - else - parent_resource.default_actions - end - end - def apply_common_behavior_for(method, resources, options, &block) if resources.length > 1 resources.each { |r| send(method, r, options, &block) } @@ -763,6 +767,10 @@ module ActionDispatch return true end + unless action_options?(options) + options.merge!(scope_action_options) if scope_action_options? + end + if resource_scope? nested do send(method, resources.pop, options, &block) @@ -773,6 +781,18 @@ module ActionDispatch false end + def action_options?(options) + options[:only] || options[:except] + end + + def scope_action_options? + @scope[:options].is_a?(Hash) && (@scope[:options][:only] || @scope[:options][:except]) + end + + def scope_action_options + @scope[:options].slice(:only, :except) + end + def resource_scope? [:resource, :resources].include?(@scope[:scope_level]) end @@ -899,7 +919,7 @@ module ActionDispatch collection_name = parent_resource.collection_name member_name = parent_resource.member_name name_prefix = "#{name_prefix}_" if name_prefix.present? - end + end case @scope[:scope_level] when :collection diff --git a/actionpack/test/dispatch/routing_test.rb b/actionpack/test/dispatch/routing_test.rb index 463a62cd53..90d05d4a67 100644 --- a/actionpack/test/dispatch/routing_test.rb +++ b/actionpack/test/dispatch/routing_test.rb @@ -352,19 +352,55 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest match ":controller(/:action(/:id))" end - scope :only => :index do - resources :clubs do - resources :players, :only => [:show] - resource :chairman, :only => [:show] + scope :only => [:index, :show] do + namespace :only do + resources :clubs do + resources :players + resource :chairman + end end end - scope :except => [:new, :create, :edit, :update] do - resources :sectors do - resources :companies, :except => :destroy do - resources :divisions, :only => :index + scope :except => [:new, :create, :edit, :update, :destroy] do + namespace :except do + resources :clubs do + resources :players + resource :chairman + end + end + end + + scope :only => :show do + namespace :only do + resources :sectors, :only => :index do + resources :companies do + scope :only => :index do + resources :divisions + end + scope :except => [:show, :update, :destroy] do + resources :departments + end + end + resource :leader + resources :managers, :except => [:show, :update, :destroy] + end + end + end + + scope :except => :index do + namespace :except do + resources :sectors, :except => [:show, :update, :destroy] do + resources :companies do + scope :except => [:show, :update, :destroy] do + resources :divisions + end + scope :only => :index do + resources :departments + end + end + resource :leader + resources :managers, :only => :index end - resource :leader, :except => :destroy end end @@ -1661,72 +1697,179 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest end end - def test_only_option_should_be_overwritten + def test_only_should_be_read_from_scope with_test_routes do - get '/clubs' - assert_equal 'clubs#index', @response.body - assert_equal '/clubs', clubs_path + get '/only/clubs' + assert_equal 'only/clubs#index', @response.body + assert_equal '/only/clubs', only_clubs_path - get '/clubs/1' + get '/only/clubs/1/edit' assert_equal 'Not Found', @response.body - assert_raise(NoMethodError) { club_path(:id => '1') } + assert_raise(NoMethodError) { edit_only_club_path(:id => '1') } + + get '/only/clubs/1/players' + assert_equal 'only/players#index', @response.body + assert_equal '/only/clubs/1/players', only_club_players_path(:club_id => '1') - get '/clubs/1/players' + get '/only/clubs/1/players/2/edit' assert_equal 'Not Found', @response.body - assert_raise(NoMethodError) { club_players_path(:club_id => '1') } + assert_raise(NoMethodError) { edit_only_club_player_path(:club_id => '1', :id => '2') } - get '/clubs/1/players/2' - assert_equal 'players#show', @response.body - assert_equal '/clubs/1/players/2', club_player_path(:club_id => '1', :id => '2') + get '/only/clubs/1/chairman' + assert_equal 'only/chairmen#show', @response.body + assert_equal '/only/clubs/1/chairman', only_club_chairman_path(:club_id => '1') - get '/clubs/1/chairman/new' + get '/only/clubs/1/chairman/edit' assert_equal 'Not Found', @response.body - assert_raise(NoMethodError) { new_club_chairman_path(:club_id => '1') } + assert_raise(NoMethodError) { edit_only_club_chairman_path(:club_id => '1') } + end + end - get '/clubs/1/chairman' - assert_equal 'chairmen#show', @response.body - assert_equal '/clubs/1/chairman', club_chairman_path(:club_id => '1') + def test_except_should_be_read_from_scope + with_test_routes do + get '/except/clubs' + assert_equal 'except/clubs#index', @response.body + assert_equal '/except/clubs', except_clubs_path + + get '/except/clubs/1/edit' + assert_equal 'Not Found', @response.body + assert_raise(NoMethodError) { edit_except_club_path(:id => '1') } + + get '/except/clubs/1/players' + assert_equal 'except/players#index', @response.body + assert_equal '/except/clubs/1/players', except_club_players_path(:club_id => '1') + + get '/except/clubs/1/players/2/edit' + assert_equal 'Not Found', @response.body + assert_raise(NoMethodError) { edit_except_club_player_path(:club_id => '1', :id => '2') } + + get '/except/clubs/1/chairman' + assert_equal 'except/chairmen#show', @response.body + assert_equal '/except/clubs/1/chairman', except_club_chairman_path(:club_id => '1') + + get '/except/clubs/1/chairman/edit' + assert_equal 'Not Found', @response.body + assert_raise(NoMethodError) { edit_except_club_chairman_path(:club_id => '1') } end end - def test_except_option_should_be_overwritten + def test_only_option_should_override_scope with_test_routes do - get '/sectors' - assert_equal 'sectors#index', @response.body - assert_equal '/sectors', sectors_path + get '/only/sectors' + assert_equal 'only/sectors#index', @response.body + assert_equal '/only/sectors', only_sectors_path - get '/sectors/1/edit' + get '/only/sectors/1' assert_equal 'Not Found', @response.body - assert_raise(NoMethodError) { edit_sector_path(:id => '1') } + assert_raise(NoMethodError) { only_sector_path(:id => '1') } + end + end + + def test_only_option_should_not_inherit + with_test_routes do + get '/only/sectors/1/companies/2' + assert_equal 'only/companies#show', @response.body + assert_equal '/only/sectors/1/companies/2', only_sector_company_path(:sector_id => '1', :id => '2') - delete '/sectors/1' - assert_equal 'sectors#destroy', @response.body + get '/only/sectors/1/leader' + assert_equal 'only/leaders#show', @response.body + assert_equal '/only/sectors/1/leader', only_sector_leader_path(:sector_id => '1') + end + end - get '/sectors/1/companies/new' - assert_equal 'companies#new', @response.body - assert_equal '/sectors/1/companies/new', new_sector_company_path(:sector_id => '1') + def test_except_option_should_override_scope + with_test_routes do + get '/except/sectors' + assert_equal 'except/sectors#index', @response.body + assert_equal '/except/sectors', except_sectors_path - delete '/sectors/1/companies/1' + get '/except/sectors/1' assert_equal 'Not Found', @response.body + assert_raise(NoMethodError) { except_sector_path(:id => '1') } + end + end + + def test_except_option_should_not_inherit + with_test_routes do + get '/except/sectors/1/companies/2' + assert_equal 'except/companies#show', @response.body + assert_equal '/except/sectors/1/companies/2', except_sector_company_path(:sector_id => '1', :id => '2') + + get '/except/sectors/1/leader' + assert_equal 'except/leaders#show', @response.body + assert_equal '/except/sectors/1/leader', except_sector_leader_path(:sector_id => '1') + end + end + + def test_except_option_should_override_scoped_only + with_test_routes do + get '/only/sectors/1/managers' + assert_equal 'only/managers#index', @response.body + assert_equal '/only/sectors/1/managers', only_sector_managers_path(:sector_id => '1') + + get '/only/sectors/1/managers/2' + assert_equal 'Not Found', @response.body + assert_raise(NoMethodError) { only_sector_manager_path(:sector_id => '1', :id => '2') } + end + end + + def test_only_option_should_override_scoped_except + with_test_routes do + get '/except/sectors/1/managers' + assert_equal 'except/managers#index', @response.body + assert_equal '/except/sectors/1/managers', except_sector_managers_path(:sector_id => '1') + + get '/except/sectors/1/managers/2' + assert_equal 'Not Found', @response.body + assert_raise(NoMethodError) { except_sector_manager_path(:sector_id => '1', :id => '2') } + end + end + + def test_only_scope_should_override_parent_scope + with_test_routes do + get '/only/sectors/1/companies/2/divisions' + assert_equal 'only/divisions#index', @response.body + assert_equal '/only/sectors/1/companies/2/divisions', only_sector_company_divisions_path(:sector_id => '1', :company_id => '2') + + get '/only/sectors/1/companies/2/divisions/3' + assert_equal 'Not Found', @response.body + assert_raise(NoMethodError) { only_sector_company_division_path(:sector_id => '1', :company_id => '2', :id => '3') } + end + end + + def test_except_scope_should_override_parent_scope + with_test_routes do + get '/except/sectors/1/companies/2/divisions' + assert_equal 'except/divisions#index', @response.body + assert_equal '/except/sectors/1/companies/2/divisions', except_sector_company_divisions_path(:sector_id => '1', :company_id => '2') + + get '/except/sectors/1/companies/2/divisions/3' + assert_equal 'Not Found', @response.body + assert_raise(NoMethodError) { except_sector_company_division_path(:sector_id => '1', :company_id => '2', :id => '3') } + end + end - get '/sectors/1/leader/new' - assert_equal 'leaders#new', @response.body - assert_equal '/sectors/1/leader/new', new_sector_leader_path(:sector_id => '1') + def test_except_scope_should_override_parent_only_scope + with_test_routes do + get '/only/sectors/1/companies/2/departments' + assert_equal 'only/departments#index', @response.body + assert_equal '/only/sectors/1/companies/2/departments', only_sector_company_departments_path(:sector_id => '1', :company_id => '2') - delete '/sectors/1/leader' + get '/only/sectors/1/companies/2/departments/3' assert_equal 'Not Found', @response.body + assert_raise(NoMethodError) { only_sector_company_department_path(:sector_id => '1', :company_id => '2', :id => '3') } end end - def test_only_option_should_overwrite_except_option + def test_only_scope_should_override_parent_except_scope with_test_routes do - get '/sectors/1/companies/2/divisions' - assert_equal 'divisions#index', @response.body - assert_equal '/sectors/1/companies/2/divisions', sector_company_divisions_path(:sector_id => '1', :company_id => '2') + get '/except/sectors/1/companies/2/departments' + assert_equal 'except/departments#index', @response.body + assert_equal '/except/sectors/1/companies/2/departments', except_sector_company_departments_path(:sector_id => '1', :company_id => '2') - get '/sectors/1/companies/2/divisions/3' + get '/except/sectors/1/companies/2/departments/3' assert_equal 'Not Found', @response.body - assert_raise(NoMethodError) { sector_company_division_path(:sector_id => '1', :company_id => '2', :id => '3') } + assert_raise(NoMethodError) { except_sector_company_department_path(:sector_id => '1', :company_id => '2', :id => '3') } end end -- cgit v1.2.3 From b802a0d4c72fbd605b92e9f403c9b8765a6e480c Mon Sep 17 00:00:00 2001 From: Andrew White Date: Tue, 6 Jul 2010 22:20:06 +0100 Subject: When a dynamic :controller segment is present in the path add a Regexp constraint that allow matching on multiple path segments. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Using a namespace block isn't compatible with dynamic routes so we raise an ArgumentError if we detect a :module present in the scope. [#5052 state:resolved] Signed-off-by: José Valim --- actionpack/lib/action_dispatch/routing/mapper.rb | 25 +++++++++++---- .../lib/action_dispatch/routing/route_set.rb | 6 ++-- actionpack/test/dispatch/routing_test.rb | 36 +++++++++++++++------- 3 files changed, 46 insertions(+), 21 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_dispatch/routing/mapper.rb b/actionpack/lib/action_dispatch/routing/mapper.rb index aab272f565..430f6fc5a3 100644 --- a/actionpack/lib/action_dispatch/routing/mapper.rb +++ b/actionpack/lib/action_dispatch/routing/mapper.rb @@ -65,6 +65,16 @@ module ActionDispatch end 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 + path = normalize_path(path) path_without_format = path.sub(/\(\.:format\)$/, '') @@ -93,7 +103,7 @@ module ActionDispatch def app Constraints.new( - to.respond_to?(:call) ? to : Routing::RouteSet::Dispatcher.new(:defaults => defaults, :module => @scope[:module]), + to.respond_to?(:call) ? to : Routing::RouteSet::Dispatcher.new(:defaults => defaults), blocks, @set.request_class ) @@ -135,8 +145,11 @@ module ActionDispatch defaults[:controller] ||= default_controller defaults[:action] ||= default_action - defaults.delete(:controller) if defaults[:controller].blank? - defaults.delete(:action) if defaults[:action].blank? + defaults.delete(:controller) if defaults[:controller].blank? || defaults[:controller].is_a?(Regexp) + defaults.delete(:action) if defaults[:action].blank? || defaults[:action].is_a?(Regexp) + + defaults[:controller] = defaults[:controller].to_s if defaults.key?(:controller) + defaults[:action] = defaults[:action].to_s if defaults.key?(:action) if defaults[:controller].blank? && segment_keys.exclude?("controller") raise ArgumentError, "missing :controller" @@ -185,15 +198,15 @@ module ActionDispatch def default_controller if @options[:controller] - @options[:controller].to_s + @options[:controller] elsif @scope[:controller] - @scope[:controller].to_s + @scope[:controller] end end def default_action if @options[:action] - @options[:action].to_s + @options[:action] end end end diff --git a/actionpack/lib/action_dispatch/routing/route_set.rb b/actionpack/lib/action_dispatch/routing/route_set.rb index 01a068a9f2..1b1a221c60 100644 --- a/actionpack/lib/action_dispatch/routing/route_set.rb +++ b/actionpack/lib/action_dispatch/routing/route_set.rb @@ -14,7 +14,6 @@ module ActionDispatch def initialize(options={}) @defaults = options[:defaults] @glob_param = options.delete(:glob) - @module = options.delete(:module) @controllers = {} end @@ -39,12 +38,11 @@ module ActionDispatch # we should raise an error in case it's not found, because it usually means # an user error. However, if the controller was retrieved through a dynamic # segment, as in :controller(/:action), we should simply return nil and - # delegate the control back to Rack cascade. Besides, if this is not a default + # delegate the control back to Rack cascade. Besides, if this is not a default # controller, it means we should respect the @scope[:module] parameter. def controller(params, default_controller=true) if params && params.key?(:controller) - controller_param = @module && !default_controller ? - "#{@module}/#{params[:controller]}" : params[:controller] + controller_param = params[:controller] controller_reference(controller_param) end rescue NameError => e diff --git a/actionpack/test/dispatch/routing_test.rb b/actionpack/test/dispatch/routing_test.rb index 90d05d4a67..2a014bf976 100644 --- a/actionpack/test/dispatch/routing_test.rb +++ b/actionpack/test/dispatch/routing_test.rb @@ -323,7 +323,7 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest end end - match "whatever/:controller(/:action(/:id))" + match "whatever/:controller(/:action(/:id))", :id => /\d+/ resource :profile do get :settings @@ -349,7 +349,6 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest namespace :private do root :to => redirect('/private/index') match "index", :to => 'private#index' - match ":controller(/:action(/:id))" end scope :only => [:index, :show] do @@ -527,15 +526,14 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest end def test_namespace_with_controller_segment - with_test_routes do - get '/private/foo' - assert_equal 'private/foo#index', @response.body - - get '/private/foo/bar' - assert_equal 'private/foo#bar', @response.body - - get '/private/foo/bar/1' - assert_equal 'private/foo#bar', @response.body + assert_raise(ArgumentError) do + self.class.stub_controllers do |routes| + routes.draw do + namespace :admin do + match '/:controller(/:action(/:id(.:format)))' + end + end + end end end @@ -1354,6 +1352,22 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest end end + def test_url_generator_for_namespaced_generic_route + with_test_routes do + get 'whatever/foo/bar/show' + assert_equal 'foo/bar#show', @response.body + + get 'whatever/foo/bar/show/1' + assert_equal 'foo/bar#show', @response.body + + assert_equal 'http://www.example.com/whatever/foo/bar/show', + url_for(:controller => "foo/bar", :action => "show") + + assert_equal 'http://www.example.com/whatever/foo/bar/show/1', + url_for(:controller => "foo/bar", :action => "show", :id => '1') + end + end + def test_assert_recognizes_account_overview with_test_routes do assert_recognizes({:controller => "account", :action => "overview"}, "/account/overview") -- cgit v1.2.3 From 81f398b804a68c8090c0fbea20f50c0ae253b708 Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Wed, 7 Jul 2010 12:03:01 -0700 Subject: Fix setting helpers_path to a string or pathname --- actionpack/lib/action_controller/metal/helpers.rb | 5 +++-- actionpack/test/abstract/helper_test.rb | 2 +- actionpack/test/controller/helper_test.rb | 6 +++--- 3 files changed, 7 insertions(+), 6 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_controller/metal/helpers.rb b/actionpack/lib/action_controller/metal/helpers.rb index 89201fb5ee..e0bc47318a 100644 --- a/actionpack/lib/action_controller/metal/helpers.rb +++ b/actionpack/lib/action_controller/metal/helpers.rb @@ -1,3 +1,4 @@ +require 'active_support/core_ext/array/wrap' require 'active_support/core_ext/class/attribute' module ActionController @@ -64,7 +65,7 @@ module ActionController def helpers_dir=(value) ActiveSupport::Deprecation.warn "helpers_dir= is deprecated, use helpers_path= instead", caller - self.helpers_path = Array(value) + self.helpers_path = Array.wrap(value) end # Declares helper accessors for controller attributes. For example, the @@ -103,7 +104,7 @@ module ActionController # Extract helper names from files in app/helpers/**/*_helper.rb def all_application_helpers helpers = [] - helpers_path.each do |path| + Array.wrap(helpers_path).each do |path| extract = /^#{Regexp.quote(path.to_s)}\/?(.*)_helper.rb$/ helpers += Dir["#{path}/**/*_helper.rb"].map { |file| file.sub(extract, '\1') } end diff --git a/actionpack/test/abstract/helper_test.rb b/actionpack/test/abstract/helper_test.rb index 0cdf5c2298..15c27501f2 100644 --- a/actionpack/test/abstract/helper_test.rb +++ b/actionpack/test/abstract/helper_test.rb @@ -1,6 +1,6 @@ require 'abstract_unit' -ActionController::Base.helpers_path = [File.dirname(__FILE__) + '/../fixtures/helpers'] +ActionController::Base.helpers_path = File.expand_path('../../fixtures/helpers', __FILE__) module AbstractController module Testing diff --git a/actionpack/test/controller/helper_test.rb b/actionpack/test/controller/helper_test.rb index c9a6e5dd45..9b9657929f 100644 --- a/actionpack/test/controller/helper_test.rb +++ b/actionpack/test/controller/helper_test.rb @@ -1,7 +1,7 @@ require 'abstract_unit' require 'active_support/core_ext/kernel/reporting' -ActionController::Base.helpers_path = [File.dirname(__FILE__) + '/../fixtures/helpers'] +ActionController::Base.helpers_path = File.expand_path('../../fixtures/helpers', __FILE__) module Fun class GamesController < ActionController::Base @@ -106,7 +106,7 @@ class HelperTest < ActiveSupport::TestCase end def test_all_helpers_with_alternate_helper_dir - @controller_class.helpers_path = [File.dirname(__FILE__) + '/../fixtures/alternate_helpers'] + @controller_class.helpers_path = File.expand_path('../../fixtures/alternate_helpers', __FILE__) # Reload helpers @controller_class._helpers = Module.new @@ -143,7 +143,7 @@ class HelperTest < ActiveSupport::TestCase assert_equal ["some/foo/bar"], ActionController::Base.helpers_dir end ensure - ActionController::Base.helpers_path = [File.dirname(__FILE__) + '/../fixtures/helpers'] + ActionController::Base.helpers_path = File.expand_path('../../fixtures/helpers', __FILE__) end private -- cgit v1.2.3 From dc364fdc595405aa3d5735e60d46ad3f9544a65b Mon Sep 17 00:00:00 2001 From: Rohit Arondekar Date: Wed, 7 Jul 2010 22:15:15 -0700 Subject: API Docs: Fixes to the Routing docs --- actionpack/lib/action_dispatch/routing.rb | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/action_dispatch/routing.rb b/actionpack/lib/action_dispatch/routing.rb index 89007fab74..c664fb0bc2 100644 --- a/actionpack/lib/action_dispatch/routing.rb +++ b/actionpack/lib/action_dispatch/routing.rb @@ -31,7 +31,7 @@ module ActionDispatch # Think of creating routes as drawing a map for your requests. The map tells # them where to go based on some predefined pattern: # - # AppName::Applications.routes.draw do |map| + # AppName::Application.routes.draw do |map| # Pattern 1 tells some request to go to one place # Pattern 2 tell them to go to another # ... @@ -62,7 +62,7 @@ module ActionDispatch # # redirect_to show_item_path(:id => 25) # - # Use root as a shorthand to name a route for the root path "". + # Use root as a shorthand to name a route for the root path "/". # # # In routes.rb # root :to => 'blogs#index' @@ -72,7 +72,7 @@ module ActionDispatch # # # and provide these named routes # root_url # => 'http://www.example.com/' - # root_path # => '' + # root_path # => '/' # # Note: when using +controller+, the route is simply named after the # method you call on the block parameter rather than map. @@ -91,9 +91,7 @@ module ActionDispatch # # Routes can generate pretty URLs. For example: # - # match '/articles/:year/:month/:day', :constraints => { - # :controller => 'articles', - # :action => 'find_by_date', + # match '/articles/:year/:month/:day' => 'articles#find_by_id', :constraints => { # :year => /\d{4}/, # :month => /\d{1,2}/, # :day => /\d{1,2}/ -- cgit v1.2.3