Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
Help us understand the problem. What is going on with this article?

Gemfile.lockをLinuxとMacで分ける

More than 5 years have passed since last update.

前置き

メリット

異なるOSでもgemが保証される。

  • 「OSごとに違うgemを入れなきゃ、でもそうするとGemfile.lockが衝突するからリビジョン管理から外そう」 ⇒ 知らぬ間にデプロイ先で不適切gemが使われる ⇒ 予期せぬ事態
    の、リスク解消。大事。

デメリット

bundleコマンドやWebrick起動がめんどくさくなる。

  • bundle install --gemfile=path/to/Gemfileしたり
  • cd path/to/Gemfileしてから実行しないといけなかったり
    • なぜかbundle install以外のbundleコマンドには--gemfileオプションがない。

RAILS_ROOTにGemfileが在る前提じゃないと動かないライブラリがあったりする。

  • ソースまで見て「だから動かないのかクソ・・・!」とか。

ハマる。

  • 自動デプロイとかで間違いなくハマる。しかも前例が見つからない。つらかった。

ので、導入・保守・効果コストを理解した上で行う。

ポイント

  • Gemfile.lockは、Gemfileが在る場所に作成される。
  • LinuxとMacで、Gemfile.lockのディレクトリを分ける。
    • GemfileもGemfile.lockもふたつ。
  • 環境変数RUBY_PLATFORMが、LinuxとMacで異なることを利用する。
    • Linuxだとlinux、Macだとdarwinという単語が入り込んでいる。

やり方

  • 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が入ってきたら対応できないよなぁと思ったりで、やめた。
  • 思い出しながら書いているので抜け漏れあったらごめんなさい。
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away