Get absolute URL for paperclip attachment - ruby-on-rails

Is it possible to get the absolute URI for a Paperclip attachment? Right now, the problem is that the production environment is deployed in a sub-URI (on Passenger: RackBaseURI), but <paperclip attachment>.url returns the Rails-app relative URI (/system/images/...). Is there a way to get the absolute URI for Paperclip attachments?
I'm using Paperclip v2.7 and Rails 3.2.8.

asset_url(model.attachment_name.url(:style))
Relevant github issue

try
URI.join(request.url, #model.attachment_name.url)
or
URI(request.url) + #model.attachment_name.url
It's safe if you use S3 or absolute url.
Update: this answer is better than mine ;) https://stackoverflow.com/a/21027839/683157

According to this github issue, it is cleaner to use ActionController::Base.asset_host so it would result the helper:
def add_host_prefix(url)
URI.join(ActionController::Base.asset_host, url)
end
This supposes you have in every /config/environments/<environment>.rb file the following:
Appname::Application.configure do
# ....
config.action_controller.asset_host = 'http://localhost:3000' # Locally
# ....
end

The most widely applicable way of doing this is to first define your asset hosts in the relevant config/environment file:
config.action_controller.asset_host = "http://assethost.com"
config.action_mailer.asset_host = "http://assethost.com"
Then in views and mailers:
asset_url(model.attachment.url(:style))
In the console:
helper.asset_url(model.attachment.url(:style))
In a model:
ApplicationController.helpers.asset_url(model.attachment.url(:style))

You can do this:
<%= image_tag "#{request.protocol}#{request.host_with_port}#{#model.attachment_name.url(:attachment_style)}" %>
Or make a helper method to wrap it.
def absolute_attachment_url(attachment_name, attachment_style = :original)
"#{request.protocol}#{request.host_with_port}#{attachment_name.url(attachment_style)}"
end
And use it like this:
<%= image_tag absolute_attachment_url(attachment_name, :attachment_style)}" %>
Ex: Model = Person (#person), attachment_name = avatar, style = :thumb
<%= image_tag absolute_attachment_url(#person.avatar, :thumb)}" %>

This doesn't solve the original poster's problem exactly (it operates in the view, not the model), but may be helpful for people who are trying to "get absolute URL for paperclip attachment" within their view: In the same way that
image_tag(user.avatar.url(:large))
puts the image itself into your view,
image_url(user.avatar.url(:large))
returns just the URL you'll need if you want to link to the asset directly (e.g. in a link_to call).

You can add to your application.rb (or for specific enviroment in config/environments/*):
config.paperclip_defaults = {
url: "http://my.address.com/system/:class/:attachment/:id_partition/:style.:extension",
path: ':rails_root/public/system/:class/:attachment/:id_partition/:style.:extension',
}
Restart and reimport your images.
PS: obviously you can replace http://my.address.com with an environment variable.

Related

How can I get the base url in an ActionMailer?

I want to send out an email with a deep link back into my app, but I'd rather not have to hard-code the URL or else I have to switch it when I move from one environment to the next. How can I obtain the base url of a web app from within an ActionMailer? For example, I'd love to be able to have something like:
<%= base_uri %>listCreate?first=foo&second=bar
render something like the following in my testing environment:
http://localhost:30000/myApp/listCreate?first=foo&second=bar
and the following in production:
http://www.myDomain.com/myApp/listCreate?first=foo&second=bar
Set the defult url option in config/environments/production.rb
config.action_mailer.default_url_options = { :host => 'your.app.com' }
and in mail template
the link should be
<%= link_to 'myapp', myapp_list_url %>
Hope this could help
You can refer the Action Mailer doc
You can set the default_url_options for your mailer in the controller where you have the current host for the request.
In my case, I send an email when I receive information in some lead creation form, so I have a LeadMailer. My solution was to create a before filter to set the host in the mailer.
Of course, you don't need to do it in a before filter, you could set it in your action.
My solutions looked like this:
class LeadsController < ApplicationController
before_action :set_host, on: [:create]
def set_host
LeadsMailer.default_url_options = { host: request.host_with_port }
LeadsMailer.asset_host = request.protocol + request.host_with_port
end
end
I set the asset_host config because I wanted to use my images from the assets pipeline.
Now you can use the _url helpers as usual
<%= link_to 'something', something_url %>
Or your asset helpers
<%= image_url('logo.png')%>

Rails: configuring a form action's host using custom URL from settings

I have a Rails app that I am feeding cross domain in production. It needs absolute references. Because of this, I have enabled the following in my config/environments/production.rb:
config.action_controller.asset_host = "http://myapp.herokuapp.com"
That works fine for images and resources but my input form that looks like this:
<%= form_tag('/plans/collapse_plans', :method => 'post', :remote => true ) do %>
is still getting this in the console:
Failed to load resource file://localhost/plans/collapse_plan
How can I change it so that form action will automatically include the specified host, instead of defaulting to localhost? Can I set this anywhere in config?
This seems like it will work:
https://github.com/binarylogic/settingslogic
Then I can just do:
<%= form_tag mysettings.myspecifiedhost + plans_collapse_plans_path, :method => 'post', :remote => true do %>
I may be on the wrong track here, but:
Asset host is not your application's host, asset host is a host that serves you /app/assets folder and this is configurable so you can set up a CDN for example, it's not intended for hosting action points.
If you want to target the full url of your own host use rake routes to get the route name corresponding to /plans/collapse_plans which probably looks something in the lines of plans_collapse_plans and then you can use plans_collapse_plans_url and rails will render the correct full URL for you.
If you're using the default host name rails provides automagically this will "just work", i.e.
[2] pry(#<#<Class:0x000000048fd780>>)> account_edit_url
=> "http://dev:3000/account/edit"
If this doesn't "just work", you can override all url helpers in the app by overriding default_url_options in your ApplicationController:
def default_url_options
{:host => HOST}
end
and be sure to set the HOST constant in your application's environment, for example:
[1] pry(#<#<Class:0x00000005047d10>>)> account_edit_url
=> "http://o7ms:3000/account/edit"
If you need to override this just in certain situations you can leave the ApplicationController alone and do:
[3] pry(#<#<Class:0x000000048fd780>>)> account_edit_url(host: MY_HOST_FOR_THE_OTHER_THINGY)
=> "http://foo:3000/account/edit"
In all cases you'll set up a config option in one place and all endpoints in the app will adjust.
EDIT
If you want to go fancy,
see default_url_options and rails 3,
by overriding url_options you may be able to implement pretty calls like account_edit_url(ajax_host: true), the url_options method would look something like this if this works:
def url_options
options = super
if super.delete(:ajax_host)
{host: AJAX_HOST}.merge(options)
else
options
end
end
what you are trying cannot be done normally for ajax calls.
see http://en.wikipedia.org/wiki/Same-origin_policy
Two approaches:--
1.) <%= form_tag root_url + plans_collapse_plans_path, :method => 'post', :remote => true do %>
concatenation:-- root_url + plans_collapse_plans_path
2.) in config/environments/production.rb
MyApp::Application.configure do
# general configurations
config.after_initialize do
Rails.application.routes.default_url_options[:host] = 'root_url' #'localhost:3000'
end
end

Rails - slice string and rails path

I do some string slice. Right now i have something like this:
#str = '/images00.someother.path_to_.image.jpg' ///my spliced string
When i do this:
#new_string = #str[1..#str.length]
i thought that i will have string like:
'images00.someother.path_to_.image.jpg'
but no... rails put in url path to images, so the output is:
<img src='/images/images00.someother.path_to_.image.jpg'>
when i slice more it looks like 'images/ages01... etc.
How can i remove this default path but only for this action in controller?
VIEW:
<% #array.each do |a| %>
<%= image_tag(a, :id => 'image_' %>
If you mean you don't want the "/images" to appear
just remove the
#new_string = #str[1..#str.length]
if you pass the path with a starting slash rails won't add the default image path
so the output would be
<img src='/images00.someother.path_to_.image.jpg'>
which is the images00.someother.path_to_.image.jpg in your public directory
If you're testing in production mode, rails by default don't serve the static files.
You should change it on config/environments/production.rb the line:
config.serve_static_assets = false
As long as the question is missing some details, it might help :)

Rails 3.1: Trouble on displaying images in mailer view files

I am using Ruby on Rails 3.1 and I would like to add my web site logo (that is, an image handled through the new Asset Pipeline) to an e-mail.
If in my mailer view file I state the following:
<% # Note: '#root_url' is my application hostname (eg: http://www.mysite.com) %>
<%= link_to image_tag( "#{#root_url.to_s}/images/logo.png"), #root_url.to_s %>
it doesn't work in production mode (that is, I cannot display the logo image) because I think the Asset Pipeline uses the Fingerprinting technique and in the received e-mail it doesn't. Inspecting the HTML logo element in the e-mail I get something like this:
<img src="http://www.mysitecom/images/logo.png"> # without Fingerprinting
How can I solve the problem?
In my production.rb file I have the following commented out code:
# Enable serving of images, stylesheets, and javascripts from an asset server
# config.action_controller.asset_host = "http://assets.example.com"
in config/environments/production.rb (and other enviroment files needed) add:
config.action_mailer.asset_host = 'http://mysite.com'
after that rails will automatically add hostname in front of paths generated by image_tag
# haml
= image_tag 'foo.jpg'
will become
#html
<img alt="" src="http://mysite.com/assets/foo.jpg" >
...same apply for image_path
#haml
%table#backgroundTable{background: image_path('email-background.jpg'), width: '100%', :border => "0", :cellpadding => "0", :cellspacing => "0"}
will become
<table background="http://mysite.com/assets/email-background.jpg" border="0" cellpadding="0" cellspacing="0" id="backgroundTable" width="100%">
watch out!!!
# this will make your emails display images
config.action_mailer.asset_host = 'http://mysite.com'
is different than
# this wont make your email images work
config.action_controller.asset_host = "http://mysite.com"
All of these answers are assuming you're using the asset pipeline, but from your example, you're specifying an image in /public/images - this is not part of the asset pipeline, so all the asset_path based answers won't work, and further your initial fingerprinting supposition is incorrect.
If you put an image in /public/images, you want your image tag to have a src of http://yoursite.com/images/the-image.jpeg, no fingerprint, no asset path, nothing - just hard-code it into your view:
<img src="<%=#root_url%>/images/logo.png">
But, you have to actually have the file in that location! If you have your image in /app/assets/images, then you'll need to use image_tag and the asset pipeline as others have answered.
An alternative is to include the image logo in the mail. The mail could also be viewed offline. You can add the logo in you Mailer class, with the following code..
attachments["your_logo.png"] = File.read("#{Rails.root}/assets/images/your_logo.png")
This code will include your image to the mail. I believe when you want to show your attachment in the mail you need to do the following:
Class YourMailer < ActionMailer::Base
def sendmail
.....
attachments.inline['your_logo.png'] = File.read("#{Rails.root}/assets/images/your_logo.png")
end
And in your sendmail.html.erb view you can use the image_tag method:
<%= image_tag attachments['your_logo.png'].url %>
note: if the mail does not get shown correctly you can alternatively try the solution at:
Rails attachments inline are not shown correctly in gmail
Your mail can then also be viewed offline correctly.
Have you tried adding something like this
config.action_mailer.default_url_options = { :host => 'www.example.com' }
to your config/enviroments/production.rb file
Try:
<%= link_to image_tag( "#{#root_url.to_s}/assets/logo.png"), #root_url.to_s %>
You're giving image_tag an absolute url so it thinks it doesn't need to do any fingerprinting or anything else other than regurgitate the string you gave it. I would try
link_to( image_tag('logo.png'), #root_url)
You'll also need to set actioncontroller's asset host to get rails to generate a full url for the image rather than just a path
One caveat to note: if you change the image then the fingerprint will obviously change and so the inage URL in all of your previously sent emails will become invalid. You may wish to consider inline images, although obviously these increase the email size
Try out this one
<%= link_to image_tag( asset_path, 'logo.png'), #root_url.to_s %>
Adding mode:'rb' worked for me:
attachments.inline['Logo.jpg'] = File.read(File.join(Rails.root,'app','assets','images','Logo.jpg'), mode: 'rb')
If you compile your assets:
RAILS_ENV=production bundle exec rake assets:precompile
and use asset_path in your view:
<%= link_to image_tag( asset_path('logo.png') ), #root_url.to_s %>
--it should work in both development and production. This is the way I do it my views, and .css.scss.erb stylesheets. I assume that it doesn't make a difference that it is a view for a mailer.
make sure your html page have follwing header
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">
and render image as:
<%= image_tag('http://'+#url+'/images/header.jpg')%>
or
if you want link to image then
<%= link_to image_tag('http://'+#url+'/images/header.jpg'),root_path %>
#url = 'your website address'

How do I get the base URL (e.g. http://localhost:3000) of my Rails app?

I'm using Paperclip to allow users to attach things, and then I'm sending an email and wanting to attach the file to the email. I'm trying to read the file in and add it as an attachment, like so:
# models/touchpoint_mailer.rb
class TouchpointMailer < ActionMailer::Base
def notification_email(touchpoint)
recipients "me#myemail.com"
from "Touchpoint Customer Portal <portal#touchpointclients.com>"
content_type "multipart/alternative"
subject "New Touchpoint Request"
sent_on Time.now
body :touchpoint => touchpoint
# Add any attachments the user has included
touchpoint.assets.each do |asset|
attachment :content_type => asset.file_content_type,
:body => File.read(asset.url)
end
end
end
This gives me the following error No such file or directory - /system/files/7/original/image.png?1254497688 with the stack trace saying it's the call to File.read. When I visit the show.html.erb page, and click on the link to the image, which is something like http://localhost:3000/system/files/7/original/image.png?1254497688, the image is displayed fine.
How can I fix this problem?
Typically root_url should provide this.
File.read is expecting a file path, not a url though. If you are generating the images, you should call the image generating code and return the bytes of the generated image instead of calling File.read(…)
asset.url returns the URL to the file. This is usually /system/classname/xx/xx/style/filename.ext. You'd put this in an image_tag.
You want asset.path. It returns the full path to the file, which will usually be something like /home/username/railsapp/public/system/classname/xx/xx/style/filename.ext
HTH.
request.env["HTTP_HOST"]
I don't know why this one line of code is so elusive on the web. Seems like it should be up front and center.
as ZiggyTheHamster is saying: the asset.url is the generated url that would be used on webpages (which is why you're getting the unix-style directory slashes, as pointed out in the comments.)
asset.path should give you the OS-aware path to the file, but even that isn't needed with paperclip.
Paperclip::Attachment is already an IOStream.
You just need :body => asset like so:
touchpoint.assets.each do |asset|
attachment :content_type => asset.file_content_type,
:body => asset
end

Resources