From ce7d5fb2e6ffa9ec323510aaff51f10b15f1649a Mon Sep 17 00:00:00 2001 From: Andrew White Date: Wed, 20 Jan 2016 15:03:10 +0000 Subject: Add support for defining custom url helpers in routes.rb Allow the definition of custom url helpers that will be available automatically wherever standard url helpers are available. The current solution is to create helper methods in ApplicationHelper or some other helper module and this isn't a great solution since the url helper module can be called directly or included in another class which doesn't include the normal helper modules. Reference #22512. --- .../dispatch/routing/custom_url_helpers_test.rb | 121 +++++++++++++++++++++ 1 file changed, 121 insertions(+) create mode 100644 actionpack/test/dispatch/routing/custom_url_helpers_test.rb (limited to 'actionpack/test/dispatch/routing/custom_url_helpers_test.rb') diff --git a/actionpack/test/dispatch/routing/custom_url_helpers_test.rb b/actionpack/test/dispatch/routing/custom_url_helpers_test.rb new file mode 100644 index 0000000000..ec0484a3ba --- /dev/null +++ b/actionpack/test/dispatch/routing/custom_url_helpers_test.rb @@ -0,0 +1,121 @@ +require "abstract_unit" + +class TestCustomUrlHelpers < ActionDispatch::IntegrationTest + class Linkable + attr_reader :id + + def initialize(id) + @id = id + end + + def linkable_type + self.class.name.demodulize.underscore + end + end + + class Category < Linkable; end + class Collection < Linkable; end + class Product < Linkable; end + + Routes = ActionDispatch::Routing::RouteSet.new + Routes.draw do + default_url_options host: "www.example.com" + + root to: "pages#index" + get "/basket", to: "basket#show", as: :basket + + resources :categories, :collections, :products + + namespace :admin do + get "/dashboard", to: "dashboard#index" + end + + url_helper(:website) { "http://www.rubyonrails.org" } + url_helper(:linkable) { |linkable| [:"#{linkable.linkable_type}", { id: linkable.id }] } + url_helper(:params) { |params| params } + url_helper(:symbol) { :basket } + url_helper(:hash) { { controller: "basket", action: "show" } } + url_helper(:array) { [:admin, :dashboard] } + url_helper(:options) { |options| [:products, options] } + url_helper(:defaults, size: 10) { |options| [:products, options] } + end + + APP = build_app Routes + + def app + APP + end + + include Routes.url_helpers + + def setup + @category = Category.new("1") + @collection = Collection.new("2") + @product = Product.new("3") + @path_params = { "controller" => "pages", "action" => "index" } + @unsafe_params = ActionController::Parameters.new(@path_params) + @safe_params = ActionController::Parameters.new(@path_params).permit(:controller, :action) + end + + def test_custom_path_helper + assert_equal "http://www.rubyonrails.org", website_path + assert_equal "http://www.rubyonrails.org", Routes.url_helpers.website_path + + assert_equal "/categories/1", linkable_path(@category) + assert_equal "/categories/1", Routes.url_helpers.linkable_path(@category) + assert_equal "/collections/2", linkable_path(@collection) + assert_equal "/collections/2", Routes.url_helpers.linkable_path(@collection) + assert_equal "/products/3", linkable_path(@product) + assert_equal "/products/3", Routes.url_helpers.linkable_path(@product) + + assert_equal "/", params_path(@safe_params) + assert_equal "/", Routes.url_helpers.params_path(@safe_params) + assert_raises(ArgumentError) { params_path(@unsafe_params) } + assert_raises(ArgumentError) { Routes.url_helpers.params_path(@unsafe_params) } + + assert_equal "/basket", symbol_path + assert_equal "/basket", Routes.url_helpers.symbol_path + assert_equal "/basket", hash_path + assert_equal "/basket", Routes.url_helpers.hash_path + assert_equal "/admin/dashboard", array_path + assert_equal "/admin/dashboard", Routes.url_helpers.array_path + + assert_equal "/products?page=2", options_path(page: 2) + assert_equal "/products?page=2", Routes.url_helpers.options_path(page: 2) + assert_equal "/products?size=10", defaults_path + assert_equal "/products?size=10", Routes.url_helpers.defaults_path + assert_equal "/products?size=20", defaults_path(size: 20) + assert_equal "/products?size=20", Routes.url_helpers.defaults_path(size: 20) + end + + def test_custom_url_helper + assert_equal "http://www.rubyonrails.org", website_url + assert_equal "http://www.rubyonrails.org", Routes.url_helpers.website_url + + assert_equal "http://www.example.com/categories/1", linkable_url(@category) + assert_equal "http://www.example.com/categories/1", Routes.url_helpers.linkable_url(@category) + assert_equal "http://www.example.com/collections/2", linkable_url(@collection) + assert_equal "http://www.example.com/collections/2", Routes.url_helpers.linkable_url(@collection) + assert_equal "http://www.example.com/products/3", linkable_url(@product) + assert_equal "http://www.example.com/products/3", Routes.url_helpers.linkable_url(@product) + + assert_equal "http://www.example.com/", params_url(@safe_params) + assert_equal "http://www.example.com/", Routes.url_helpers.params_url(@safe_params) + assert_raises(ArgumentError) { params_url(@unsafe_params) } + assert_raises(ArgumentError) { Routes.url_helpers.params_url(@unsafe_params) } + + assert_equal "http://www.example.com/basket", symbol_url + assert_equal "http://www.example.com/basket", Routes.url_helpers.symbol_url + assert_equal "http://www.example.com/basket", hash_url + assert_equal "http://www.example.com/basket", Routes.url_helpers.hash_url + assert_equal "/admin/dashboard", array_path + assert_equal "/admin/dashboard", Routes.url_helpers.array_path + + assert_equal "http://www.example.com/products?page=2", options_url(page: 2) + assert_equal "http://www.example.com/products?page=2", Routes.url_helpers.options_url(page: 2) + assert_equal "http://www.example.com/products?size=10", defaults_url + assert_equal "http://www.example.com/products?size=10", Routes.url_helpers.defaults_url + assert_equal "http://www.example.com/products?size=20", defaults_url(size: 20) + assert_equal "http://www.example.com/products?size=20", Routes.url_helpers.defaults_url(size: 20) + end +end -- cgit v1.2.3 From 47a27e8950ad00654e2ba0420cefd87269e08055 Mon Sep 17 00:00:00 2001 From: Andrew White Date: Tue, 23 Feb 2016 09:59:33 +0000 Subject: Rename url_helper to direct --- .../dispatch/routing/custom_url_helpers_test.rb | 24 +++++++++++----------- 1 file changed, 12 insertions(+), 12 deletions(-) (limited to 'actionpack/test/dispatch/routing/custom_url_helpers_test.rb') diff --git a/actionpack/test/dispatch/routing/custom_url_helpers_test.rb b/actionpack/test/dispatch/routing/custom_url_helpers_test.rb index ec0484a3ba..a55ee8e9b0 100644 --- a/actionpack/test/dispatch/routing/custom_url_helpers_test.rb +++ b/actionpack/test/dispatch/routing/custom_url_helpers_test.rb @@ -30,14 +30,14 @@ class TestCustomUrlHelpers < ActionDispatch::IntegrationTest get "/dashboard", to: "dashboard#index" end - url_helper(:website) { "http://www.rubyonrails.org" } - url_helper(:linkable) { |linkable| [:"#{linkable.linkable_type}", { id: linkable.id }] } - url_helper(:params) { |params| params } - url_helper(:symbol) { :basket } - url_helper(:hash) { { controller: "basket", action: "show" } } - url_helper(:array) { [:admin, :dashboard] } - url_helper(:options) { |options| [:products, options] } - url_helper(:defaults, size: 10) { |options| [:products, options] } + direct(:website) { "http://www.rubyonrails.org" } + direct(:linkable) { |linkable| [:"#{linkable.linkable_type}", { id: linkable.id }] } + direct(:params) { |params| params } + direct(:symbol) { :basket } + direct(:hash) { { controller: "basket", action: "show" } } + direct(:array) { [:admin, :dashboard] } + direct(:options) { |options| [:products, options] } + direct(:defaults, size: 10) { |options| [:products, options] } end APP = build_app Routes @@ -57,7 +57,7 @@ class TestCustomUrlHelpers < ActionDispatch::IntegrationTest @safe_params = ActionController::Parameters.new(@path_params).permit(:controller, :action) end - def test_custom_path_helper + def test_direct_paths assert_equal "http://www.rubyonrails.org", website_path assert_equal "http://www.rubyonrails.org", Routes.url_helpers.website_path @@ -88,7 +88,7 @@ class TestCustomUrlHelpers < ActionDispatch::IntegrationTest assert_equal "/products?size=20", Routes.url_helpers.defaults_path(size: 20) end - def test_custom_url_helper + def test_direct_urls assert_equal "http://www.rubyonrails.org", website_url assert_equal "http://www.rubyonrails.org", Routes.url_helpers.website_url @@ -108,8 +108,8 @@ class TestCustomUrlHelpers < ActionDispatch::IntegrationTest assert_equal "http://www.example.com/basket", Routes.url_helpers.symbol_url assert_equal "http://www.example.com/basket", hash_url assert_equal "http://www.example.com/basket", Routes.url_helpers.hash_url - assert_equal "/admin/dashboard", array_path - assert_equal "/admin/dashboard", Routes.url_helpers.array_path + assert_equal "http://www.example.com/admin/dashboard", array_url + assert_equal "http://www.example.com/admin/dashboard", Routes.url_helpers.array_url assert_equal "http://www.example.com/products?page=2", options_url(page: 2) assert_equal "http://www.example.com/products?page=2", Routes.url_helpers.options_url(page: 2) -- cgit v1.2.3 From e96da0a7beb483ed5e8a8096ff67b09ecc5ca7a1 Mon Sep 17 00:00:00 2001 From: Andrew White Date: Mon, 20 Feb 2017 13:54:06 +0000 Subject: Only accept symbols and strings for Mapper#direct --- .../test/dispatch/routing/custom_url_helpers_test.rb | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'actionpack/test/dispatch/routing/custom_url_helpers_test.rb') diff --git a/actionpack/test/dispatch/routing/custom_url_helpers_test.rb b/actionpack/test/dispatch/routing/custom_url_helpers_test.rb index a55ee8e9b0..bf4b323cf0 100644 --- a/actionpack/test/dispatch/routing/custom_url_helpers_test.rb +++ b/actionpack/test/dispatch/routing/custom_url_helpers_test.rb @@ -31,6 +31,7 @@ class TestCustomUrlHelpers < ActionDispatch::IntegrationTest end direct(:website) { "http://www.rubyonrails.org" } + direct("string") { "http://www.rubyonrails.org" } direct(:linkable) { |linkable| [:"#{linkable.linkable_type}", { id: linkable.id }] } direct(:params) { |params| params } direct(:symbol) { :basket } @@ -61,6 +62,9 @@ class TestCustomUrlHelpers < ActionDispatch::IntegrationTest assert_equal "http://www.rubyonrails.org", website_path assert_equal "http://www.rubyonrails.org", Routes.url_helpers.website_path + assert_equal "http://www.rubyonrails.org", string_path + assert_equal "http://www.rubyonrails.org", Routes.url_helpers.string_path + assert_equal "/categories/1", linkable_path(@category) assert_equal "/categories/1", Routes.url_helpers.linkable_path(@category) assert_equal "/collections/2", linkable_path(@collection) @@ -92,6 +96,9 @@ class TestCustomUrlHelpers < ActionDispatch::IntegrationTest assert_equal "http://www.rubyonrails.org", website_url assert_equal "http://www.rubyonrails.org", Routes.url_helpers.website_url + assert_equal "http://www.rubyonrails.org", string_url + assert_equal "http://www.rubyonrails.org", Routes.url_helpers.string_url + assert_equal "http://www.example.com/categories/1", linkable_url(@category) assert_equal "http://www.example.com/categories/1", Routes.url_helpers.linkable_url(@category) assert_equal "http://www.example.com/collections/2", linkable_url(@collection) @@ -118,4 +125,14 @@ class TestCustomUrlHelpers < ActionDispatch::IntegrationTest assert_equal "http://www.example.com/products?size=20", defaults_url(size: 20) assert_equal "http://www.example.com/products?size=20", Routes.url_helpers.defaults_url(size: 20) end + + def test_raises_argument_error + routes = ActionDispatch::Routing::RouteSet.new + + assert_raises ArgumentError do + routes.draw do + direct(1) { "http://www.rubyonrails.org" } + end + end + end end -- cgit v1.2.3 From d67e2520289745913e7bab9a852c86b99245f738 Mon Sep 17 00:00:00 2001 From: Andrew White Date: Mon, 20 Feb 2017 14:37:00 +0000 Subject: Add test for calling a url helper in Mapper#direct --- actionpack/test/dispatch/routing/custom_url_helpers_test.rb | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'actionpack/test/dispatch/routing/custom_url_helpers_test.rb') diff --git a/actionpack/test/dispatch/routing/custom_url_helpers_test.rb b/actionpack/test/dispatch/routing/custom_url_helpers_test.rb index bf4b323cf0..22e8bbf21e 100644 --- a/actionpack/test/dispatch/routing/custom_url_helpers_test.rb +++ b/actionpack/test/dispatch/routing/custom_url_helpers_test.rb @@ -32,6 +32,7 @@ class TestCustomUrlHelpers < ActionDispatch::IntegrationTest direct(:website) { "http://www.rubyonrails.org" } direct("string") { "http://www.rubyonrails.org" } + direct(:helper) { basket_url } direct(:linkable) { |linkable| [:"#{linkable.linkable_type}", { id: linkable.id }] } direct(:params) { |params| params } direct(:symbol) { :basket } @@ -65,6 +66,9 @@ class TestCustomUrlHelpers < ActionDispatch::IntegrationTest assert_equal "http://www.rubyonrails.org", string_path assert_equal "http://www.rubyonrails.org", Routes.url_helpers.string_path + assert_equal "http://www.example.com/basket", helper_url + assert_equal "http://www.example.com/basket", Routes.url_helpers.helper_url + assert_equal "/categories/1", linkable_path(@category) assert_equal "/categories/1", Routes.url_helpers.linkable_path(@category) assert_equal "/collections/2", linkable_path(@collection) @@ -99,6 +103,9 @@ class TestCustomUrlHelpers < ActionDispatch::IntegrationTest assert_equal "http://www.rubyonrails.org", string_url assert_equal "http://www.rubyonrails.org", Routes.url_helpers.string_url + assert_equal "http://www.example.com/basket", helper_url + assert_equal "http://www.example.com/basket", Routes.url_helpers.helper_url + assert_equal "http://www.example.com/categories/1", linkable_url(@category) assert_equal "http://www.example.com/categories/1", Routes.url_helpers.linkable_url(@category) assert_equal "http://www.example.com/collections/2", linkable_url(@collection) -- cgit v1.2.3 From 3bf47b018be912fc7946342315e67b2ac6c33eaf Mon Sep 17 00:00:00 2001 From: Andrew White Date: Mon, 20 Feb 2017 20:22:42 +0000 Subject: Add custom polymorphic mapping Allow the use of `direct` to specify custom mappings for polymorphic_url, e.g: resource :basket direct(class: "Basket") { [:basket] } This will then generate the following: >> link_to "Basket", @basket => Basket More importantly it will generate the correct url when used with `form_for`. Fixes #1769. --- .../dispatch/routing/custom_url_helpers_test.rb | 145 --------------------- 1 file changed, 145 deletions(-) delete mode 100644 actionpack/test/dispatch/routing/custom_url_helpers_test.rb (limited to 'actionpack/test/dispatch/routing/custom_url_helpers_test.rb') diff --git a/actionpack/test/dispatch/routing/custom_url_helpers_test.rb b/actionpack/test/dispatch/routing/custom_url_helpers_test.rb deleted file mode 100644 index 22e8bbf21e..0000000000 --- a/actionpack/test/dispatch/routing/custom_url_helpers_test.rb +++ /dev/null @@ -1,145 +0,0 @@ -require "abstract_unit" - -class TestCustomUrlHelpers < ActionDispatch::IntegrationTest - class Linkable - attr_reader :id - - def initialize(id) - @id = id - end - - def linkable_type - self.class.name.demodulize.underscore - end - end - - class Category < Linkable; end - class Collection < Linkable; end - class Product < Linkable; end - - Routes = ActionDispatch::Routing::RouteSet.new - Routes.draw do - default_url_options host: "www.example.com" - - root to: "pages#index" - get "/basket", to: "basket#show", as: :basket - - resources :categories, :collections, :products - - namespace :admin do - get "/dashboard", to: "dashboard#index" - end - - direct(:website) { "http://www.rubyonrails.org" } - direct("string") { "http://www.rubyonrails.org" } - direct(:helper) { basket_url } - direct(:linkable) { |linkable| [:"#{linkable.linkable_type}", { id: linkable.id }] } - direct(:params) { |params| params } - direct(:symbol) { :basket } - direct(:hash) { { controller: "basket", action: "show" } } - direct(:array) { [:admin, :dashboard] } - direct(:options) { |options| [:products, options] } - direct(:defaults, size: 10) { |options| [:products, options] } - end - - APP = build_app Routes - - def app - APP - end - - include Routes.url_helpers - - def setup - @category = Category.new("1") - @collection = Collection.new("2") - @product = Product.new("3") - @path_params = { "controller" => "pages", "action" => "index" } - @unsafe_params = ActionController::Parameters.new(@path_params) - @safe_params = ActionController::Parameters.new(@path_params).permit(:controller, :action) - end - - def test_direct_paths - assert_equal "http://www.rubyonrails.org", website_path - assert_equal "http://www.rubyonrails.org", Routes.url_helpers.website_path - - assert_equal "http://www.rubyonrails.org", string_path - assert_equal "http://www.rubyonrails.org", Routes.url_helpers.string_path - - assert_equal "http://www.example.com/basket", helper_url - assert_equal "http://www.example.com/basket", Routes.url_helpers.helper_url - - assert_equal "/categories/1", linkable_path(@category) - assert_equal "/categories/1", Routes.url_helpers.linkable_path(@category) - assert_equal "/collections/2", linkable_path(@collection) - assert_equal "/collections/2", Routes.url_helpers.linkable_path(@collection) - assert_equal "/products/3", linkable_path(@product) - assert_equal "/products/3", Routes.url_helpers.linkable_path(@product) - - assert_equal "/", params_path(@safe_params) - assert_equal "/", Routes.url_helpers.params_path(@safe_params) - assert_raises(ArgumentError) { params_path(@unsafe_params) } - assert_raises(ArgumentError) { Routes.url_helpers.params_path(@unsafe_params) } - - assert_equal "/basket", symbol_path - assert_equal "/basket", Routes.url_helpers.symbol_path - assert_equal "/basket", hash_path - assert_equal "/basket", Routes.url_helpers.hash_path - assert_equal "/admin/dashboard", array_path - assert_equal "/admin/dashboard", Routes.url_helpers.array_path - - assert_equal "/products?page=2", options_path(page: 2) - assert_equal "/products?page=2", Routes.url_helpers.options_path(page: 2) - assert_equal "/products?size=10", defaults_path - assert_equal "/products?size=10", Routes.url_helpers.defaults_path - assert_equal "/products?size=20", defaults_path(size: 20) - assert_equal "/products?size=20", Routes.url_helpers.defaults_path(size: 20) - end - - def test_direct_urls - assert_equal "http://www.rubyonrails.org", website_url - assert_equal "http://www.rubyonrails.org", Routes.url_helpers.website_url - - assert_equal "http://www.rubyonrails.org", string_url - assert_equal "http://www.rubyonrails.org", Routes.url_helpers.string_url - - assert_equal "http://www.example.com/basket", helper_url - assert_equal "http://www.example.com/basket", Routes.url_helpers.helper_url - - assert_equal "http://www.example.com/categories/1", linkable_url(@category) - assert_equal "http://www.example.com/categories/1", Routes.url_helpers.linkable_url(@category) - assert_equal "http://www.example.com/collections/2", linkable_url(@collection) - assert_equal "http://www.example.com/collections/2", Routes.url_helpers.linkable_url(@collection) - assert_equal "http://www.example.com/products/3", linkable_url(@product) - assert_equal "http://www.example.com/products/3", Routes.url_helpers.linkable_url(@product) - - assert_equal "http://www.example.com/", params_url(@safe_params) - assert_equal "http://www.example.com/", Routes.url_helpers.params_url(@safe_params) - assert_raises(ArgumentError) { params_url(@unsafe_params) } - assert_raises(ArgumentError) { Routes.url_helpers.params_url(@unsafe_params) } - - assert_equal "http://www.example.com/basket", symbol_url - assert_equal "http://www.example.com/basket", Routes.url_helpers.symbol_url - assert_equal "http://www.example.com/basket", hash_url - assert_equal "http://www.example.com/basket", Routes.url_helpers.hash_url - assert_equal "http://www.example.com/admin/dashboard", array_url - assert_equal "http://www.example.com/admin/dashboard", Routes.url_helpers.array_url - - assert_equal "http://www.example.com/products?page=2", options_url(page: 2) - assert_equal "http://www.example.com/products?page=2", Routes.url_helpers.options_url(page: 2) - assert_equal "http://www.example.com/products?size=10", defaults_url - assert_equal "http://www.example.com/products?size=10", Routes.url_helpers.defaults_url - assert_equal "http://www.example.com/products?size=20", defaults_url(size: 20) - assert_equal "http://www.example.com/products?size=20", Routes.url_helpers.defaults_url(size: 20) - end - - def test_raises_argument_error - routes = ActionDispatch::Routing::RouteSet.new - - assert_raises ArgumentError do - routes.draw do - direct(1) { "http://www.rubyonrails.org" } - end - end - end -end -- cgit v1.2.3 From d7c1e62c2cd2969b991bc4a1150b02b27f6d6e3f Mon Sep 17 00:00:00 2001 From: Andrew White Date: Tue, 21 Feb 2017 15:29:10 +0000 Subject: Split direct method into two Use a separate method called `resolve` for the custom polymorphic mapping to clarify the API. --- .../dispatch/routing/custom_url_helpers_test.rb | 291 +++++++++++++++++++++ 1 file changed, 291 insertions(+) create mode 100644 actionpack/test/dispatch/routing/custom_url_helpers_test.rb (limited to 'actionpack/test/dispatch/routing/custom_url_helpers_test.rb') diff --git a/actionpack/test/dispatch/routing/custom_url_helpers_test.rb b/actionpack/test/dispatch/routing/custom_url_helpers_test.rb new file mode 100644 index 0000000000..6d230a2557 --- /dev/null +++ b/actionpack/test/dispatch/routing/custom_url_helpers_test.rb @@ -0,0 +1,291 @@ +require "abstract_unit" + +class TestCustomUrlHelpers < ActionDispatch::IntegrationTest + class Linkable + attr_reader :id + + def initialize(id) + @id = id + end + + def linkable_type + self.class.name.demodulize.underscore + end + end + + class Category < Linkable; end + class Collection < Linkable; end + class Product < Linkable; end + + class Model + extend ActiveModel::Naming + include ActiveModel::Conversion + + attr_reader :id + + def initialize(id = nil) + @id = id + end + + remove_method :model_name + def model_name + @_model_name ||= ActiveModel::Name.new(self.class, nil, self.class.name.demodulize) + end + + def persisted? + false + end + end + + class Basket < Model; end + class User < Model; end + class Video < Model; end + + class Article + attr_reader :id + + def self.name + "Article" + end + + def initialize(id) + @id = id + end + end + + class Page + attr_reader :id + + def self.name + super.demodulize + end + + def initialize(id) + @id = id + end + end + + class CategoryPage < Page; end + class ProductPage < Page; end + + Routes = ActionDispatch::Routing::RouteSet.new + Routes.draw do + default_url_options host: "www.example.com" + + root to: "pages#index" + get "/basket", to: "basket#show", as: :basket + get "/posts/:id", to: "posts#show", as: :post + get "/profile", to: "users#profile", as: :profile + get "/media/:id", to: "media#show", as: :media + get "/pages/:id", to: "pages#show", as: :page + + resources :categories, :collections, :products + + namespace :admin do + get "/dashboard", to: "dashboard#index" + end + + direct(:website) { "http://www.rubyonrails.org" } + direct("string") { "http://www.rubyonrails.org" } + direct(:helper) { basket_url } + direct(:linkable) { |linkable| [:"#{linkable.linkable_type}", { id: linkable.id }] } + direct(:params) { |params| params } + direct(:symbol) { :basket } + direct(:hash) { { controller: "basket", action: "show" } } + direct(:array) { [:admin, :dashboard] } + direct(:options) { |options| [:products, options] } + direct(:defaults, size: 10) { |options| [:products, options] } + + resolve("Article") { |article| [:post, { id: article.id }] } + resolve("Basket") { |basket| [:basket] } + resolve("User", anchor: "details") { |user, options| [:profile, options] } + resolve("Video") { |video| [:media, { id: video.id }] } + resolve(%w[Page CategoryPage ProductPage]) { |page| [:page, { id: page.id }] } + end + + APP = build_app Routes + + def app + APP + end + + include Routes.url_helpers + + def setup + @category = Category.new("1") + @collection = Collection.new("2") + @product = Product.new("3") + @basket = Basket.new + @user = User.new + @video = Video.new("4") + @article = Article.new("5") + @page = Page.new("6") + @category_page = CategoryPage.new("7") + @product_page = ProductPage.new("8") + @path_params = { "controller" => "pages", "action" => "index" } + @unsafe_params = ActionController::Parameters.new(@path_params) + @safe_params = ActionController::Parameters.new(@path_params).permit(:controller, :action) + end + + def test_direct_paths + assert_equal "http://www.rubyonrails.org", website_path + assert_equal "http://www.rubyonrails.org", Routes.url_helpers.website_path + + assert_equal "http://www.rubyonrails.org", string_path + assert_equal "http://www.rubyonrails.org", Routes.url_helpers.string_path + + assert_equal "http://www.example.com/basket", helper_url + assert_equal "http://www.example.com/basket", Routes.url_helpers.helper_url + + assert_equal "/categories/1", linkable_path(@category) + assert_equal "/categories/1", Routes.url_helpers.linkable_path(@category) + assert_equal "/collections/2", linkable_path(@collection) + assert_equal "/collections/2", Routes.url_helpers.linkable_path(@collection) + assert_equal "/products/3", linkable_path(@product) + assert_equal "/products/3", Routes.url_helpers.linkable_path(@product) + + assert_equal "/", params_path(@safe_params) + assert_equal "/", Routes.url_helpers.params_path(@safe_params) + assert_raises(ArgumentError) { params_path(@unsafe_params) } + assert_raises(ArgumentError) { Routes.url_helpers.params_path(@unsafe_params) } + + assert_equal "/basket", symbol_path + assert_equal "/basket", Routes.url_helpers.symbol_path + assert_equal "/basket", hash_path + assert_equal "/basket", Routes.url_helpers.hash_path + assert_equal "/admin/dashboard", array_path + assert_equal "/admin/dashboard", Routes.url_helpers.array_path + + assert_equal "/products?page=2", options_path(page: 2) + assert_equal "/products?page=2", Routes.url_helpers.options_path(page: 2) + assert_equal "/products?size=10", defaults_path + assert_equal "/products?size=10", Routes.url_helpers.defaults_path + assert_equal "/products?size=20", defaults_path(size: 20) + assert_equal "/products?size=20", Routes.url_helpers.defaults_path(size: 20) + end + + def test_direct_urls + assert_equal "http://www.rubyonrails.org", website_url + assert_equal "http://www.rubyonrails.org", Routes.url_helpers.website_url + + assert_equal "http://www.rubyonrails.org", string_url + assert_equal "http://www.rubyonrails.org", Routes.url_helpers.string_url + + assert_equal "http://www.example.com/basket", helper_url + assert_equal "http://www.example.com/basket", Routes.url_helpers.helper_url + + assert_equal "http://www.example.com/categories/1", linkable_url(@category) + assert_equal "http://www.example.com/categories/1", Routes.url_helpers.linkable_url(@category) + assert_equal "http://www.example.com/collections/2", linkable_url(@collection) + assert_equal "http://www.example.com/collections/2", Routes.url_helpers.linkable_url(@collection) + assert_equal "http://www.example.com/products/3", linkable_url(@product) + assert_equal "http://www.example.com/products/3", Routes.url_helpers.linkable_url(@product) + + assert_equal "http://www.example.com/", params_url(@safe_params) + assert_equal "http://www.example.com/", Routes.url_helpers.params_url(@safe_params) + assert_raises(ArgumentError) { params_url(@unsafe_params) } + assert_raises(ArgumentError) { Routes.url_helpers.params_url(@unsafe_params) } + + assert_equal "http://www.example.com/basket", symbol_url + assert_equal "http://www.example.com/basket", Routes.url_helpers.symbol_url + assert_equal "http://www.example.com/basket", hash_url + assert_equal "http://www.example.com/basket", Routes.url_helpers.hash_url + assert_equal "http://www.example.com/admin/dashboard", array_url + assert_equal "http://www.example.com/admin/dashboard", Routes.url_helpers.array_url + + assert_equal "http://www.example.com/products?page=2", options_url(page: 2) + assert_equal "http://www.example.com/products?page=2", Routes.url_helpers.options_url(page: 2) + assert_equal "http://www.example.com/products?size=10", defaults_url + assert_equal "http://www.example.com/products?size=10", Routes.url_helpers.defaults_url + assert_equal "http://www.example.com/products?size=20", defaults_url(size: 20) + assert_equal "http://www.example.com/products?size=20", Routes.url_helpers.defaults_url(size: 20) + end + + def test_resolve_paths + assert_equal "/basket", polymorphic_path(@basket) + assert_equal "/basket", Routes.url_helpers.polymorphic_path(@basket) + + assert_equal "/profile#details", polymorphic_path(@user) + assert_equal "/profile#details", Routes.url_helpers.polymorphic_path(@user) + + assert_equal "/profile#password", polymorphic_path(@user, anchor: "password") + assert_equal "/profile#password", Routes.url_helpers.polymorphic_path(@user, anchor: "password") + + assert_equal "/media/4", polymorphic_path(@video) + assert_equal "/media/4", Routes.url_helpers.polymorphic_path(@video) + assert_equal "/media/4", ActionDispatch::Routing::PolymorphicRoutes::HelperMethodBuilder.path.handle_model_call(self, @video) + + assert_equal "/posts/5", polymorphic_path(@article) + assert_equal "/posts/5", Routes.url_helpers.polymorphic_path(@article) + assert_equal "/posts/5", ActionDispatch::Routing::PolymorphicRoutes::HelperMethodBuilder.path.handle_model_call(self, @article) + + assert_equal "/pages/6", polymorphic_path(@page) + assert_equal "/pages/6", Routes.url_helpers.polymorphic_path(@page) + assert_equal "/pages/6", ActionDispatch::Routing::PolymorphicRoutes::HelperMethodBuilder.path.handle_model_call(self, @page) + + assert_equal "/pages/7", polymorphic_path(@category_page) + assert_equal "/pages/7", Routes.url_helpers.polymorphic_path(@category_page) + assert_equal "/pages/7", ActionDispatch::Routing::PolymorphicRoutes::HelperMethodBuilder.path.handle_model_call(self, @category_page) + + assert_equal "/pages/8", polymorphic_path(@product_page) + assert_equal "/pages/8", Routes.url_helpers.polymorphic_path(@product_page) + assert_equal "/pages/8", ActionDispatch::Routing::PolymorphicRoutes::HelperMethodBuilder.path.handle_model_call(self, @product_page) + end + + def test_resolve_urls + assert_equal "http://www.example.com/basket", polymorphic_url(@basket) + assert_equal "http://www.example.com/basket", Routes.url_helpers.polymorphic_url(@basket) + assert_equal "http://www.example.com/basket", polymorphic_url(@basket) + assert_equal "http://www.example.com/basket", Routes.url_helpers.polymorphic_url(@basket) + + assert_equal "http://www.example.com/profile#details", polymorphic_url(@user) + assert_equal "http://www.example.com/profile#details", Routes.url_helpers.polymorphic_url(@user) + + assert_equal "http://www.example.com/profile#password", polymorphic_url(@user, anchor: "password") + assert_equal "http://www.example.com/profile#password", Routes.url_helpers.polymorphic_url(@user, anchor: "password") + + assert_equal "http://www.example.com/media/4", polymorphic_url(@video) + assert_equal "http://www.example.com/media/4", Routes.url_helpers.polymorphic_url(@video) + assert_equal "http://www.example.com/media/4", ActionDispatch::Routing::PolymorphicRoutes::HelperMethodBuilder.url.handle_model_call(self, @video) + + assert_equal "http://www.example.com/posts/5", polymorphic_url(@article) + assert_equal "http://www.example.com/posts/5", Routes.url_helpers.polymorphic_url(@article) + assert_equal "http://www.example.com/posts/5", ActionDispatch::Routing::PolymorphicRoutes::HelperMethodBuilder.url.handle_model_call(self, @article) + + assert_equal "http://www.example.com/pages/6", polymorphic_url(@page) + assert_equal "http://www.example.com/pages/6", Routes.url_helpers.polymorphic_url(@page) + assert_equal "http://www.example.com/pages/6", ActionDispatch::Routing::PolymorphicRoutes::HelperMethodBuilder.url.handle_model_call(self, @page) + + assert_equal "http://www.example.com/pages/7", polymorphic_url(@category_page) + assert_equal "http://www.example.com/pages/7", Routes.url_helpers.polymorphic_url(@category_page) + assert_equal "http://www.example.com/pages/7", ActionDispatch::Routing::PolymorphicRoutes::HelperMethodBuilder.url.handle_model_call(self, @category_page) + + assert_equal "http://www.example.com/pages/8", polymorphic_url(@product_page) + assert_equal "http://www.example.com/pages/8", Routes.url_helpers.polymorphic_url(@product_page) + assert_equal "http://www.example.com/pages/8", ActionDispatch::Routing::PolymorphicRoutes::HelperMethodBuilder.url.handle_model_call(self, @product_page) + end + + def test_defining_direct_inside_a_scope_raises_runtime_error + routes = ActionDispatch::Routing::RouteSet.new + + assert_raises RuntimeError do + routes.draw do + namespace :admin do + direct(:rubyonrails) { "http://www.rubyonrails.org" } + end + end + end + end + + def test_defining_resolve_inside_a_scope_raises_runtime_error + routes = ActionDispatch::Routing::RouteSet.new + + assert_raises RuntimeError do + routes.draw do + namespace :admin do + resolve("User") { "/profile" } + end + end + end + end +end -- cgit v1.2.3 From 630e709ea6cb535b45a9cbd89c08c572646f5608 Mon Sep 17 00:00:00 2001 From: Andrew White Date: Wed, 22 Feb 2017 21:22:22 +0000 Subject: Clarify use of params in `direct` Since a `direct` url helper block is evaluated using `instance_exec` then methods that are available in the instance context can be accessed, e.g. the params object in a controller action or view. This wasn't clear from the example so expand on that point and add a test case for this situation. --- .../test/dispatch/routing/custom_url_helpers_test.rb | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'actionpack/test/dispatch/routing/custom_url_helpers_test.rb') diff --git a/actionpack/test/dispatch/routing/custom_url_helpers_test.rb b/actionpack/test/dispatch/routing/custom_url_helpers_test.rb index 6d230a2557..f85b989892 100644 --- a/actionpack/test/dispatch/routing/custom_url_helpers_test.rb +++ b/actionpack/test/dispatch/routing/custom_url_helpers_test.rb @@ -96,6 +96,10 @@ class TestCustomUrlHelpers < ActionDispatch::IntegrationTest direct(:options) { |options| [:products, options] } direct(:defaults, size: 10) { |options| [:products, options] } + direct(:browse, page: 1, size: 10) do |options| + [:products, options.merge(params.permit(:page, :size).to_h.symbolize_keys)] + end + resolve("Article") { |article| [:post, { id: article.id }] } resolve("Basket") { |basket| [:basket] } resolve("User", anchor: "details") { |user, options| [:profile, options] } @@ -127,6 +131,10 @@ class TestCustomUrlHelpers < ActionDispatch::IntegrationTest @safe_params = ActionController::Parameters.new(@path_params).permit(:controller, :action) end + def params + ActionController::Parameters.new(page: 2, size: 25) + end + def test_direct_paths assert_equal "http://www.rubyonrails.org", website_path assert_equal "http://www.rubyonrails.org", Routes.url_helpers.website_path @@ -162,6 +170,9 @@ class TestCustomUrlHelpers < ActionDispatch::IntegrationTest assert_equal "/products?size=10", Routes.url_helpers.defaults_path assert_equal "/products?size=20", defaults_path(size: 20) assert_equal "/products?size=20", Routes.url_helpers.defaults_path(size: 20) + + assert_equal "/products?page=2&size=25", browse_path + assert_raises(NameError) { Routes.url_helpers.browse_path } end def test_direct_urls @@ -199,6 +210,9 @@ class TestCustomUrlHelpers < ActionDispatch::IntegrationTest assert_equal "http://www.example.com/products?size=10", Routes.url_helpers.defaults_url assert_equal "http://www.example.com/products?size=20", defaults_url(size: 20) assert_equal "http://www.example.com/products?size=20", Routes.url_helpers.defaults_url(size: 20) + + assert_equal "http://www.example.com/products?page=2&size=25", browse_url + assert_raises(NameError) { Routes.url_helpers.browse_url } end def test_resolve_paths -- cgit v1.2.3 From 35afd2c53b4a49a6b4495b167eef233428123b4a Mon Sep 17 00:00:00 2001 From: Andrew White Date: Fri, 17 Mar 2017 17:07:09 +0000 Subject: Add support for calling nested direct routes (#28462) Not all requirements can be expressed in terms of polymorphic url options so add a `route_for` method that allows calling another direct route (or regular named route) which a set of arguments, e.g: resources :buckets direct :recordable do |recording| route_for(:bucket, recording.bucket) end direct :threadable do |threadable| route_for(:recordable, threadable.parent) end This maintains the context of the original caller, e.g. threadable_path(threadable) # => /buckets/1 threadable_url(threadable) # => http://example.com/buckets/1 --- .../dispatch/routing/custom_url_helpers_test.rb | 36 +++++++++++++++++----- 1 file changed, 28 insertions(+), 8 deletions(-) (limited to 'actionpack/test/dispatch/routing/custom_url_helpers_test.rb') diff --git a/actionpack/test/dispatch/routing/custom_url_helpers_test.rb b/actionpack/test/dispatch/routing/custom_url_helpers_test.rb index f85b989892..cb5ca5888b 100644 --- a/actionpack/test/dispatch/routing/custom_url_helpers_test.rb +++ b/actionpack/test/dispatch/routing/custom_url_helpers_test.rb @@ -4,18 +4,23 @@ class TestCustomUrlHelpers < ActionDispatch::IntegrationTest class Linkable attr_reader :id + def self.name + super.demodulize + end + def initialize(id) @id = id end def linkable_type - self.class.name.demodulize.underscore + self.class.name.underscore end end class Category < Linkable; end class Collection < Linkable; end class Product < Linkable; end + class Manufacturer < Linkable; end class Model extend ActiveModel::Naming @@ -79,7 +84,7 @@ class TestCustomUrlHelpers < ActionDispatch::IntegrationTest get "/media/:id", to: "media#show", as: :media get "/pages/:id", to: "pages#show", as: :page - resources :categories, :collections, :products + resources :categories, :collections, :products, :manufacturers namespace :admin do get "/dashboard", to: "dashboard#index" @@ -89,6 +94,7 @@ class TestCustomUrlHelpers < ActionDispatch::IntegrationTest direct("string") { "http://www.rubyonrails.org" } direct(:helper) { basket_url } direct(:linkable) { |linkable| [:"#{linkable.linkable_type}", { id: linkable.id }] } + direct(:nested) { |linkable| route_for(:linkable, linkable) } direct(:params) { |params| params } direct(:symbol) { :basket } direct(:hash) { { controller: "basket", action: "show" } } @@ -102,6 +108,7 @@ class TestCustomUrlHelpers < ActionDispatch::IntegrationTest resolve("Article") { |article| [:post, { id: article.id }] } resolve("Basket") { |basket| [:basket] } + resolve("Manufacturer") { |manufacturer| route_for(:linkable, manufacturer) } resolve("User", anchor: "details") { |user, options| [:profile, options] } resolve("Video") { |video| [:media, { id: video.id }] } resolve(%w[Page CategoryPage ProductPage]) { |page| [:page, { id: page.id }] } @@ -119,6 +126,7 @@ class TestCustomUrlHelpers < ActionDispatch::IntegrationTest @category = Category.new("1") @collection = Collection.new("2") @product = Product.new("3") + @manufacturer = Manufacturer.new("apple") @basket = Basket.new @user = User.new @video = Video.new("4") @@ -136,14 +144,14 @@ class TestCustomUrlHelpers < ActionDispatch::IntegrationTest end def test_direct_paths - assert_equal "http://www.rubyonrails.org", website_path - assert_equal "http://www.rubyonrails.org", Routes.url_helpers.website_path + assert_equal "/", website_path + assert_equal "/", Routes.url_helpers.website_path - assert_equal "http://www.rubyonrails.org", string_path - assert_equal "http://www.rubyonrails.org", Routes.url_helpers.string_path + assert_equal "/", string_path + assert_equal "/", Routes.url_helpers.string_path - assert_equal "http://www.example.com/basket", helper_url - assert_equal "http://www.example.com/basket", Routes.url_helpers.helper_url + assert_equal "/basket", helper_path + assert_equal "/basket", Routes.url_helpers.helper_path assert_equal "/categories/1", linkable_path(@category) assert_equal "/categories/1", Routes.url_helpers.linkable_path(@category) @@ -152,6 +160,9 @@ class TestCustomUrlHelpers < ActionDispatch::IntegrationTest assert_equal "/products/3", linkable_path(@product) assert_equal "/products/3", Routes.url_helpers.linkable_path(@product) + assert_equal "/categories/1", nested_path(@category) + assert_equal "/categories/1", Routes.url_helpers.nested_path(@category) + assert_equal "/", params_path(@safe_params) assert_equal "/", Routes.url_helpers.params_path(@safe_params) assert_raises(ArgumentError) { params_path(@unsafe_params) } @@ -192,6 +203,9 @@ class TestCustomUrlHelpers < ActionDispatch::IntegrationTest assert_equal "http://www.example.com/products/3", linkable_url(@product) assert_equal "http://www.example.com/products/3", Routes.url_helpers.linkable_url(@product) + assert_equal "http://www.example.com/categories/1", nested_url(@category) + assert_equal "http://www.example.com/categories/1", Routes.url_helpers.nested_url(@category) + assert_equal "http://www.example.com/", params_url(@safe_params) assert_equal "http://www.example.com/", Routes.url_helpers.params_url(@safe_params) assert_raises(ArgumentError) { params_url(@unsafe_params) } @@ -244,6 +258,9 @@ class TestCustomUrlHelpers < ActionDispatch::IntegrationTest assert_equal "/pages/8", polymorphic_path(@product_page) assert_equal "/pages/8", Routes.url_helpers.polymorphic_path(@product_page) assert_equal "/pages/8", ActionDispatch::Routing::PolymorphicRoutes::HelperMethodBuilder.path.handle_model_call(self, @product_page) + + assert_equal "/manufacturers/apple", polymorphic_path(@manufacturer) + assert_equal "/manufacturers/apple", Routes.url_helpers.polymorphic_path(@manufacturer) end def test_resolve_urls @@ -277,6 +294,9 @@ class TestCustomUrlHelpers < ActionDispatch::IntegrationTest assert_equal "http://www.example.com/pages/8", polymorphic_url(@product_page) assert_equal "http://www.example.com/pages/8", Routes.url_helpers.polymorphic_url(@product_page) assert_equal "http://www.example.com/pages/8", ActionDispatch::Routing::PolymorphicRoutes::HelperMethodBuilder.url.handle_model_call(self, @product_page) + + assert_equal "http://www.example.com/manufacturers/apple", polymorphic_url(@manufacturer) + assert_equal "http://www.example.com/manufacturers/apple", Routes.url_helpers.polymorphic_url(@manufacturer) end def test_defining_direct_inside_a_scope_raises_runtime_error -- cgit v1.2.3