Skip to content

Commit

Permalink
Add support for host, protocol, and port configuration.
Browse files Browse the repository at this point in the history
  • Loading branch information
Andrew Havens committed Dec 10, 2014
1 parent ebf4bbc commit 72570db
Show file tree
Hide file tree
Showing 4 changed files with 195 additions and 42 deletions.
12 changes: 7 additions & 5 deletions Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -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: []
Expand All @@ -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`
Expand Down
28 changes: 24 additions & 4 deletions lib/js_routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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)}) {
Expand All @@ -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
Expand Down
191 changes: 158 additions & 33 deletions spec/js_routes/options_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
6 changes: 6 additions & 0 deletions spec/spec_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit 72570db

Please sign in to comment.