Rails Engine(gem)を作成していると、導入の際、利用者(本体側)で何かと作業してもらわないといけないことが生じがちです。
migrationファイルのコピー、rake db:migrate
の実行、本体側のroutes.rb
の書き換え......これらの作業を利用者に強いるのは、Rails Engine導入のハードルを上げることになりかねません。
ですが、もしも下記のようにコマンド一発で上記の作業をRails Engine側でやってくれるとすれば、利用者は楽になると思いませんか?
rails g (gem名):install
本記事では、foremというRails Engineのやり方を参考にして、Rails Engineでのインストーラ作成方法を紹介します。
forem: https://github.com/rubysherpas/forem
install_generatorの作成
下記のように、Rails::Generators::Base
を継承したクラスを作成します。
置き場所はlib以下のどこでもいいと思いますが、私はforemに習い、lib/generators
以下に配置しています。
require "rails/generators"
module OkuribitoRails
class InstallGenerator < Rails::Generators::Base
class_option "with-migrate", type: :boolean
def start
puts "Start installing OkuribitoRails..."
puts "*" * 80 + "\n"
end
def install_migrations
puts "Copying over OkuribitoRails migrations..."
Dir.chdir(Rails.root) do
`rake okuribito_rails:install:migrations`
end
end
def run_migrations
return unless options["with-migrate"]
puts "Running rake db:migrate"
`rake db:migrate`
end
def mount_engine
puts "Insert routing..."
route("mount OkuribitoRails::Engine, :at => '/okuribito_rails'")
end
def finished
puts "\n" + ("*" * 80)
puts "Done! OkuribitoRails has been successfully installed."
end
end
end
インストーラは、メソッドを定義した順番に実行されます。(定義したメソッドを呼び出すコードを書く必要がありません!)
私が理解している範囲で、やっていることを一つ一つ解説していきたいと思います。
インストール開始(start)
何も説明することはありません。
今からインストール開始するよ、って標準出力しているだけですね。
migrationファイルのコピー(install_migration)
本体側のrootディレクトリに移動しつつ、rake okuribito_rails:install:migrations
を実行しています。
こうすることで、本体側のdb/migrate
以下に、Rails Engineのmigrationファイルが配置されます。
なお、二回以上実行されたとしても、同名のmigrationファイルが既にあるので、エラーや変な挙動を起こすことはありません。
rake db:migrateの実行(run_migrations)
オプションが与えられていない場合、ガードして即メソッドを抜けるようにしています。
オプションの定義方法ですが、下記のように書くことができます。
class_option "with-migrate", type: :boolean
こう書くことで、インストーラ実行時にオプションを与えられるようになります。
オプションを与えてインストーラを実行したい場合は、下記のようなコマンドとなります。
rails g (gem名):install --with-migrate
routes.rbの書き換え(mount_engine)
これだけでよしなにroutes.rbに、Rails Engineのマウントを差し込んでくれます。
route("mount OkuribitoRails::Engine, :at => '/okuribito_rails'")
二回以上インストーラが実行されたとしても、既にルーティングが定義されているので、エラーを起こしたり、重複定義したりすることはありません。
賢いですね。こういう便利な仕組みには積極的に乗っかっていきたい。
インストール終了(finished)
開始同様、インストールが完了した旨を標準出力しているだけですね。
実行結果
作成したRails Engineをbundle installし終えた状態で、以下のようにコマンドを実行してみます。
$ rails g okuribito_rails:install --with-migrate
Start installing OkuribitoRails...
********************************************************************************
Copying over OkuribitoRails migrations...
Running rake db:migrate
Insert routing...
route mount OkuribitoRails::Engine, :at => '/okuribito_rails'
********************************************************************************
Done! OkuribitoRails has been successfully installed.
結果は端折りますが、無事にmigrationが実行され、routes.rbも書き換えられた状態になりました。
おわりに
今回、Railsジェネレータの使い勝手を手っ取り早く感じていただくために、ミニマムな例で紹介させていただきました。
簡単にインストーラを作成できる、ということを感じていただけたのではないでしょうか。