Rails: attachments.inline[] in mail - ruby-on-rails-3

I am looking for displaying company logo in the email when email is sent. I went thought action mailer base and there is attachment inline feature which supports images in mail.
I implemented it in this way:
in user_mailer.rb
def welcome_email(user)
#user = user
#url = "http://mealnut.com"
attachments.inline['mealnut.png']
mail(:to => user.email, :subject => "Mealnut: New Order #{order.id}")
end
in config/application.rb:
config.action_mailer.default_url_options = { :host => "mealnut.com" }
in welcome_email.html.web
<div class="logo">
<%= image_tag attachments['mealnut.png'].url, :alt => 'Mealnut', :class => 'photo' %>
</div>
But it is giving error:
undefined method `url' for nil:NilClass
Whats going wrong?

attachments and inline attachments differs only that inline will insert it via base64 but you need to attach a file anyhow to it!
attachments.inline['mealnut.png'] = File.read( Rails.root.join("app/some/path/","mealnut.png") )
than you are able to reference it in the view
hope that helped!

Related

ActionMailer mail with inline attachments not working

I am using rails 3.2.8. This is how mailer class looks like:
class Newsletter < ActionMailer::Base
default :charset => "UTF-8",
:from => "\"Example\" <info#example.com>"
def campaign
attachments.inline['image1.gif'] = File.read("#{Rails.root}/app/assets/images/image1.gif")
attachments.inline['image2.gif'] = File.read("#{Rails.root}/app/assets/images/image2.gif")
attachments.inline["image3.jpg"] = File.read("#{Rails.root}/app/assets/images/image3.jpg")
mail(:to => "mytest#example.com", :subject => "Test")
end
end
When I send it, I only receive one attachment without main body. When I look at mail source I see other parts, but I don't understand why they are not showing as they should.
I checked other similar questions but nothing helped.
Please, help me. Do you need more code to solve the problem?
Regards,
Tomaž
Did you mention the attachments in your mail-content view file?
Add this code in you mail-content view file:
<%= image_tag attachments['image1.gif'].url %>
<%= image_tag attachments['image2.gif'].url %>
<%= image_tag attachments['image3.gif'].url %>
You can also have a look at a more detailed explanation available at:
http://technical-feeds.blogspot.in/2014/02/how-to-add-attachments-and-inline.html

Allowing User to Download File from S3 Storage

Right now I am using Amazon S3 and Paperclip which is allowing my users to upload an image that is associated with the event they are creating. My ultimate goal is since others can view this event, to be able to click on the image and have it prompt a SAVE TO their computer. As of now, clicking the link will open the image in a browser window. I rather have it ask for them to download instead. All images only saved on S3, not local. Need to hide exposed s3 url as well if possible or camouflage it
Here is my current setup
Index.html
<%= link_to 'Download Creative', event.creative.url, class: "btn btn-info" %>
Event.rb
has_attached_file :creative,
:styles => { :thumb => "150x150", :custcreative => "250x75" },
:path => ":attachment/:id/:style.:extension",
:s3_domain_url => "******.s3.amazonaws.com",
:storage => :s3,
:s3_credentials => Rails.root.join("config/s3.yml"),
:bucket => '*****',
:s3_permissions => :public_read,
:s3_protocol => "http",
:convert_options => { :all => "-auto-orient" },
:encode => 'utf8'
Hoping someone can help me out.
To avoid extra load to your app (saving dyno's time in Heroku), I would rather do something like this: add this method to your model with the attachment:
def download_url(style_name=:original)
creative.s3_bucket.objects[creative.s3_object(style_name).key].url_for(:read,
:secure => true,
     :expires => 24*3600,  # 24 hours
     :response_content_disposition => "attachment; filename='#{creative_file_name}'").to_s
end
And then use it in your views/controllers like this:
<%= link_to 'Download Creative', event.download_url, class: "btn btn-info" %>
To make this work, I've just added a new action in the controller, so in your case it could be:
#routes
resources :events do
member { get :download }
end
#index
<%= link_to 'Download Creative', download_event_path(event), class: "btn btn-info" %>
#events_controller
def download
data = open(event.creative_url)
send_data data.read, :type => data.content_type, :x_sendfile => true
end
EDIT:
the correct solution for download controller action can be found here (I've updated the code above): Force a link to download an MP3 rather than play it?
Now in aws-sdk v2, there is a method :presigned_url defined in Aws::S3::Object, you can use this method to construct the direct download url for a s3 object:
s3 = Aws::S3::Resource.new
# YOUR-OBJECT-KEY should be the relative path of the object like 'uploads/user/logo/123/pic.png'
obj = s3.bucket('YOUR-BUCKET-NAME').object('YOUR-OBJECT-KEY')
url = obj.presigned_url(:get, expires_in: 3600, response_content_disposition: "attachment; filename='FILENAME'")
then in your views, just use:
= link_to 'download', url
event = Event.find(params[:id])
data = open(event.creative.url)
send_data data.read, :type => data.content_type, :x_sendfile => true, :url_based_filename => true
end
You need to set the "Content-Disposition" to "attachment" in your HTTP response header. I'm not a Rails developer - so just Google it and you'll see plenty of examples - but it probably looks something like this:
:content_disposition => "attachment"
or
...
:disposition => "attachment"

Custom message in devise invitable email

How do you pass a custom message to the devise invitable email? I want the inviter to include a message to the invitee, like "Hey check out this site".
I tried both including it in the attributes and setting an instance variable in the block, neither seem to be accessible from the email.
user = User.invite!(:email => share.to_user_email, :message => "hey check this out") do
#message = "hey it's me!"
end
you have to do rails generate devise_invitable:views users
then you will get new erb file app/views/users/mailer/invitation_instructions.html.erb which you will be able to customize in any way you want
Email template will allow you to send same message for all the emails.
Here is another way/case, when you are taking message as an input from user.
model/user.rb
attr_accessor :message
controller
User.invite!({email: email}, current_user) do |user|
user.message = params[:message]
end
/views/devise/mailer/invitation_instructions.html.erb
<p>Hello <%= #resource.email %>!</p>
<p><%= #resource.message%>.</p>
the content of the mail is in app/views/devise/mailer/invitation_instructions.html.erb. By default it is:
<p>Hello <%= #resource.email %>!</p>
<p>Someone has invited you to <%= root_url %>, you can accept it through the link below.</p>
<p><%= link_to 'Accept invitation', accept_invitation_url(#resource, :invitation_token => #resource.invitation_token) %></p>
<p>If you don't want to accept the invitation, please ignore this email.<br />
Your account won't be created until you access the link above and set your password.</p>
modify this file to customize.

Rails3: How to pass param into custom will_paginate renderer?

I've got a custom will_paginate renderer that overrides WillPaginate::ViewHelpers::LinkRenderer's link method like so:
def link(text, target, attributes = {})
"<a href='/users/95/friends_widget?page=#{target}' rel='next' data-remote='true'>#{text}</a>"
end
...and that works great, except you can see the hard-coded 95 in that link. How would I pass a parameter (e.g. user or user's ID) into the custom renderer via the Rails view?
<%= will_paginate(#user_friends, :remote => true, :renderer => FriendsRenderer) %>
Or is there something I'm missing, some easier way to do it?
BTW: #user_friends isn't available in the custom renderer, and I've already tried just adding params onto the end of that will_paginate call, e.g. :user => user)
will_paginate lets you pass in :params for the links:
will_paginate(#user_friends, :params => { :user_id => 95 })
View:
<%= will_paginate #user_friends, :renderer => 'FriendsRenderer',
:remote => true,
:link_path => friends_widget_user_path(#user) %>
class FriendsRenderer < WillPaginate::LinkRenderer
def prepare(collection, options, template)
#link_path = options.delete(:link_path)
super
end
protected
def link(page, text, attributes = {})
# Here you can use #link_path
end
end
Note that this works for the will-paginate version: 2.3.6

Rails 3 ActionMailer and Wicked_PDF

I'm trying to generate emails with rendered PDF attachements using ActionMailer and wicked_pdf.
On my site, I'm using already both wicked_pdf and actionmailer separately. I can use wicked_pdf to serve up a pdf in the web app, and can use ActionMailer to send mail, but I'm having trouble attaching rendered pdf content to an ActionMailer (edited for content):
class UserMailer < ActionMailer::Base
default :from => "webadmin#mydomain.com"
def generate_pdf(invoice)
render :pdf => "test.pdf",
:template => 'invoices/show.pdf.erb',
:layout => 'pdf.html'
end
def email_invoice(invoice)
#invoice = invoice
attachments["invoice.pdf"] = {:mime_type => 'application/pdf',
:encoding => 'Base64',
:content => generate_pdf(#invoice)}
mail :subject => "Your Invoice", :to => invoice.customer.email
end
end
Using Railscasts 206 (Action Mailer in Rails 3) as a guide, I can send email with my desired rich content, only if I don't try to add my rendered attachment.
If I try to add the attachment (as shown above), I get an attachement of what looks to be the right size, only the name of the attachment doesn't come across as expected, nor is it readable as a pdf. In addition to that, the content of my email is missing...
Does anyone have any experience using ActionMailer while rendering the PDF on the fly in Rails 3.0?
Thanks in advance!
--Dan
WickedPDF can render to a file just fine to attach to an email or save to the filesystem.
Your method above won't work for you because generate_pdf is a method on the mailer, that returns a mail object (not the PDF you wanted)
Also, there is a bug in ActionMailer that causes the message to be malformed if you try to call render in the method itself
http://chopmode.wordpress.com/2011/03/25/render_to_string-causes-subsequent-mail-rendering-to-fail/
https://rails.lighthouseapp.com/projects/8994/tickets/6623-render_to_string-in-mailer-causes-subsequent-render-to-fail
There are 2 ways you can make this work,
The first is to use the hack described in the first article above:
def email_invoice(invoice)
#invoice = invoice
attachments["invoice.pdf"] = WickedPdf.new.pdf_from_string(
render_to_string(:pdf => "invoice",:template => 'documents/show.pdf.erb')
)
self.instance_variable_set(:#lookup_context, nil)
mail :subject => "Your Invoice", :to => invoice.customer.email
end
Or, you can set the attachment in a block like so:
def email_invoice(invoice)
#invoice = invoice
mail(:subject => 'Your Invoice', :to => invoice.customer.email) do |format|
format.text
format.pdf do
attachments['invoice.pdf'] = WickedPdf.new.pdf_from_string(
render_to_string(:pdf => "invoice",:template => 'documents/show.pdf.erb')
)
end
end
end
I used of Unixmonkey's solutions above, but then when I upgraded to rails 3.1.rc4 setting the #lookup_context instance variable no longer worked. Perhaps there's another way to achieve the same clearing of the lookup context, but for now, setting the attachment in the mail block works fine like so:
def results_email(participant, program)
mail(:to => participant.email,
:subject => "my subject") do |format|
format.text
format.html
format.pdf do
attachments['trust_quotient_results.pdf'] = WickedPdf.new.pdf_from_string(
render_to_string :pdf => "results",
:template => '/test_sessions/results.pdf.erb',
:layout => 'pdf.html')
end
end
end
Heres' how I fixed this issue:
Removed wicked_pdf
Installed prawn (https://github.com/sandal/prawn/wiki/Using-Prawn-in-Rails)
While Prawn is/was a bit more cumbersome in laying out a document, it can easily sling around mail attachments...
Better to use PDFKit, for example:
class ReportMailer < ApplicationMailer
def report(users:, amounts:)
#users = users
#amounts = amounts
attachments["proveedores.pdf"] = PDFKit.new(
render_to_string(
pdf: 'bcra',
template: 'reports/users.html.haml',
layout: false,
locals: { users: #users }
)
).to_pdf
mail subject: "Report - #{Date.today}"
end
end