Rails のアプリケーションテンプレート

Railsのアプリケーションテンプレートは単純なRubyファイルであり、新規または既存のRailsプロジェクトにgemやイニシャライザを追加するためのDSL (ドメイン固有言語) を含んでいます。

このガイドの内容:

1 利用法


アプリケーションテンプレートを適用するためには、-mオプションを使ってテンプレートの場所を指定する必要があります。ファイルパスまたはURLのどちらでも使えます。

$ rails new blog -m ~/template.rb
$ rails new blog -m http://example.com/template.rb

rakeタスクapp:templateを使って、既存のRailsアプリケーションにテンプレートを適用することもできます。テンプレートの場所はLOCATION環境変数で渡す必要があります。ここでも、ファイルパスまたはURLのどちらを使ってもかまいません。

$ bin/rails app:template LOCATION=~/template.rb
$ bin/rails app:template LOCATION=http://example.com/template.rb

2 テンプレートAPI

RailsのテンプレートAPIはわかりやすく設計されています。以下は代表的なRailsアプリケーションテンプレートです。

# template.rb
generate(:scaffold, "person name:string")
route "root to: 'people#index'"
rails_command("db:migrate")

after_bundle do
  git :init
  git add: "."
  git commit: %Q{ -m 'Initial commit' }
end

以下のセクションで、APIで提供される主なメソッドの概要を解説します。

2.1 gem(*args)

生成されたGemfileファイルに、指定されたgemのエントリを追加します。

たとえば、Railsアプリケーションがbjnokogiri gemに依存しているとします。

gem "bj"
gem "nokogiri"

Gemfileでgemを指定しただけではインストールされないのでご注意ください。指定したgemをインストールするためにはbundle installを実行する必要があります。

bundle install

2.2 gem_group(*names, &block)

gemのエントリを指定のグループに含めます。

たとえば、rspec-rails gemをdevelopmentグループとtestグループだけで読み込みたい場合は以下のようにします。

gem_group :development, :test do
  gem "rspec-rails"
end

2.3 add_source(source, options={}, &block)

生成されたGemfileファイルに、指定されたソースを追加します。

たとえば、"http://code.whytheluckystiff.net"にあるgemをソースとして使いたい場合は以下のようにします。

add_source "http://code.whytheluckystiff.net"

ブロックを1つ渡すと、ブロック内のgemエントリがそのソースのグロープにラップされます。

add_source "http://gems.github.com/" do
  gem "rspec-rails"
end

2.4 environment/application(data=nil, options={}, &block)

config/application.rbファイルのApplicationクラスの内側に指定の行を追加します。

options[:env]が指定されている場合は、config/environmentsディレクトリに置かれている同等のファイルに追加します。

environment 'config.action_mailer.default_url_options = {host: "http://yourwebsite.example.com"}', env: 'production'

data引数の代わりにブロックをひとつ渡すこともできます。

2.5 vendor/lib/file/initializer(filename, data = nil, &block)

生成されたRailsアプリケーションのconfig/initializersディレクトリにイニシャライザをひとつ追加します。

たとえば、Object#not_nil?Object#not_blank?というメソッドを使いたい場合は以下のようにします。

initializer 'bloatlol.rb', <<-CODE
  class Object
    def not_nil?
      !nil?
    end

    def not_blank?
      !blank?
    end
  end
CODE

同様に、lib()lib/ディレクトリに、vendor()vendor/ディレクトリにそれぞれファイルをひとつ作成します。

file()メソッドを使えば、Rails.rootからの相対パスを渡してディレクトリやファイルを自在に作成することもできます。

file 'app/components/foo.rb', <<-CODE
  class Foo
  end
CODE

上のコードはapp/componentsディレクトリを作成し、その中にfoo.rbファイルを置きます。

2.6 rakefile(filename, data = nil, &block)

指定されたタスクを含むrakeファイルをlib/tasksの下に作成します。

rakefile("bootstrap.rake") do
  <<-TASK
    namespace :boot do
      task :strap do
        puts "i like boots!"
      end
    end
  TASK
end

上のコードはlib/tasks/bootstrap.rakeファイルを作成し、その中にboot:strap rakeタスクを置きます。

2.7 generate(what, *args)

引数を渡してRailsジェネレータを実行します。

generate(:scaffold, "person", "name:string", "address:text", "age:number")

2.8 run(command)

任意のコマンドを実行します。いわゆるバッククォートと同等です。たとえばREADME.rdocファイルを削除する場合は以下のようにします。

run "rm README.rdoc"

2.9 rails_command(command, options = {})

指定のタスクをRailsアプリケーションで実行します。たとえばデータベースのマイグレーションを行いたい場合は次のようにします。

rails_command "db:migrate"

Railsの環境を指定してrakeタスクを実行することもできます。

rails_command "db:migrate", env: 'production'

スーパーユーザーとしてタスクを実行することもできます。

rails_command "log:clear", sudo: true

2.10 route(routing_code)

ルーティングエントリをconfig/routes.rbファイルにひとつ追加します。上の手順では、scaffoldでpersonを生成し、続けてREADME.rdocを削除しました。今度は以下のようにしてPeopleController#indexをアプリケーションのデフォルトページにします。

route "root to: 'person#index'"

2.11 inside(dir)

ディレクトリを指定してコマンドをひとつ実行します。たとえば、edge railsのコピーがあり、アプリケーションからそこにシンボリックリンクを張るには以下のようにします。

inside('vendor') do
  run "ln -s ~/commit-rails/rails rails"
end

2.12 ask(question)

ask()はユーザーからのフィードバックを受け取ってテンプレートで利用するのに使います。たとえば、追加される新品のライブラリに付ける名前をユーザーに入力してもらうには、以下のようにします。

lib_name = ask("ライブラリに付ける名前を入力してください")
lib_name << ".rb" unless lib_name.index(".rb")

lib lib_name, <<-CODE
  class Shiny
  end
CODE

2.13 yes?(question)またはno?(question)

テンプレートでユーザーからの入力に基いて処理の流れを変えたい場合に使います。たとえば、指定があった場合にのみRailsをFreezeしたい場合は以下のようにします。

rails_command("rails:freeze:gems") if yes?("Freeze rails gems?")
# no?(question) はyes?と逆の動作

2.14 git(:command)

Railsテンプレートで任意のgitコマンドを実行します。

git :init
git add: "."
git commit: "-a -m 'Initial commit'"

2.15 after_bundle(&block)

gemのバンドルとbinstub生成の完了後に実行したいコールバックを登録します。生成したファイルをバージョン管理するところまで自動化したい場合に便利です。

after_bundle do
  git :init
  git add: "."
  git commit: "-a -m 'Initial commit'"
end

これらのコールバックは--skip-bundle--skip-springを指定した場合でもスキップされずに実行されます。

3 高度な利用法

アプリケーションテンプレートは、Rails::Generators::AppGeneratorインスタンスのコンテキストで評価されます。ここで使われるapplyアクションはThorが提供しています。 これにより、このインスタンスを必要に応じて拡張したり変更したりできます。

たとえば、source_pathsメソッドを上書きしてテンプレートの位置を指定することができます。これにより、copy_fileなどのメソッドでテンプレートの位置からの相対パスを指定できるようになります。

def source_paths
  [__dir__]
end