Full url for an image-path in Rails 3

2019-01-21 22:42发布

问题:

I have an Image, which contains carrierwave uploads:

Image.find(:first).image.url #=> "/uploads/image/4d90/display_foo.jpg"

In my view, I want to find the absolute url for this. Appending the root_url results in a double /.

root_url + image.url #=> http://localhost:3000//uploads/image/4d90/display_foo.jpg

I cannot use url_for (that I know of), because that either allows passing a path, or a list of options to identify the resource and the :only_path option. Since I do't have a resource that can be identified trough "controller"+"action" I cannot use the :only_path option.

url_for(image.url, :only_path => true) #=> wrong amount of parameters, 2 for 1

What would be the cleanest and best way to create a path into a full url in Rails3?

回答1:

try path method

Image.find(:first).image.path

UPD

request.host + Image.find(:first).image.url

and you can wrap it as a helper to DRY it forever

request.protocol + request.host_with_port + Image.find(:first).image.url


回答2:

You can also set CarrierWave's asset_host config setting like this:

# config/initializers/carrierwave.rb
CarrierWave.configure do |config|
  config.storage = :file
  config.asset_host = ActionController::Base.asset_host
end

This ^ tells CarrierWave to use your app's config.action_controller.asset_host setting, which can be defined in one of your config/envrionments/[environment].rb files. See here for more info.

Or set it explicitly:

  config.asset_host = 'http://example.com'

Restart your app, and you're good to go - no helper methods required.

* I'm using Rails 3.2 and CarrierWave 0.7.1



回答3:

Another simple method to use is URI.parse, in your case would be

require 'uri'

(URI.parse(root_url) + image.url).to_s

and some examples:

1.9.2p320 :001 > require 'uri'
 => true 
1.9.2p320 :002 > a = "http://asdf.com/hello"
 => "http://asdf.com/hello" 
1.9.2p320 :003 > b = "/world/hello"
 => "/world/hello" 
1.9.2p320 :004 > c = "world"
 => "world" 
1.9.2p320 :005 > d = "http://asdf.com/ccc/bbb"
 => "http://asdf.com/ccc/bbb" 
1.9.2p320 :006 > e = "http://newurl.com"
 => "http://newurl.com" 
1.9.2p320 :007 > (URI.parse(a)+b).to_s
 => "http://asdf.com/world/hello" 
1.9.2p320 :008 > (URI.parse(a)+c).to_s
 => "http://asdf.com/world" 
1.9.2p320 :009 > (URI.parse(a)+d).to_s
 => "http://asdf.com/ccc/bbb" 
1.9.2p320 :010 > (URI.parse(a)+e).to_s
 => "http://newurl.com" 


回答4:

Just taking floor's answer and providing the helper:

# Use with the same arguments as image_tag. Returns the same, except including
# a full path in the src URL. Useful for templates that will be rendered into
# emails etc.
def absolute_image_tag(*args)
  raw(image_tag(*args).sub /src="(.*?)"/, "src=\"#{request.protocol}#{request.host_with_port}" + '\1"')
end


回答5:

There's quite a bunch of answers here. However, I didn't like any of them since all of them rely on me to remember to explicitly add the port, protocol etc. I find this to be the most elegant way of doing this:

full_url = URI( root_url )
full_url.path = Image.first.image.url
# Or maybe you want a link to some asset, like I did:
# full_url.path = image_path("whatevar.jpg")
full_url.to_s

And what is the best thing about it is that we can easily change just one thing and no matter what thing that might be you always do it the same way. Say if you wanted to drop the protocol and and use the The Protocol-relative URL, do this before the final conversion to string.

full_url.scheme = nil

Yay, now I have a way of converting my asset image urls to protocol relative urls that I can use on a code snippet that others might want to add on their site and they'll work regardless of the protocol they use on their site (providing that your site supports either protocol).



回答6:

I used default_url_options, because request is not available in mailer and avoided duplicating hostname in config.action_controller.asset_host if haven't specified it before.

config.asset_host = ActionDispatch::Http::URL.url_for(ActionMailer::Base.default_url_options)


回答7:

You can't refer to request object in an email, so how about:

def image_url(*args)
    raw(image_tag(*args).sub /src="(.*?)"/, "src=\"//#{ActionMailer::Base.default_url_options[:protocol]}#{ActionMailer::Base.default_url_options[:host]}" + '\1"')
end


回答8:

You can actually easily get this done by

root_url[0..-2] + image.url

I agree it doesn't look too good, but gets the job done.. :)



回答9:

I found this trick to avoid double slash:

URI.join(root_url, image.url)