Rails 4 link to static file in public in mailer - ruby-on-rails

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 %>

Related

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

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 - 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.

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'

Resources