create a (Prawn) PDF inside custom DelayedJob and upload it to S3? - amazon-s3

Using: Rails 4.2, Prawn, Paperclip, DelayedJobs via ActiveJobs, Heroku.
I have a PDF that is very large and needs to be handled in the background. Inside a custom Job I want to create it, upload it to S3, and then email the user with a url when its ready. I facilitate this via a PdfUpload model.
Is there anything wrong with my approach/code? Im using File.open() as outlined in examples I found, but this seems to be the root of my error ( TypeError: no implicit conversion of FlightsWithGradesReport into String ).
class PdfUpload < ActiveRecord::Base
has_attached_file :report,
path: "schools/:school/pdf_reports/:id_:style.:extension"
end
/pages_controller.rb
def flights_with_grades_report
flash[:success] = "The report you requested is being generated. An email will be sent to '#{ current_user.email }' when it is ready."
GenerateFlightsWithGradesReportJob.perform_later(current_user.id, #rating.id)
redirect_to :back
authorize #rating, :reports?
end
/ the job
class GenerateFlightsWithGradesReportJob < ActiveJob::Base
queue_as :generate_pdf
def perform(recipient_user_id, rating_id)
rating = Rating.find(rating_id)
pdf = FlightsWithGradesReport.new( rating.id )
pdf_upload = PdfUpload.new
pdf_upload.report = File.open( pdf )
pdf_upload.report_processing = true
pdf_upload.report_file_name = "report.pdf"
pdf_upload.report_content_type = "application/pdf"
pdf_upload.save!
PdfMailer.pdf_ready(recipient_user_id, pdf_upload.id)
end
end
This results in an error:
TypeError: no implicit conversion of FlightsWithGradesReport into String

Changing this:
pdf_upload.report = File.open( pdf )
to this:
pdf_upload.report = StringIO.new(pdf.render)
fixed my problem.

Related

How to attach images in mailer from active storage association in Rails

In rails 5.2, I have a model using has_many_attached :images. I would like to send out an email that includes all associated images as attachments.
My mailer method currently looks like:
def discrepancy_alert(asset_discrepancy_id, options={})
#asset_discrepancy = AssetDiscrepancy.find asset_discrepancy_id
#asset_discrepancy.images.each_with_index do |img,i|
attachments["img_#{ i }"] = File.read(img)
end
mail to: 'noone#gmail.com', subject: "email subject"
end
obviously, File.read does not work here because img is not a path, it is a blob. I have not been able to find any info on this in the docs
Question One:
Is there a rails method for attaching a blob like this?
I can use the following instead:
#asset_discrepancy.images.each_with_index do |img,i|
attachments["img_#{ i }"] = img.blob.download
end
Question Two:
the download method could use a log of RAM, is this usage ill advised?
It seems, with the addition of ActiveStorage, that rails mailers would have some new methods for interaction between the two....I have not seen anything in the docs. All the mailer attachments[] examples use paths to a local file.
in app/mailers/mailer.rb:
if #content.image.attached?
#filename = object.id.to_s + object.image.filename.extension_with_delimiter
if ActiveStorage::Blob.service.respond_to?(:path_for)
attachments.inline[#filename] = File.read(ActiveStorage::Blob.service.send(:path_for, object.image.key))
elsif ActiveStorage::Blob.service.respond_to?(:download)
attachments.inline[#filename] = object.image.download
end
end
in mailer view:
if #filename
image_tag(attachments[#filename].url)
else
image_tag(attachments['placeholder.png'].url)
end
This worked for me in production using Amazon S3.
in mailer view:
if #object.images
#object.images.each do |image|
path = "https://www.example.com" + Rails.application.routes.url_helpers.rails_blob_path(image, only_path: true)
<img src="<%=path%>">
end
end
Here is the working solution for active storage url in email template. I have seen the images visible in gmail. You can use "rails_blob_url". This works for file stored in aws s3.
mailer.rb
....
#image_url = Rails.application.routes.url_helpers.rails_blob_url(blob),
....
mailer view file
<img src="<%= #image_url %>">

Rails helper method method not works in PDF if sending as an attachment

Hi i have create a PDF conversion in my rails application using Prawn and it working fine.
Now i am sending that PDf in an email attachment. Now problem is that i can send PDF attachment if i do not use any helper method, but when i use my format_currency method in PDf file it gives error on instance_eval method. here is my code sample:
format currency code:
module ApplicationHelper
def format_currency(amt)
unit = 'INR'
country = current_company.country
if !country.blank? && !country.currency_unicode.blank?
unit = country.currency_unicode.to_s
elsif !country.blank?
unit = country.currency_code.to_s
end
number_to_currency(amt, :unit => unit+" ", :precision=> 2)
end
end
My controller code :
pdf.instance_eval do
#company = current_company
#invoice = invoice
#invoice_line_items = invoice_line_items
#receipt_vouchers = receipt_vouchers
eval(template) #this evaluates the template with your variables
end
the error message i got :
undefined method `format_currency' for #<Prawn::Document:0x7f89601c2b68>
with this code i can send attachment successfuly if i don't use helper method but i need to use that method.
I have fixed this issue in a different manner, i have created a new currency_code method in my company model and called that in my format_currency helper method and it is working for me fine:
Here is what i have done :
def currency_code
unit = 'INR'
if !country.blank? && !country.currency_unicode.blank?
unit = country.currency_unicode.to_s
elsif !country.blank?
unit = country.currency_code.to_s
end
unit
end
and used it in my format_currency helper :
def format_currency(amt)
unit = current_company.currency_code
number_to_currency(amt, :unit => unit+" ", :precision=> 2)
end
and in my controller i have added a variable for currency and used it in my pdf file:
pdf.instance_eval do
#company = current_company
#invoice = invoice
#invoice_line_items = invoice_line_items
#receipt_vouchers = receipt_vouchers
#currency = current_company.currency_code # new added variable for currency
eval(template) #this evaluates the template with your variables
end

NameError (uninitialized constant Ckeditor::Picture): i am getting this error onclick on send it to the server

NameError (uninitialized constant Ckeditor::Picture):
i am getting this error should i write pictures controller .
i am unable to upload the image using ckeditor
In config.js
In that change the path of browser upload path give custom path there define own method. There you can write your own like
def upload_image
#func_num = params["CKEditorFuncNum"]
#ck_editor = params["CKEditor"]
if params.include?(:upload)
data = params[:upload]
#image = Upload.create(:image => data) if data.present?
end
render :layout => false
end\
coresponding view in html
- if #image
= image_tag #image.image.url
:javascript
CKEditorFuncNum = #{#func_num};
function SetUrl( fileUrl )
{
window.parent.CKEDITOR.tools.callFunction(CKEditorFuncNum, fileUrl);
}
SetUrl("#{ #image.image.url }");
note : only if you are using paperclip for upload image.

"Can't dump file" error occurs when using Paperclip attachments with Multi-step form in Rails 3

I'm having the same issue mentioned here:
Multi-step form in Rails 3 with Paperclip attachments
"TypeError in..." "can't dump File"
However, I can't seem to wrap my head around the solution mentioned in the answer:
unless #model.valid?
#model.image.clear
#model.image.queued_for_write.clear
end
Where do I put the above lines?
Here's my code for my controller:
def new
session[:member_params] ||= {}
#member = Member.new(session[:member_params])
#member.current_step = session[:member_step]
end
def create
session[:member_params].deep_merge!(params[:member]) if params[:member]
#member = Member.new(session[:member_params])
#member.current_step = session[:member_step]
if #member.valid?
if params[:back_button]
#member.previous_step
elsif #member.last_step?
#member.save if #member.all_valid?
else
#member.next_step
end
session[:member_step] = #member.current_step
end
if #member.new_record?
render "new"
else
session[:member_step] = session[:member_params] = nil
flash[:notice] = "Personal Data Sheet saved!"
redirect_to #member
end
end
I tried putting it here after the declaration of #member, but no good:
session[:member_params].deep_merge!(params[:member]) if params[:member]
#member = Member.new(session[:member_params])
unless #member.valid?
#member.image.clear
#member.image.queued_for_write.clear
end
P.S.
I thought of appending my question to the question here:
Multi-step form in Rails 3 with Paperclip attachments
But I'm not sure if it's okay to post-follow-up questions on the same issue/question.

Alter URL using ActiveResource

I am using ActiveResource to manage accessing an external service.
The external service has an URL like:
http://api.cars.com/v1/cars/car_id/range/range_num?filter=filter1,filter2
Here's my Car class:
class Car < ActiveResource::Base
class << self
def element_path(id, prefix_options = {}, query_options = nil)
prefix_options, query_options = split_options(prefix_options) if query_options.nil?
"#{prefix(prefix_options)}#{collection_name}/#{URI.parser.escape id.to_s}#{query_string(query_options)}"
end
def collection_path(prefix_options = {}, query_options = nil)
prefix_options, query_options = split_options(prefix_options) if query_options.nil?
"#{prefix(prefix_options)}#{collection_name}#{query_string(query_options)}"
end end
self.site = "http://api.cars.com/"
self.prefix = "/v1/"
self.format = :json
end
When I set up my object to get a particular car in rails console:
> car = car.new
> car.get('1234')
I get a URL like this:
http://api.cars.com/v1/cars//1234.json
How do I get the URL to include the range and range_num elements?
Also, i don't want the .json extension on the end of the URL. I've attempted overriding the element_name and collection_name methods as described here: How to remove .xml and .json from url when using active resource but it doesn't seem to be working for me...
Thanks in advance for any ideas!
Get rid of the forward slash in the URL
"#{prefix(prefix_options)}#{collection_name}/#{URI.parser.escape id.to_s}#{query_string(query_options)}"
becomes:
"#{prefix(prefix_options)}#{collection_name}#{URI.parser.escape id.to_s}#{query_string(query_options)}"