使用 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 部落格上的文章
安裝 Nginx/Apache 搭配 Passenger
首先,有 passenger-install-apache2-module 和 passenger-install-nginx-module。在安裝結束時,它會為網路伺服器輸出 PassengerRuby 組態片段。其值設定為與用於執行安裝程式的 RVM Ruby 和 RVM gemset 相應的 RVM Ruby 包裝指令碼。這應該是您所有 Passenger 3 組態所需的!
如果您仍然遇到問題,請使用 .ruby-version 或 .versions.conf 等新格式,而不是建立 .rvmrc 檔案
echo 1.9.3@my-app-name > .ruby-version
然後在 Rails 專案中,新增一個新檔案 config/setup_load_paths.rb,並新增從 RVM 1.12.0(或 head)開始,RVM 已安裝為預設 gemset 中的 gem,無需取消 $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,並將 passenger_ruby 指令寫入 Nginx 組態檔案。此指令指向與用於執行「passenger start」指令的 RVM Ruby 和 RVM gemset 相應的 RVM Ruby 包裝指令碼。
Bundler 陷阱
在專案中使用 Bundler 時,Passenger 會嘗試聰明地只將 Gemfile 中列出的寶石新增到 $LOAD_PATH。這可能會導致未列出寶石的「無法載入」錯誤(這只會在開發期間發生)。您可以透過在應用程式的 main 檔案中新增以下程式碼來檢查執行時期的載入路徑(在「require」呼叫之前)。您將無法載入不在載入路徑中的任何寶石。
f = File.open('/tmp/load_path', 'w') f.write($:) f.close
到應用程式的 main 檔案中(在「require」呼叫之前)。您將無法載入不在載入路徑中的任何寶石。
疑難排解
- 最常見的問題是忘記路徑的 /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 下使用自訂寶石集?
答:沒有 bundler,您可以在 config.ru 中自行設定環境變數,如下所示
ENV["GEM_HOME"]=%x{"source ~/.bash_profile ; rvm ree@pancake ; rvm gemdir"}.strip
答:使用 bundler:在任何寶石集之外安裝 bundler,切換回您要使用的寶石集,然後執行 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