将 RVM ruby 与 Passenger 3 一起使用
此页面包含有关将 RVM 与 Phusion Passenger 3 一起使用的说明。您应该升级到 Phusion Passenger 4 或更高版本,因为它提供了更好的 RVM 支持。有关 Phusion Passenger 4 说明,请参阅 此页面。
Passenger 3
Passenger 本质上是 Nginx 和 Apache 的“mod_ruby”。您可以选择 *一个* Ruby 来运行所有 Passenger 3 应用程序。如果您需要运行多个 Ruby 解释器,则应选择最常用的一个。然后,您可以使用代理传递到外部应用程序服务器(例如 Passenger Standalone、Unicorn、Thin、Mongrel、Mongrel2 等)来实现运行不同 Ruby 下的不同应用程序。有关此内容的完整解释(带精美图片!),请参阅 Phusion 博客上的帖子
安装带有 Passenger 的 Nginx/Apache
首先,有 passenger-install-apache2-module 和 passenger-install-nginx-module。在安装结束时,它会输出一个用于 Web 服务器的 PassengerRuby 配置代码段。它的值设置为与用于运行安装程序的 RVM Ruby 和 RVM gemset 相对应的 RVM Ruby 包装器脚本。这应该是您配置 Passenger 3 所需的一切!
如果您仍然遇到问题,而不是创建 .rvmrc 文件,请使用新的格式之一,例如 .ruby-version 或 .versions.conf
echo 1.9.3@my-app-name > .ruby-version
然后在 rails 项目中,添加一个新文件 config/setup_load_paths.rb 并添加从 RVM 1.12.0(或 head)开始,RVM 作为 gem 安装在默认 gemset 中,无需将 $LOAD_PATH 提前,但需要设置 GEM_PATH。 config/setup_load_paths.rb。
if ENV['MY_RUBY_HOME'] && ENV['MY_RUBY_HOME'].include?('rvm') begin gems_path = ENV['MY_RUBY_HOME'].split(/@/)[0].sub(/rubies/,'gems') ENV['GEM_PATH'] = "#{gems_path}:#{gems_path}@global" require 'rvm' RVM.use_from_path! File.dirname(File.dirname(__FILE__)) rescue LoadError raise "RVM gem is currently unavailable." end end # If you're not using Bundler at all, remove lines bellow ENV['BUNDLE_GEMFILE'] = File.expand_path('../Gemfile', File.dirname(__FILE__)) require 'bundler/setup'
请注意,对于 Passenger 3,您现在直接使用 ruby 包装器脚本,无需使用 passenger_ruby 包装器。
启动 Passenger Standalone
然后是 Passenger Standalone,即“passenger start”。Passenger Standalone 在内部使用 Nginx,它会在 Nginx 配置文件中写入一个 passenger_ruby 指令。该指令指向与用于运行“passenger start”命令的 RVM Ruby 和 RVM gemset 相对应的 RVM Ruby 包装器脚本。
Bundler 陷阱
在项目中使用 Bundler 时,Passenger 会尝试智能地只将 Gemfile 中列出的 gem 添加到您的 $LOAD_PATH。这可能会导致您的未列出 gem 出现“无法加载”错误(这应该只在开发过程中发生)。您可以通过在应用程序的主文件中添加以下内容来检查您的运行时加载路径
f = File.open('/tmp/load_path', 'w') f.write($:) f.close
(在“require”调用之前)。您将无法加载不在该加载路径中的任何 gem。
故障排除
- 最常见的问题是忘记路径中的 /bin/ 部分以获取正确的包装器脚本
-
下一个最常见的问题是倾听 Passenger 安装脚本的输出,了解 passenger_ruby/PassengerRuby 的位置。请务必使用上面指定的包装器脚本位置。为了更清楚地说明,请参见下面的 nginx 示例
passenger_ruby /home/wayne/.rvm/bin/passenger_ruby; * NOTICE THE '.rvm/bin' DIR ^ ^ ^ * do NOT use the actual ruby binary in .rvm/rubies/{passenger_ruby}/bin/ruby * do not listen to passenger's output for passenger_ruby as passenger is not aware of rvm.
对于系统范围(root)安装,bin 目录为 /usr/local/rvm/binpassenger_ruby /usr/local/rvm/bin/passenger_ruby;
常见问题解答
-
问:我可以在 Passenger 下运行多个项目,每个项目使用不同的 Ruby 版本吗?
答:Passenger 3 只支持在 *一个* Ruby 下运行,但您可以使用代理传递来获得每个站点/项目的行为。
-
问:如何在 Passenger 下使用自定义 gemset?
答:在没有 bundler 的情况下,您可以在 config.ru 中自行设置环境变量,例如
ENV["GEM_HOME"]=%x{"source ~/.bash_profile ; rvm ree@pancake ; rvm gemdir"}.strip
答:使用 bundler:在任何 gemset 之外安装 bundler,切换回您要使用的 gemset 并运行 bundle install 并重新启动应用程序(通过触摸 tmp/restart.txt)。这是因为 bundler 在 .bundle/environment.rb 中存储绝对路径,该路径将由 bundler 直接加载。如果这不能按预期工作,请尝试像这样运行 bundle install
bundle install $BUNDLE_PATH
如何使用 passenger-status 等命令与用户安装一起使用,但以 root 身份运行?主要的关键是在 sudoers 文件中使用通配符,如下面的示例所示。
/usr/bin/env GEM_PATH=* GEM_HOME=* PATH=* passenger-status
这是 RVM 版本低于 1.12.0 的 config/setup_load_paths.rb。
if ENV['MY_RUBY_HOME'] && ENV['MY_RUBY_HOME'].include?('rvm') begin rvm_path = File.dirname(File.dirname(ENV['MY_RUBY_HOME'])) rvm_lib_path = File.join(rvm_path, 'lib') # $LOAD_PATH.unshift rvm_lib_path require 'rvm' RVM.use_from_path! File.dirname(File.dirname(__FILE__)) rescue LoadError # RVM is unavailable at this point. raise "RVM ruby lib is currently unavailable." end end # Pick the lines for your version of Bundler # If you're not using Bundler at all, remove all of them # Require Bundler 1.0 ENV['BUNDLE_GEMFILE'] = File.expand_path('../Gemfile', File.dirname(__FILE__)) require 'bundler/setup' # Require Bundler 0/9 # if File.exist?(".bundle/environment.rb") # require '.bundle/environment' # else # require 'rubygems' # require 'bundler' # Bundler.setup # end