第11回: Bundler

2010/05/17

前回までで、タスク管理アプリケーション Nchak はかなり形になってきました。

まだ、タスクの名前や日付を変更する機能がありませんが、今回は少し趣向を変えて、Rails 3.0 の目玉である Bundler の話をしましょう。

Bundler は、Ruby アプリケーションが動作するのに必要な、別の言い方をすれば、アプリケーションが依存する Gem パッケージの管理ツールです。

Rails 2.x では、config/environment.rbconfig/environments/*.rbconfig.gem メソッドを使用して、依存する Gem パッケージを宣言し、rake gems:install でまとめてインストールしていました。Bundler はこれに代わるパッケージ管理機構です。

Gemfile

Bundler では、Rails アプリケーションのルートディレクトリにある Gemfile に、依存するパッケージを列挙します。

初期状態では、次のようになっているはずです。

source 'http://rubygems.org'

gem 'rails', '3.0.0'

# Bundle edge Rails instead:
# gem 'rails', :git => 'git://github.com/rails/rails.git'

gem 'sqlite3-ruby', :require => 'sqlite3'

# Use unicorn as the web server
# gem 'unicorn'

# Deploy with Capistrano
# gem 'capistrano'

# Bundle the extra gems:
# gem 'bj'
# gem 'nokogiri'
# gem 'sqlite3-ruby', :require => 'sqlite3'
# gem 'aws-s3', :require => 'aws/s3'

# Bundle gems for the local environment. Make sure to
# put test-only gems in this group so their generators
# and rake tasks are available in development mode:
# group :test do
#   gem 'webrat'
# end

これを次のように修正してください。

source 'http://rubygems.org'

gem 'rails', '3.0.0'
gem 'sqlite3-ruby', :require => 'sqlite3'
gem 'will_paginate', '3.0.pre2'

コメント行を除くと、元々書かれていたパッケージは rails と sqlite-ruby だけです。これに will_paginate を追加しています。

執筆時点(2010/05/20)では、will_paginate の最新版は 2.3.12 ですが、これは Rails 3.0 に対応していません。ここでは、β版のパッケージを使うため、'3.0.pre' とバージョン番号を指定しています。

[更新] will_paginateのバージョンを 3.0.pre から 3.0.pre2 に変更しました。3.0.pre では「DEPRECATION WARNING: railtie_name is deprecated and has no effect.」という警告が出ることを、読者の方から教えていただきました。(2011/5/9)

インストール

Bundler は、コマンド一発で依存関係を調べ、必要なすべてのパッケージをインストールしてくれます。

まず、必要なパッケージがインストールされているかどうか調べます。

% bundle check
Your Gemfile's dependencies could not be satisfied
Install missing gems with `bundle install`

続いて、インストールします。

% bundle install
Fetching source index from http://rubygems.org/
Using rake (0.8.7) from bundler gems 
Using abstract (1.0.0) from system gems 
Using builder (2.1.2) from system gems 
Using i18n (0.3.7) from system gems 
Using memcache-client (1.8.3) from bundler gems 
Using tzinfo (0.3.20) from bundler gems 
Using activesupport (3.0.0) from bundler gems 
Using activemodel (3.0.0) from bundler gems 
Using erubis (2.6.5) from system gems 
Using rack (1.1.0) from system gems 
Using rack-mount (0.6.3) from bundler gems 
Using rack-test (0.5.3) from system gems 
Using actionpack (3.0.0) from bundler gems 
Using mime-types (1.16) from system gems 
Using polyglot (0.3.1) from system gems 
Using treetop (1.4.5) from system gems 
Using mail (2.2.1) from bundler gems 
Using text-hyphen (1.0.0) from system gems 
Using text-format (1.0.0) from system gems 
Using actionmailer (3.0.0) from bundler gems 
Using arel (0.3.3) from system gems 
Using activerecord (3.0.0) from bundler gems 
Using activeresource (3.0.0) from bundler gems 
Using bundler (0.9.25) from system gems 
Using cgi_multipart_eof_fix (2.5.0) from system gems 
Using daemons (1.0.10) from system gems 
Using fastthread (1.0.7) from system gems 
Using gem_plugin (0.2.3) from system gems 
Using thor (0.13.6) from system gems 
Using railties (3.0.0) from bundler gems 
Using rails (3.0.0) from bundler gems 
Using sqlite3-ruby (1.2.5) from system gems 
Installing will_paginate (3.0.pre2) from rubygems repository at http://rubygems.org/
Your bundle is complete! Use `bundle show [gemname]` to see where a bundled gem is installed.

Linux および Mac OS X ユーザーへの注意。bundle install の前に sudo を付けたくなるかもしれませんが、付けないでください。bundle コマンドは、実行途中であなたのパスワードを尋ね、root 権限で Gem パッケージをインストールしてくれます。(加筆訂正、2010-10-11)

サーバーが動いていたら、ここで再起動してください。再起動を忘れると undefined method paginate for Class というエラーが出ます。

読者の方からの指摘により、サーバー再起動の件を追加しました。(2011-06-15)

ページネーション

will_pagination パッケージを利用して、タスクリストにページネーション機能を追加しましょう。

まず、シードデータを用意します。db/seeds/development/tasks.rb を開いて、次のように修正してください。

Task.create(:name => "Task 0", :due_date => Date.today, :done => true)

1.upto(100) do |n|
  Task.create(:name => "Task #{n}", :due_date => n.days.from_now, :done => false)
end

シードデータを投入します。

% rake db:reset

app/controllers/tasks_controller.rb を開いて、アクション index と done を修正します。

class TasksController < ApplicationController
  def index
    @task = Task.new
    @tasks = Task.undone.paginate(:page => params[:page], :per_page => 10)
  end

  def done
    @task = Task.new
    @tasks = Task.done.paginate(:page => params[:page], :per_page => 10)
    render :action => 'index'
  end

  (省略)
end

app/views/tasks/index.html.erb を修正します。

  (省略)
</table>

<%= will_paginate(@tasks) %>

新規ファイル public/stylesheets/pagination.css を次のように作成します。

div.pagination {
  text-align: center;
  padding: 5px;
}

div.pagination a {
  background-color: #666;
  color: #fff;
  padding: 5px;
}

div.pagination em {
  background-color: #ccc;
  font-weight: bold;
  font-style: normal;
  padding: 5px;
}

div.pagination span.disabled {
  background-color: #ccc;
  padding: 5px;
}

動作確認

ブラウザでタスク一覧ページを開きます。

画面キャプチャ1

「Next」リンクをクリックすると、2ページ目が表示されます。

画面キャプチャ2