我在生产服务器上遇到了一个问题,我们有一个 Rails 应用程序,它使用 gemwicked_pdf
生成一个 PDF,它抛出了以下错误:
Failed to execute:
["/var/www/myapp/vendor/cache/ruby/2.6.0/bin/wkhtmltopdf", "file:////tmp/wicked_pdf20201004-5058-g9f64a.html", "/tmp/wicked_pdf_generated_file20201004-5058-1gjfrw5.pdf"]
Error: PDF could not be generated!
Command Error: /usr/bin/env: 'ruby2.6': No such file or directory
现在奇怪的是,这在 rake 任务中工作正常(耙任务是用sudo
执行的)
当然,Ruby 解决得很好:
$ which ruby
/usr/bin/ruby
$ which ruby2.6
/usr/bin/ruby2.6
$ ruby -v
ruby 2.6.5p114 (2019-10-01 revision 67812) [x86_64-linux-gnu]
$ echo $PATH
/home/julien/bin:/home/julien/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games
Rails应用程序与www-data
用户一起运行。 Ubuntu 16.04.5 LTS.
我的猜测是应用程序用于执行二进制文件的任何 bash 在其$PATH
中都缺少某些内容,或者也许我需要在某处有一个符号链接,但我不知道,有什么想法吗?
如何调试它以了解问题所在? 如何检查并修改 Rails 加载的 shell PATH?
更新
Rails应用程序与Nginx + Passenger一起运行。
ENV['PATH']
输出以下内容:
/var/www/myapp/vendor/cache/ruby/2.6.0/bin
以下是生成 PDF 的代码的相关部分:
#generate the PDF
pdf = WickedPdf.new.pdf_from_string(
ActionController::Base.new.render_to_string(
template: 'templates/_doc',
locals: {
url: self.url,
signature: sig,
name: full_name,
title: "some title"
}
)
)
#save the file
save_path = Rails.root.join(PATH_TO_STORE_FILE, "some-filename-#{self.clean_url}.pdf")
File.open(save_path, 'wb') do |file|
file << pdf
end
与其弄清楚在哪里编辑PATH
,解决问题的最简单方法是:
cd /var/www/myapp/vendor/cache/ruby/2.6.0/bin
ln -s /usr/bin/ruby2.6 .
这样,您将有一个指向供应商 bin 文件夹中ruby2.6
的链接,并且由于该文件夹位于 Web 服务器的路径中,因此它应该可以解决您的问题。
在某些情况下,WickedPdf试图通过调用which wkhtmltopdf
来找出wkhtmltopdf
在哪里。在这里,它正在选取一个调用 Ruby 2.6 的二进制存根(binstub),但调用它的进程在他们的 PATH 中没有。
您可以显式指定wkhtmltopdf
二进制文件的路径,如下所示:
WickedPdf.config = {
exe_path: '/usr/local/bin/wkhtmltopdf'
}
理想情况下,这应该是实际二进制文件的直接路径,而不是二进制存根,但是一些提供二进制wkhtmltopdf
的 gem 会使用 binstub 根据执行它的平台切换二进制文件。
如果使用其中之一,这样的事情应该可以工作:
WickedPdf.config = {
exe_path: "#{ENV['GEM_HOME']}/gems/wkhtmltopdf-binary-#{Gem.loaded_specs['wkhtmltopdf-binary'].version}/bin/wkhtmltopdf_linux_amd64"
}