RailsEngineでRubyのバージョンを変えて使えないのかな〜と思って色々と調べた結果をメモ。
RailsEngineとは
エンジン (engine) は、ホストとなるRailsアプリケーションに機能を提供するミニチュア版Railsアプリケーションとみなせます。
**
すなわち、エンジンとアプリケーションは、細かな違いを除けばほぼ同じものであると考えていただいてよいでしょう。(中略)エンジンとアプリケーションは、同じ構造を共有しています。
簡単に言うと、大元のアプリケーションとは別に独立したアプリケーションを作成することができるRailsの機能の一つのこと。
モデルやコントローラーの機能は継承して共有しつつも、大元のアプリの肥大化を防ぎ切り分けて管理することができる。
詳しくは下記の記事でわかりやすく書かれています。
[Rails4/5]はじめてのMountable Engine - Qiita
Rails Engineを使ってAPIと管理画面を分離する - blog.daich.org
今回の背景
今回、どうしてもRubyのバージョンを既存の2.4系から2.5系以上に引き上げなければいけないケースが発生し、
アプリケーション全体をバージョンアップ対応するにはリスクが大きい&数ヶ月ほど時間を有することを考えた時に、
- 大元のアプリ(2.4系)とは別プロジェクトで2.5系のアプリケーションを一から作成して連携
- 大元のアプリ配下にRailsEngineの機能を使いEngine内だけ2.5系で動かせないかどうか
の2つの案が上がった。
一からアプリを作る方が確実ではあるものの、サーバーを新たに用意したりリポジトリを分けて管理したりしなくてはいけないのが面倒だったので、元々導入経験のあるRailsEngineでどうにかならないかと思い調べてみた。
検証する前は、そういったニーズが一定数ありそうだからググれば事例が出てくるんじゃないかな〜とか思っていた。
結論から言うと、使えなかった。(TT)
試したこと
- 大元のアプリ...hoge_app
- Engine側のアプリ..fuga_app
とする。
fuga_appディレクトリで2.5系をインストール
rbenvがあればディレクトリごとに異なるRubyのバージョンを入れて動かすことができるので、これはすんなり実現できた。
$ pwd /Users/hako/Project/hoge_app $ ruby -v ruby 2.4.3p205 (2017-12-14 revision 61247) [x86_64-darwin18]
大元のアプリhoge_app
では2.4.3を使っている。
$ cd fuga_app $ rbenv versions system * 2.4.3 (set by /Users/hako/Project/hoge_app/.ruby-version)
rbenv versions
で見るとまだ2.5系が入っていないのでインストール
$ rbenv install 2.5.0 Downloading ruby-2.5.0.tar.bz2... -> https://cache.ruby-lang.org/pub/ruby/2.5/ruby-2.5.0.tar.bz2 Installing ruby-2.5.0... Installed ruby-2.5.0 to /usr/local/rbenv/versions/2.5.0
$ rbenv versions system * 2.4.3 (set by /Users/hako/Project/hoge_app/.ruby-version) 2.5.0
インストールできたので、現在のfuga_appディレクトリのみ2.5系を使うよう設定
$ rbenv local 2.5.0
$ rbenv versions system 2.4.3 * 2.5.0 (set by /Users/hako/Project/hoge_app/fuga_app/.ruby-version)
先ほどまではhoge_app/.ruby-version
を参照していたのに対し、localの指定を行ったことでhoge_app/fuga_app/.ruby-version
が生成され、そちらを読み込んで2.5系が使えるようになった。
Engine側でgemのインストール
今回、そもそも2.5系にバージョンアップしたかったのは、特定のgemのサポートが2.5以上で、そのgemをどうしても使う必要があるという結論に至ったからだった。
要するに、「Ruby2.5系でsupportedのgemがインストールできて、そのgemがRailsEngine内でだけでも動いて欲しい」というのが本来の目的。
Engine側のfuga_appディレクトリには通常のrailsアプリケーションのツリーが同様に存在しているので、fuga_appのgemfileにインストールしたいgemを追加して、fuga_appディレクトリでbundle installを実行すれば良い。
hoge_app/fuga_app/Gemfile
gemspec
↑Engine側のGemfileではgemspecというファイルを読み込んでいて、インストールしたいgemはgemspecに追記する
hoge_app/fuga_app/fuga_app.gemspec
s.add_dependency "rails", "~> 5.1.5" s.add_dependency "google-ads-googleads" s.add_development_dependency "sqlite3"
今回追加したいgemは「google-ads-googleads」。
テスト環境にのみインストールしたい場合はadd_development_dependency
、そうでない場合はadd_dependency
で追記する。
これでfuga_appディレクトリでbundle installを実行するとGemfile.lockが生成され
google-ads-googleads (9.0.0)
インストールが実行できた。
大元のアプリケーション側でgemのインストール
ドキュメント等には書いていなかったのだけど、Engine側のディレクトリでgemを追加しbundle installを実行したら、大元のアプリ側でもbundle installを実行しなければいけない。
しなければいけないというか、bundle installしたタイミングでEngine側が依存しているgemを読み取って、大元のアプリ側のGemfile.lockに記載される。
ということで、大元のアプリ(hoge_app)に移動して
$ pwd /Users/hako/Project/hoge_app/fuga_app $ cd ../ $ bundle install
bundle installを実行したところ、
hoge_app/Gemfile.lock
PATH remote: fuga_app specs: fuga_app (0.1.0) google-ads-googleads rails (~> 5.1.5) . . . . . google-ads-googleads (3.2.0)
大元のアプリ側にはEngine側でlockされているものとは別バージョンがインストールされてしまった。
Ruby2.4.3でbundle installしているから当然といえば当然なような気もするけど、fuga_app側でlockされているから同じバージョンをインストールしてくれないかなとか、大元のアプリ側ではEngine側に入っているgemのインストールがスキップされるのかなとかいう淡い期待があった。。
bundlerの性質を考えると、特定のgemが依存するパッケージも合わせてinstallするはずであり、Engineの機能を使って作成したfuga_appも一つのgemとしてhoge_app/Gemfile
に記載し読み込んでいるので、これもまた考えてみれば当然だった。
当然、大元のアプリ(hoge_app)で動いているサーバーではgoogle-ads-googleads (3.2.0)
を使って動くことになるので、今回やりたかったことはできないという結論に至りました。
でも、どちらにせよhoge_app側でもインストールされるのであれば、fuga_appの中で使うgemだからといってわざわざfuga_app.gemspec
から読み込む必要があるのか(パフォーマンス上何か違いがあるのか)というのは気になりました。
両方のディレクトリでbundle installしなくちゃいけないというのは面倒だし、Engine側のアプリも大元のアプリ側のサーバーで動いているとなると別途bundle installする必要すらないのでは?と思ったり。
単純に可読性のためというか、決まりとしてそういうことなんだろうとは思うけど。。
まとめ
- RailsEngine側にインストールしたいgemはgemspecに追記
- gemspecに追記したものはEngine側のディレクトリでbundle install
- Engine内でインストールしたgemも大元のアプリ側にインストールされる
参考
bundle install | Bundler日本語ドキュメント | Ruby STUDIO