Reputation: 23317
I'd like to create an URL using an endpoint and a path or a host and path. Unfortunately URI.join
doesn't allow to do it:
pry(main)> URI.join "https://service.com", "endpoint", "/path"
=> #<URI::HTTPS:0xa947f14 URL:https://service.com/path>
pry(main)> URI.join "https://service.com/endpoint", "/path"
=> #<URI::HTTPS:0xabba56c URL:https://service.com/path>
and what I want is: "https://service.com/endpoint/path"
. How could I do it in Ruby/Rails?
EDIT: As the URI.join
has some drawback, I'm tempted to use File.join
:
URI.join("https://service.com", File.join("endpoint", "/path"))
What do you think?
Upvotes: 6
Views: 6970
Reputation: 1547
I made a script to allow you to do something like:
SmartURI.join('http://example.com/subpath', 'hello', query: { token: secret })
=> "http://example.com/subpath/hello?token=secret"
https://gist.github.com/zernel/0f10c71f5a9e044653c1a65c6c5ad697
Upvotes: 0
Reputation: 5708
Looks like URI.join checks for the presence of slash character '/' to figures out the folder in the url path. So, if you missed the trailing slash '/' in the path it will not treat it as folder, and omit it. Check this out:
URI.join("https://service.com", 'omitted_part', 'omitted_again', 'end_point_stays').to_s
# =>"https://service.com/end_point_stays"
Here, if we try to JOIN THE WORDS ONLY, first and last params only stay, rest are omitted, where first param is, absolute uri with protocol & last param is, the end point.
So, if you want to include the folder component, add trailing slash in each folder-component, then only it is considered part of the path:
URI.join("https://service.com", 'omitted_no_trailing_slash', 'omitted_again', 'stays/', 'end_point_stays').to_s
# => "https://service.com/stays/end_point_stays"
One more interesting thing to consider is that, if you are providing path in first parameter it acts as follows:
URI.join("https://service.com/omitted_because_no_trailing_slash", 'end_point_stays').to_s
# => "https://service.com/end_point_stays"
URI.join("https://service.com/stays_because_of_trailing_slash/", 'end_point_stays').to_s
# => "https://service.com/stays_because_of_trailing_slash/end_point_stays"
URI.join("https://service.com/safe_with_trailing_slash/omitted_because_no_trailing_slash", 'end_point_stays').to_s
# => "https://service.com/safe_with_trailing_slash/end_point_stays"
Upvotes: 3
Reputation: 222128
URI.join works like what you'd expect an <a>
tag to work.
You're joining example.com
, endpoint
, /path
, so /path
takes you back to the root of the domain, instead of appending it.
You need to end the endpoint with a /
, and not start the path with /
.
URI.join "https://service.com/", "endpoint/", "path"
=> #<URI::HTTPS:0x007f8a5b0736d0 URL:https://service.com/endpoint/path>
Edit: As per your request in the comment below, try this:
def join(*args)
args.map { |arg| arg.gsub(%r{^/*(.*?)/*$}, '\1') }.join("/")
end
Test:
> join "https://service.com/", "endpoint", "path"
=> "https://service.com/endpoint/path"
> join "http://example.com//////", "///////a/////////", "b", "c"
=> "http://example.com/a/b/c"
Upvotes: 9