Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I safely join relative url segments?

Tags:

uri

ruby

I'm trying to find a robust method of joining partial url path segments together. Is there a quick way to do this?

I tried the following:

puts URI::join('resource/', '/edit', '12?option=test') 

I expect:

resource/edit/12?option=test 

But I get the error:

`merge': both URI are relative (URI::BadURIError) 

I have used File.join() in the past for this but something does not seem right about using the file library for urls.

like image 701
Tim Santeford Avatar asked Jan 17 '12 19:01

Tim Santeford


1 Answers

URI's api is not neccearily great.

URI::join will work only if the first one starts out as an absolute uri with protocol, and the later ones are relative in the right ways... except I try to do that and can't even get that to work.

This at least doesn't error, but why is it skipping the middle component?

 URI::join('http://somewhere.com/resource', './edit', '12?option=test')  

I think maybe URI just kind of sucks. It lacks significant api on instances, such as an instance #join or method to evaluate relative to a base uri, that you'd expect. It's just kinda crappy.

I think you're going to have to write it yourself. Or just use File.join and other File path methods, after testing all the edge cases you can think of to make sure it does what you want/expect.

edit 9 Dec 2016 I figured out the addressable gem does it very nicely.

base = Addressable::URI.parse("http://example.com") base + "foo.html" # => #<Addressable::URI:0x3ff9964aabe4 URI:http://example.com/foo.html>  base = Addressable::URI.parse("http://example.com/path/to/file.html") base + "relative_file.xml" # => #<Addressable::URI:0x3ff99648bc80 URI:http://example.com/path/to/relative_file.xml>  base = Addressable::URI.parse("https://example.com/path") base + "//newhost/somewhere.jpg" # => #<Addressable::URI:0x3ff9960c9ebc URI:https://newhost/somewhere.jpg>  base = Addressable::URI.parse("http://example.com/path/subpath/file.html") base + "../up-one-level.html" => #<Addressable::URI:0x3fe13ec5e928 URI:http://example.com/path/up-one-level.html> 
like image 163
jrochkind Avatar answered Oct 11 '22 16:10

jrochkind