Rails 3.1: Trouble on displaying images in mailer view files - ruby-on-rails

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'

Related

wicked_pdf_image_tag resolves to public folder when looking for images

I want to render an image that a user uploads in a PDF.
I am saving the image to the current Rails directory public folder.
Images are being saved at the moment inside the public folder.
Everything works in development but when in production, it is thinking that the image is part of the assets and raises the "image is not in the assets" error.
In development, it is looking at the correct path inside the public folder.
In production with the code below, it looks at public/public for the image.
This is the code that I have in my view that renders the PDF.
<% #images.each do |image| %>
<% if Rails.env != "development" %>
<%= wicked_pdf_image_tag ("public/#{image.original_filename}")%>
<% else %>
<%= wicked_pdf_image_tag(image.original_filename)%>
<% end %>
<% end %>
I tried using
wicked_pdf_image_tag("public/#{image.original_filename}")
but it returns an assets error since its looking inside public/assets folder.
I also tried using
wicked_pdf_image_tag("/public#{image.original_filename}")
but it results in public/public folder, which the image is not inside there but instead one level up.
When I try to retrieve the image I expect for the wicked_pdf_image_tag to look at the public/ folder for the image.
wicked_pdf_image_tag is a shorthand for image_tag with asset path resolved with wicked pdf rules (see wicked_pdf/wicked_pdf_helper/assets.rb):
def wicked_pdf_image_tag(img, options = {})
image_tag wicked_pdf_asset_path(img), options
end
def wicked_pdf_asset_path(asset)
if (pathname = asset_pathname(asset).to_s) =~ URI_REGEXP
pathname
else
"file:///#{pathname}"
end
end
So when you need some variations, nothing prohibits you from using image_tag directly with correct image url/path. The catch is that wicked_pdf need absolute file path at local filesystem to render (and plain image url for html preview):
image_tag "file://#{File.expand_path("public/your_image_path_goes_here.jpg")}"
Also nore that original_filename is not the name of that file in your storage, it's the name of the file at client machine during upload. You need to use storage path, this depends on your upload library, for example for Paperclip this would be like yourmodel.image.path

Why do image tags work in regular views but not mailer views?

Why does the below code show images on regular Rails views (webpages) but not show the images when used in mailer views (i.e. the emails I send from the app)? The images are located in /app/assets/images.
<%= image_tag "hr1.png" %>
<%= image_tag "pic_mountain.jpg" %>
<%= link_to image_tag("hr1.png", alt: "Sample alt text"), 'http://google.com' %>
As a follow up, is this the best way to include images in html emails being sent to users? Should I somehow store the images at www.url.com/images/sample_pic.jpg? If so, how do you do this? I'm using mailer classes I created that inherit from ActionMailer. Also, this is Rails 4.1.6. Thanks!
The ERB you posted generates html of the form
<img src="/assets/hr1.png" />
(Iglorying asset digests for brevity), ie it contains only the path to the image and the browser uses the host and protocol the containing page was loaded from.
In an email this doesn't work because there is no such host. You can either include the host in the url or add the images as inline attachments.
The most basic way for the first is to do something along the lines of
image_tag(image_url("foo", host: "example.com"))
You can also set default_url_options on your mailer so that you don't have to do this over and over again.
For inline attachments you first add the image as an attachment (in your mailer)
attachments.inline['foo.png'] = File.read(Rails.root.join("app", "assets", "images", "foo.png")
And then in your view you use it like so:
<%= image_tag attachments['foo.png'].url -%>
Note that this turns your email into a multipart email, so you shouldn't try and force the content type to text/html

Rails 4 link to static file in public in mailer

In a Rails 4 app, I have a static file stored in the /public directory. And I have a view partial that links to that file like this:
<%= "Please download the #{link_to 'Static file', '/static_filename.docx'}".html_safe %>
The partial is used in both a regular view and in a mailer view. In the regular view, this works perfectly, and the link url is like this:
www.example.com/static_filename.docx
But in the mailer, the url comes out like this, missing the host name:
/static_filename.docx
This, despite the fact that I took care to configure the default url in config/environments/production.rb as such:
config.action_mailer.default_url_options = { :host => 'http://www.example.com' }
I'm puzzled as to what I am doing wrong, and why the regular view works when the mailer does not work.
Any help would be greatly appreciated!
You should your asset host for action mailer
config.action_mailer.asset_host = "http://www.yourdomain.com"
Secondly, use the asset_path() wrapper on your asset, ie
<%= "Please download the #{link_to 'Static file', asset_path('/static_filename.docx')}".html_safe %>

Rails - ActionMailer view: how do I link to a file in my public folder

I want to send an email to a user with a link to download a PDF file in my public folder. How do I create the link from within an ActionMailer view? I need a solution that will work in my Test, Development, and Production environments (so, no hard coded links).
If you already have a route that you use in a normal view, then you can just replace _path with _url.
If you are building a custom link, then just use the root_url variable in a string which will print out: http://yourhost.com/
eg for HTML emails, assuming a filename variable
<%= link_to 'Download PDF', "#{root_url}#{filename}" %>
for Text emails:
<%= "#{root_url}#{filename}" %>
Make sure you set your correct host name for each environment in your config/environments/ENV.rb as this is where the _url gets its hostname from
eg: config/environments/production.rb
config.action_mailer.default_url_options = { :host => 'yourhost.com' }

Get absolute URL for paperclip attachment

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.

Resources