前置き
メリット
異なるOSでもgemが保証される。
- 「OSごとに違うgemを入れなきゃ、でもそうするとGemfile.lockが衝突するからリビジョン管理から外そう」 ⇒ 知らぬ間にデプロイ先で不適切gemが使われる ⇒ 予期せぬ事態
の、リスク解消。大事。
デメリット
bundleコマンドやWebrick起動がめんどくさくなる。
-
bundle install --gemfile=path/to/Gemfile
したり -
cd path/to/Gemfile
してから実行しないといけなかったり- なぜかbundle install以外のbundleコマンドには
--gemfile
オプションがない。
- なぜかbundle install以外のbundleコマンドには
RAILS_ROOTにGemfileが在る前提じゃないと動かないライブラリがあったりする。
- ソースまで見て「だから動かないのかクソ・・・!」とか。
ハマる。
- 自動デプロイとかで間違いなくハマる。しかも前例が見つからない。つらかった。
ので、導入・保守・効果コストを理解した上で行う。
ポイント
- Gemfile.lockは、Gemfileが在る場所に作成される。
- LinuxとMacで、Gemfile.lockのディレクトリを分ける。
- GemfileもGemfile.lockもふたつ。
- 環境変数
RUBY_PLATFORM
が、LinuxとMacで異なることを利用する。- Linuxだと
linux
、Macだとdarwin
という単語が入り込んでいる。
- Linuxだと
やり方
- Gemfileの置き場所を、
RAILS_ROOT
直下ではない場所にする。-
linux
,darwin
だけが違うディレクトリを2つ作る。たとえば、- gemfiles/darwin/
- gemfiles/linux/
- それぞれに
Gemfile
,Gemfile.lock
を配置する。
-
# 配置イメージ
├── README.md
├── Rakefile
├── app
├── bin
├── config
│ ├── application.rb
│ └── boot.rb
├── db
├── gemfiles
│ ├── darwin
│ │ ├── Gemfile
│ │ └── Gemfile.lock
│ └── linux
│ ├── Gemfile
│ └── Gemfile.lock
├── lib
├── log
├── public
├── spec
└── vendor
- アプリケーションがbundleを正しく読み込めるよう、application.rbに追記する。
config/application.rb
require File.expand_path('../boot', __FILE__)
require 'rails/all'
require 'bundler' # 追記
# Require the gems listed in Gemfile, including any gems
# you've limited to :test, :development, or :production.
Bundler.require(*Rails.groups)
platform = RUBY_PLATFORM.match(/(linux|darwin)/)[0].to_sym # 追記
Bundler.require(platform) # 追記
...
- boot.rbにも追記する。
config/boot.rb
#ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__) # もともとあるのでコメントアウト
platform = RUBY_PLATFORM =~ /darwin/ ? 'darwin' : 'linux' # 追記
ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../gemfiles/#{platform}/Gemfile", __FILE__) # 追記
- 【一方のGemfile】分けたいgemに、ifやgroupを追加する。
gemfiles/darwin/Gemfile
...
# for Mac
group :darwin do
gem 'libv8', '3.16.14.3' if RUBY_PLATFORM=~ /darwin/
end
# for Linux
group :linux do
gem 'libv8', '3.3.10.4' if RUBY_PLATFORM=~ /linux/
end
...
if RUBY_PLATFORM=~ /linux/
gem 'therubyracer', '0.10.2', platforms: :ruby
else
gem 'therubyracer', platforms: :ruby
end
...
- 【もう一方のGemfile】下記のみにする。
gemfiles/linux/Gemfile
eval(Pathname(File.expand_path('../../darwin/Gemfile', __FILE__)).read) # linuxとdarwinは適宜。
動作確認
bundle install 例
bundle install --gemfile=gemfiles/darwin/Gemfile # Mac
bundle install --gemfile=gemfiles/linux/Gemfile # Linux
それぞれ正常に読み込まれ、別々にGemfile.lockが更新されたらOK!
※最初は、Gemfile.lockを退避なり削除なりしてから実行したほうがよいかも。
bundle list 例
# Mac
cd gemfiles/darwin
bundle list
# Linux
cd gemfiles/linux
bundle list
bundle update等々も同様。ちなみにbundle installもこれで出来る。
最後に
- 開発はMac、デプロイ先はCentOS、だからこの努力はきっと必要なはず・・・!
- Gemfileってただのrubyスクリプトなんだなぁと。
- Gemfile読み込みは、シンボリックリンクにしていたこともあるが、何かの拍子に何故か実ファイルになってしまったり、Winが入ってきたら対応できないよなぁと思ったりで、やめた。
- 思い出しながら書いているので抜け漏れあったらごめんなさい。