From 72570db50d956b86822c515d7a58c2df8831f79b Mon Sep 17 00:00:00 2001 From: Andrew Havens Date: Wed, 10 Dec 2014 14:28:36 -0800 Subject: [PATCH] Add support for host, protocol, and port configuration. --- Readme.md | 12 ++- lib/js_routes.rb | 28 ++++- spec/js_routes/options_spec.rb | 191 +++++++++++++++++++++++++++------ spec/spec_helper.rb | 6 ++ 4 files changed, 195 insertions(+), 42 deletions(-) diff --git a/Readme.md b/Readme.md index 6baa80d0..913a86c5 100644 --- a/Readme.md +++ b/Readme.md @@ -43,9 +43,10 @@ end Available options: -* `default_url_options` - default parameters to be used to generate url - * Note that currently only optional parameters (like `:format` or `:trailing_slash`) can be defaulted. - * Example: {:format => "json", :trailing_slash => true} +* `default_url_options` - default parameters used when generating URLs + * Note that only specific options are supported at this time. + * Supported options: `:format`, `:trailing_slash`, `:protocol`, `:host`, `:port` + * Example: {:format => "json", :trailing_slash => true, :protocol => "https", :host => "example.com", :port => 3000} * Default: {} * `exclude` - Array of regexps to exclude from js routes. * Default: [] @@ -61,9 +62,10 @@ Available options: * Default: blank * `camel_case` (version >= 0.8.8) - Generate camel case route names. * Default: false -* `url_links` (version >= 0.8.9) - Generate `*_url` links (in addition to default `*_path`), where url_links value is beginning of url routes - * Example: http[s]://example.com +* `url_links` (version >= 0.8.9) - Generate `*_url` helpers (in addition to the default `*_path` helpers). + * Example: true * Default: false + * Be sure to specify a default host in `default_url_options`. Routes which specify a specific host, protocol, or port will be used instead of their corresponding default. * `compact` (version > 0.9.9) - Remove `_path` suffix in path routes(`*_url` routes stay untouched if they were enabled) * Default: false * Sample route call when option is set to true: Routes.users() => `/users` diff --git a/lib/js_routes.rb b/lib/js_routes.rb index a10d1a5a..c4a09dfa 100644 --- a/lib/js_routes.rb +++ b/lib/js_routes.rb @@ -156,7 +156,7 @@ def build_js(route, parent_route) required_parts, optional_parts = route.required_parts.clone, route.optional_parts.clone optional_parts.push(required_parts.delete :format) if required_parts.include?(:format) route_name = generate_route_name(name, (:path unless @options[:compact])) - url_link = generate_url_link(name, route_name, required_parts) + url_link = generate_url_link(name, route_name, required_parts, route) _ = <<-JS.strip! // #{name.join('.')} => #{parent_spec}#{route.path.spec} #{route_name}: function(#{build_params(required_parts)}) { @@ -165,16 +165,36 @@ def build_js(route, parent_route) JS end - def generate_url_link(name, route_name, required_parts) + def generate_url_link(name, route_name, required_parts, route) return "" unless @options[:url_links] - raise "invalid URL format in url_links (ex: http[s]://example.com)" if @options[:url_links].match(URI::regexp(%w(http https))).nil? _ = <<-JS.strip! #{generate_route_name(name, :url)}: function(#{build_params(required_parts)}) { - return "" + #{@options[:url_links].inspect} + this.#{route_name}(#{build_params(required_parts)}); + return #{generate_base_url_js(route)} + this.#{route_name}(#{build_params(required_parts)}); } JS end + def generate_base_url_js(route) + # preserve and deprecate previous behavior + unless @options[:url_links] == true + ActiveSupport::Deprecation.warn('js-routes url_links config value must be a boolean. Use default_url_options for specifying a default host.') + raise "invalid URL format in url_links (ex: http[s]://example.com)" if @options[:url_links].match(URI::regexp(%w(http https))).nil? + return "#{@options[:url_links].inspect}" + else + protocol = route.defaults[:protocol] || @options[:default_url_options][:protocol] || 'http' + hostname = route.defaults[:host] || @options[:default_url_options][:host] + port = route.defaults[:port] || (@options[:default_url_options][:port] unless route.defaults[:host]) + port = ":#{port}" if port + + unless hostname + raise "A :default_url_options[:host] must be configured in order to generate *_url helpers" + end + + return %Q|'#{protocol}://#{hostname}#{port}'| + end + base_url_js + end + def generate_route_name(name, suffix) route_name = name.join('_') route_name << "_#{ suffix }" if suffix diff --git a/spec/js_routes/options_spec.rb b/spec/js_routes/options_spec.rb index 562b84b5..6d4d9f98 100644 --- a/spec/js_routes/options_spec.rb +++ b/spec/js_routes/options_spec.rb @@ -238,56 +238,181 @@ end end - context "with host" do - let(:_options) { { :url_links => "http://localhost" } } - it "should generate path and url links" do - expect(evaljs("Routes.inbox_path")).not_to be_nil - expect(evaljs("Routes.inbox_url")).not_to be_nil - expect(evaljs("Routes.inbox_path(1)")).to eq(routes.inbox_path(1)) - expect(evaljs("Routes.inbox_url(1)")).to eq("http://localhost#{routes.inbox_path(1)}") - expect(evaljs("Routes.inbox_url(1, { test_key: \"test_val\" })")).to eq("http://localhost#{routes.inbox_path(1, :test_key => "test_val")}") + context 'with deprecated, non-boolean config value' do + context "with host" do + let(:_options) { { :url_links => "http://localhost" } } + it "should generate path and url links" do + expect(evaljs("Routes.inbox_path")).not_to be_nil + expect(evaljs("Routes.inbox_url")).not_to be_nil + expect(evaljs("Routes.inbox_path(1)")).to eq(routes.inbox_path(1)) + expect(evaljs("Routes.inbox_url(1)")).to eq("http://localhost#{routes.inbox_path(1)}") + expect(evaljs("Routes.inbox_url(1, { test_key: \"test_val\" })")).to eq("http://localhost#{routes.inbox_path(1, :test_key => "test_val")}") + end end - end - context "with invalid host" do - it "should raise error" do - expect { JsRoutes.generate({ :url_links => "localhost" }) }.to raise_error RuntimeError + context "with invalid host" do + it "should raise error" do + expect { JsRoutes.generate({ :url_links => "localhost" }) }.to raise_error RuntimeError + end end - end - context "with host and camel_case" do - let(:_options) { { :camel_case => true, :url_links => "http://localhost" } } - it "should generate path and url links" do - expect(evaljs("Routes.inboxPath")).not_to be_nil - expect(evaljs("Routes.inboxUrl")).not_to be_nil - expect(evaljs("Routes.inboxPath(1)")).to eq(routes.inbox_path(1)) - expect(evaljs("Routes.inboxUrl(1)")).to eq("http://localhost#{routes.inbox_path(1)}") + context "with host and camel_case" do + let(:_options) { { :camel_case => true, :url_links => "http://localhost" } } + it "should generate path and url links" do + expect(evaljs("Routes.inboxPath")).not_to be_nil + expect(evaljs("Routes.inboxUrl")).not_to be_nil + expect(evaljs("Routes.inboxPath(1)")).to eq(routes.inbox_path(1)) + expect(evaljs("Routes.inboxUrl(1)")).to eq("http://localhost#{routes.inbox_path(1)}") + end + end + + context "with host and prefix" do + let(:_options) { { :prefix => "/api", :url_links => "https://example.com" } } + it "should generate path and url links" do + expect(evaljs("Routes.inbox_path")).not_to be_nil + expect(evaljs("Routes.inbox_url")).not_to be_nil + expect(evaljs("Routes.inbox_path(1)")).to eq("/api#{routes.inbox_path(1)}") + expect(evaljs("Routes.inbox_url(1)")).to eq("https://example.com/api#{routes.inbox_path(1)}") + end end end - context "with host and prefix" do - let(:_options) { { :prefix => "/api", :url_links => "https://example.com" } } - it "should generate path and url links" do - expect(evaljs("Routes.inbox_path")).not_to be_nil - expect(evaljs("Routes.inbox_url")).not_to be_nil - expect(evaljs("Routes.inbox_path(1)")).to eq("/api#{routes.inbox_path(1)}") - expect(evaljs("Routes.inbox_url(1)")).to eq("https://example.com/api#{routes.inbox_path(1)}") + context "when configuring with default_url_options" do + context "when default host is not specified" do + it "raises an error" do + expect { JsRoutes.generate({ :url_links => true }) }.to raise_error RuntimeError + end + end + + context "when default host is specified" do + let(:_options) { { :url_links => true, :default_url_options => {:host => "example.com"} } } + + it "is used as the host" do + expect(evaljs("Routes.inbox_url")).not_to be_nil + expect(evaljs("Routes.inbox_url(1)")).to eq("http://example.com#{routes.inbox_path(1)}") + end + + it "does not override host when specified in route" do + expect(evaljs("Routes.sso_url()")).to eq("http://sso.example.com#{routes.sso_path}") + end + + it "does not affect path helpers" do + expect(evaljs("Routes.inbox_path")).not_to be_nil + expect(evaljs("Routes.inbox_path(1)")).to eq(routes.inbox_path(1)) + end + end + + context "when default protocol is not specified" do + let(:_options) { { :url_links => true, :default_url_options => {:host => "example.com"} } } + + it "defaults to http" do + expect(evaljs("Routes.inbox_url(1)")).to eq("http://example.com#{routes.inbox_path(1)}") + end + + it "does not override protocol when specified in route" do + expect(evaljs("Routes.new_session_url()")).to eq("https://example.com#{routes.new_session_path}") + end + end + + context "when default protocol is specified" do + let(:_options) { { :url_links => true, :default_url_options => {:host => "example.com", :protocol => "ftp"} } } + + it "is used as the protocol" do + expect(evaljs("Routes.inbox_url(1)")).to eq("ftp://example.com#{routes.inbox_path(1)}") + end + + it "does not override protocol when specified in route" do + expect(evaljs("Routes.new_session_url()")).to eq("https://example.com#{routes.new_session_path}") + end + end + + context "when default port is not specified" do + let(:_options) { { :url_links => true, :default_url_options => {:host => "example.com"} } } + + it "defaults to port 80 (leaving the port blank)" do + expect(evaljs("Routes.inbox_url(1)")).to eq("http://example.com#{routes.inbox_path(1)}") + end + + it "does not override port when specified in route" do + expect(evaljs("Routes.portals_url()")).to eq("http://example.com:8080#{routes.portals_path}") + end + end + + context "when default port is specified" do + let(:_options) { { :url_links => true, :default_url_options => {:host => "example.com", :port => 3000} } } + + it "is used as the port" do + expect(evaljs("Routes.inbox_url(1)")).to eq("http://example.com:3000#{routes.inbox_path(1)}") + expect(evaljs("Routes.sso_url()")).to eq("http://sso.example.com:3000#{routes.sso_path}") # this may be unintentional since the host is different + end + + it "does not override port when specified in route" do + expect(evaljs("Routes.portals_url()")).to eq("http://example.com:8080#{routes.portals_path}") + end + end + + context "with camel_case option" do + let(:_options) { { :camel_case => true, :url_links => true, :default_url_options => {:host => "example.com"} } } + it "should generate path and url links" do + expect(evaljs("Routes.inboxUrl")).not_to be_nil + expect(evaljs("Routes.inboxUrl(1)")).to eq("http://example.com#{routes.inbox_path(1)}") + expect(evaljs("Routes.newSessionUrl()")).to eq("https://example.com#{routes.new_session_path}") + expect(evaljs("Routes.ssoUrl()")).to eq("http://sso.example.com#{routes.sso_path}") + expect(evaljs("Routes.portalsUrl()")).to eq("http://example.com:8080#{routes.portals_path}") + end + end + + context "with prefix option" do + let(:_options) { { :prefix => "/api", :url_links => true, :default_url_options => {:host => 'example.com'} } } + it "should generate path and url links" do + expect(evaljs("Routes.inbox_url")).not_to be_nil + expect(evaljs("Routes.inbox_url(1)")).to eq("http://example.com/api#{routes.inbox_path(1)}") + expect(evaljs("Routes.new_session_url()")).to eq("https://example.com/api#{routes.new_session_path}") + expect(evaljs("Routes.sso_url()")).to eq("http://sso.example.com/api#{routes.sso_path}") + expect(evaljs("Routes.portals_url()")).to eq("http://example.com:8080/api#{routes.portals_path}") + end + end + + context "with compact option" do + let(:_options) { { :compact => true, :url_links => true, :default_url_options => {:host => 'example.com'} } } + it "does not affect url helpers" do + expect(evaljs("Routes.inbox_path")).to be_nil + expect(evaljs("Routes.inboxes()")).to eq(routes.inboxes_path()) + expect(evaljs("Routes.inbox(2)")).to eq(routes.inbox_path(2)) + + expect(evaljs("Routes.inbox_url")).not_to be_nil + expect(evaljs("Routes.inbox_url(1)")).to eq("http://example.com#{routes.inbox_path(1)}") + expect(evaljs("Routes.new_session_url()")).to eq("https://example.com#{routes.new_session_path}") + expect(evaljs("Routes.sso_url()")).to eq("http://sso.example.com#{routes.sso_path}") + expect(evaljs("Routes.portals_url()")).to eq("http://example.com:8080#{routes.portals_path}") + end end end end describe "when the compact mode is enabled" do let(:_options) { { :compact => true } } - it "should avoid a path suffix" do + it "removes _path suffix from path helpers" do + expect(evaljs("Routes.inbox_path")).to be_nil expect(evaljs("Routes.inboxes()")).to eq(routes.inboxes_path()) expect(evaljs("Routes.inbox(2)")).to eq(routes.inbox_path(2)) end - context "with url links" do - let(:_options) { { :compact => true, :url_links => "http://localhost" } } - it "should not strip urls" do - expect(evaljs("Routes.inbox(1)")).to eq(routes.inbox_path(1)) - expect(evaljs("Routes.inbox_url(1)")).to eq("http://localhost#{routes.inbox_path(1)}") + context "with url_links option" do + context "with deprecated url_links config value" do + let(:_options) { { :compact => true, :url_links => "http://localhost" } } + it "should not strip urls" do + expect(evaljs("Routes.inbox(1)")).to eq(routes.inbox_path(1)) + expect(evaljs("Routes.inbox_url(1)")).to eq("http://localhost#{routes.inbox_path(1)}") + end + end + + context "when configuring with default_url_options" do + let(:_options) { { :compact => true, :url_links => true, :default_url_options => {:host => 'example.com'} } } + it "does not affect url helpers" do + expect(evaljs("Routes.inbox_url")).not_to be_nil + expect(evaljs("Routes.inbox_url(1)")).to eq("http://example.com#{routes.inbox_path(1)}") + end end end end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 88562aae..63c73a2c 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -108,6 +108,12 @@ def draw_routes get '/привет' => "foo#foo", :as => :hello get '(/o/:organization)/search/:q' => "foo#foo", as: :search + + resources :sessions, :only => [:new, :create, :destroy], :protocol => 'https' + + get '/' => 'sso#login', host: 'sso.example.com', as: :sso + + resources :portals, :port => 8080 end end