Rails PDFKit - Errno::ENOENT (No such file or directory) when using to_file - ruby-on-rails

Whenever I try to generate a pdf using to_file, the process will just hang, and when I stop the development server I get Errno::ENOENT (No such file or directory - path/to/pdf). However, I am able to render a pdf inline using to_pdf. I'm also able to generate PDFs from the command line in the same folder that I'm trying to generate them in with to_file.
I'm using Rails 3.2.12 and pdfkit 0.8.2. I've tried using wkhtmltopdf versions 0.9.6 through 0.12.4. I'm on Ubuntu 14.04.
Example from controller:
html = render_to_string(:action => "show.html.erb", :formats => :html)
kit.stylesheets << "{Rails.root}/app/assets/stylesheets/stylesheet1.css"
kit.stylesheets << "#{Rails.root}/vendor/assets/stylesheets/stylesheet2.css"
kit.to_file("#{Rails.root}/folder_to_write_to/generated_pdf.pdf")

Turns out the issue was the asset pipeline conflicting with wkhtmltopdf. Added config.threadsafe! to development.rb and it started working.

Another issue can be the default options passed. For example, when I left the default print_media_type option in place, found this message in the log:
The switch --print-media-type, is not support using unpatched qt, and will be ignored."
Only when I override that does it work for me, either in the initializer or like so:
PDFKit.new(html, {print_media_type: false})
The message says it'll be ignored, but it wasn't. It was causing the file to not get generated.

Related

Attach a pdf in asset pipeline using ActionMailer Rails 4

I'm trying to attach a file to an email. The file is in assets/downloads/product.pdf
In the mailer, I have:
attachments["product.pdf"] = File.read(ActionController::Base.helpers.asset_path("product.pdf"))
I've tried:
attachments["product.pdf"] = File.read(ActionController::Base.helpers.asset_url("product.pdf"))
...and even:
attachments["product.pdf"] = File.read(ActionController::Base.helpers.compute_asset_host("product.pdf") + ActionController::Base.helpers.compute_asset_path("product.pdf"))
I always get the same error:
EmailJob crashed!
Errno::ENOENT: No such file or directory - //localhost:3000/assets/product.pdf
...or a variation on the theme. But even when I try using asset_url in the view or just put the url in the browser it works:
http://localhost:3000/assets/product.pdf
I've also tried using straight up:
File.read("app/assets/downloads/product.pdf")
File.read("downloads/product.pdf")
...which works in dev environment but not on staging server (heroku). Error is still:
Errno::ENOENT: No such file or directory - downloads/product-market-fit-storyboard.pdf
Also tried:
File.read("/downloads/product.pdf")
File.read("http://lvh.me:3000/assets/product.pdf")
...don't work at all.
Ideas?
you should use syntex like this.it is work for me may be will work for you also.
File.open(Dir.glob("#{Rails.root}/app/assets/downloads/product.pdf"), "r")
When using mailer, you shouldn't use assets pipline. Asset pipeline would be useful if you wanted to have link to a file inside your email. When rendering an email, action mailer has access to files in app directory.
Please read about attachments in action mailer guide. As you can see, you just need to pass path to a file, not url:
attachments['filename.jpg'] = File.read('/path/to/filename.jpg')

Dynamic CSS using Sprockets

I'm working on a site builder in rails and I would like to render the sites css using Sprockets SCSS processors. Since the user can change colors and logos, I can't use Sprockets precompilation so I've started working on a Rails SCSS template handler to handle dynamic views.
The goal is to compile 'app/views/sites/show.css.scss' any time /sites/43543.css is requested. Here's what I have so far. You'll notice I first run the template through the ERB processor and then attempt to run it through Sprockets.
https://gist.github.com/3870095
Manuel Meurer came up with an alternative solution that writes the ERB output to a path and then triggers the Asset Pipeline to compile it. I was able to get his solution to work locally but it wont work on heroku because the asset path is not writable. Files can only be written to the tmp directory and those files are only guaranteed for a single request.
http://www.krautcomputing.com/blog/2012/03/27/how-to-compile-custom-sass-stylesheets-dynamically-during-runtime/
After a long day I was able to solve my problem thanks to John Feminella and his post on google. The challenging part for me was figuring out how to create a new Sprockets::Context. Luckily John's solution doesn't require a Context.
Updated gist here
Attempt #1
This code does not allow importing css files from the asset pipeline.
#import "foundation"; works because foundation is loaded as a compass module
#import "custom_css"; results in an error message saying the file could not be found
def call(template)
erb = ActionView::Template.registered_template_handler(:erb).call(template)
%{
options = Compass.configuration.to_sass_engine_options.merge(
:syntax => :scss,
:custom => {:resolver => ::Sass::Rails::Resolver.new(CompassRails.context)},
)
Sass::Engine.new((begin;#{erb};end), options).render
}
end
Attempt #2
This code fails to embed base64 urls using asset-data-url
def call(template)
erb = ActionView::Template.registered_template_handler(:erb).call(template)
%{
compiler = Compass::Compiler.new *Compass.configuration.to_compiler_arguments
options = compiler.options.merge({
:syntax => :scss,
:custom => {:resolver => ::Sass::Rails::Resolver.new(CompassRails.context)},
})
Sass::Engine.new((begin;#{erb};end), options).render
}
end
Attempt 3
Turns out you can use empty values while creating the context. Code below works in development but throws an error in production.
ActionView::Template::Error (can't modify immutable index)
It appears the error occurs in Sprockets::Index which is used instead of Sprockets::Environment in production. Switching to Sprockets::Environment doesn't solve the problem either.
def call(template)
erb = ActionView::Template.registered_template_handler(:erb).call(template)
%{
context = CompassRails.context.new(::Rails.application.assets, '', Pathname.new(''))
resolver = ::Sass::Rails::Resolver.new(context)
compiler = Compass::Compiler.new *Compass.configuration.to_compiler_arguments
options = compiler.options.merge({
:syntax => :scss,
:custom => {:resolver => resolver}
})
Sass::Engine.new((begin;#{erb};end), options).render
}
end

JRuby with acts_as_flying_saucer on windows

I've been using Jruby with Rails and acts_as_flying_saucer to successfully generate PDF files for almost a year now. I'm having to move some apps off of our Linux server to a Windows2003 box. This shouldn't cause too much problem as Tomcat/JRuby run just fine on Windows.
The problem I'm having is when acts_as_flying_saucer deposits an HTML file in my temp directory (c:\tmp) it never converts to a PDF. Then Actionpack never sees it and throws an error:
ActionController::MissingFile in ProjectsController#pdf
Cannot read file c:/tmp/b5b79e6ef202dbaa112232220e86a010.pdf
Indeed the file is not there. I added these lines to my production.rb:
ActsAsFlyingSaucer::Config.options = {
:classpath_separator => ';', # classpath separator. unixes system use ':' and windows ';'
:tmp_path => 'c:/tmp', # path where temporary files will be stored
:nailgun =>false
}
but it still won't produce a PDF. I've also tried reversing the directory separator (and properly escaping it of course).
Is anyone else doing this successfully?

I can't get rails plugin wicked_pdf to work

I wanted to create PDFs for my rails application using wkhtml2pdf and wicked_pdf.
I downloaded and extracted wkhtml2pdf beta 4 and placed it in /usr/local/bin/wkhtml2pdf
I tried running it on a web site and it gave a nice result.
In my rails application (2.3.4) I installed wicked_pdf:
script/plugin install git://github.com/mileszs/wicked_pdf.git
script/generate wicked_pdf
Everything seemed to be ok.
inside script/console I run the following - (with the following output)
wp = WickedPdf.new
=># WickedPdf:0xb62f2c70 #exe_path="/usr/local/bin/wkhtmltopdf"
HTML_DOCUMENT = "<html><body>Hello World</body></html>"
=> "<html><body>Hello World</body></html>"
pdf = wp.pdf_from_string HTML_DOCUMENT
=> "/usr/local/bin/wkhtmltopdf - - -q"
=> "\n\n\n\n\n\n\n\n\n\n"
of course this isn't good. According to the test the result of my last command should start with "%pdf-1.4"
Any idea what I can do?
Having the same problem. Removed the -q option from the wicked_pdf.rb file on line 19 and then was able to get the proper string on the console.
=> "%PDF-1.4\n1 0 obj\n<<\n/Title ...
This also seems to have solved other problems. The PDF still didn't render correctly when using it from the web site - embedded font issue - on to the next issue now.
Hopefully this will work for you.

FileTest.exists? issue with ruby on rails

I am trying to check if a file exists in my rails application.
I am running ruby 1.8.6 and rails 2.1.2 with windows XP.
So, the problem is that the FileTest.exists? method doesn't seem to be working. I have simplified the code to this point :
if FileTest.exists?("/images/header.jpg")
render :text => "yes"
else
render :text => "no <img src='/images/header.jpg' />"
end
If I do that the system displays "no" and then includes the image that displays correctly because /images/header.jpg exists.
I tried FileTest.exists?, FileTest.exist?, File.exists?, File.exist? and nothing seems to be working.
What am I doing wrong ?
Thanks
I'm guessing it's because you're asking whether a file "header.jpg" exists in a directory "images" off of the root directory for your system (which on Windows I'd assume is "c:\"). Try putting the full path (from the filesystem root) to the "/images" directory rather than the URL path.
In particular, as pointed out by #Brian, you should use:
FileTest.exists?(RAILS_ROOT + "/images/header.jpg") # < rails 3.0
FileTest.exists?(Rails.root + "/images/header.jpg") # >= rails 3.0
Add RAILS_ROOT to the filename that you're checking before calling exists?

Resources