Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for host, protocol, and port configuration. #137

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
27 changes: 23 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,35 @@ 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
end

def generate_route_name(name, suffix)
route_name = name.join('_')
route_name << "_#{ suffix }" if suffix
Expand Down
181 changes: 148 additions & 33 deletions spec/js_routes/options_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -238,56 +238,171 @@
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
around(:each) do |example|
ActiveSupport::Deprecation.silence do
example.run
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 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 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 invalid host" do
it "should raise error" do
expect { JsRoutes.generate({ :url_links => "localhost" }) }.to raise_error RuntimeError
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)}")
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 only host option is specified" do
let(:_options) { { :url_links => true, :default_url_options => {:host => "example.com"} } }

it "uses the specified host, defaults protocol to http, defaults port to 80 (leaving it blank)" 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

it "does not override host when specified in route" do
expect(evaljs("Routes.sso_url()")).to eq(routes.sso_url)
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 host and protocol are specified" do
let(:_options) { { :url_links => true, :default_url_options => {:host => "example.com", :protocol => "ftp"} } }

it "uses the specified protocol and host, defaults port to 80 (leaving it blank)" 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

it "does not override host when host is specified in route" do
expect(evaljs("Routes.sso_url()")).to eq("ftp://sso.example.com#{routes.sso_path}")
end

it "does not override port when specified in route" do
expect(evaljs("Routes.portals_url()")).to eq("ftp://example.com:8080#{routes.portals_path}")
end
end

context "when default host and port are specified" do
let(:_options) { { :url_links => true, :default_url_options => {:host => "example.com", :port => 3000} } }

it "uses the specified host and port, defaults protocol to http" do
expect(evaljs("Routes.inbox_url(1)")).to eq("http://example.com:3000#{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:3000#{routes.new_session_path}")
end

it "does not override host, protocol, or port when host is specified in route" do
expect(evaljs("Routes.sso_url()")).to eq(routes.sso_url)
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(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(routes.sso_url)
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(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_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(routes.sso_url)
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
around(:each) do |example|
ActiveSupport::Deprecation.silence do
example.run
end
end

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
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