LoginSignup
7
5

More than 5 years have passed since last update.

Rails Engineで簡単にインストーラを作成する方法

Last updated at Posted at 2017-01-08

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以下に配置しています。

install_generator.rb
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ジェネレータの使い勝手を手っ取り早く感じていただくために、ミニマムな例で紹介させていただきました。
簡単にインストーラを作成できる、ということを感じていただけたのではないでしょうか。

7
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
5