Dismiss
Announcing Stack Overflow Documentation

We started with Q&A. Technical documentation is next, and we need your help.

Whether you're a beginner or an experienced developer, you can contribute.

Sign up and start helping → Learn more about Documentation →

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?

share|improve this question
1  
Check out: stackoverflow.com/questions/8900782/… – My God Feb 26 '13 at 14:39

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"
share|improve this answer
    
Thanks. However, I'd like not to care about slashes (lack of slash, double slash and so on), because URI.join("https://service.com/", "endpoint", "path") also doesn't work correctly. So the whole URI.join in my case is as useful as simple string concatenation. Do you know about any 'automatic' method of concatenating paths in URIs without taking care of slashes? – mrzasa Feb 26 '13 at 14:06
    
@mrzasa, please try the function I added to my answer above. – Dogbert Feb 26 '13 at 14:58
1  
@mrzasa, URI.join works perfectly, when given the values it needs. While you don't want to care, you get to because that's what programmers do. We have to be aware of the content of values we're passing to methods, so that what goes in returns what we expect out. Here's something to think about: "On two occasions I have been asked,—'Pray, Mr. Babbage, if you put into the machine wrong figures, will the right answers come out?' ... I am not able rightly to apprehend the kind of confusion of ideas that could provoke such a question." —Charles Babbage, Passages from the Life of a Philosopher – the Tin Man Feb 26 '13 at 15:25
1  
@the Tin Man: It's not about that I care or not -- I do know that I need to validate/normalize input values. I just want to provide an interface that seems to be convenient: pass the endpoint and a path with or without slash. I thought that there was a function that would do that concatenation for me. If not -- I'll take care. – mrzasa Feb 26 '13 at 21:49

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"
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.