シングルトン・リソース

2008/12/21

前回は、blog_entries コントローラの機能テストを通しました。

今日は、account コントローラです。

> ruby -Itest test/functional/account_controller_test.rb
Loaded suite test/functional/account_controller_test
Started
FF....
Finished in 0.262014 seconds.

  1) Failure:
test_edit1(AccountControllerTest)
    [/usr/lib/ruby/gems/1.8/gems/actionpack-2.2.2/lib/action_controller/assertions/selector_assertions.rb:297:in `assert_select'
     test/functional/account_controller_test.rb:49:in `test_edit1'
     /usr/lib/ruby/gems/1.8/gems/activesupport-2.2.2/lib/active_support/testing/setup_and_teardown.rb:60:in `__send__'
     /usr/lib/ruby/gems/1.8/gems/activesupport-2.2.2/lib/active_support/testing/setup_and_teardown.rb:60:in `run']:
Expected at least 1 element matching "form[action='/account']", found 0.
<false> is not true.

  2) Failure:
test_routing(AccountControllerTest)
    [test/functional/account_controller_test.rb:18:in `test_routing'
     /usr/lib/ruby/gems/1.8/gems/activesupport-2.2.2/lib/active_support/testing/setup_and_teardown.rb:60:in `__send__'
     /usr/lib/ruby/gems/1.8/gems/activesupport-2.2.2/lib/active_support/testing/setup_and_teardown.rb:60:in `run']:
The generated path <"/account/show"> did not match <"/account">

6 tests, 17 assertions, 2 failures, 0 errors

今回は、ページネーションには関係ないようですね。

テストメソッド test_routing から見ていきましょう。失敗は次の箇所で起きています。

    assert_generates '/account',
      { :controller => 'account', :action => 'show' }

これは、Rails 2.0 からシングルトン・リソースのコントローラの名前が単数形から複数形に変わったことによるものです。
account リソースに対応するコントローラは account_controller.rb ではなく、accounts_controller.rb になりました。そのため、ルーティングが混乱してしまったのです。

シングルトン・リソースとは

ある文脈において、Web アプリケーションにひとつしかないリソースのこと。

例えば、「アカウント」というリソースは複数存在しますが、あるユーザーがログインした状態において、「私のアカウント」というリソースはひとつしか存在しません。

Rails では、/accounts という URL パスで「アカウントのリスト」を表し、/accounts/99 で「id が 99 のアカウント」を表し、/account で「私のアカウント」を表します。

Rails 1.2 時代には、普通のリソースとシングルトン・リソースとでコントローラを別々に用意する必要がありましたが、Rails 2.0 以降は同じコントローラで処理できるようになりました。

以下の手順でテストが通ります。

  • /app/controllers/account_controller.rb のファイル名を accounts_controller.rb に変更します。
  • accounts_controller.rb を開いて、クラス名を AccountController から AccountsController に変更します。
  • /app/views/account ディレクトリの名前を accounts に変更します。
  • /test/functional/account_controller_test.rb のファイル名を accounts_controller_test.rb に変更します。
  • accounts_controller_test.rb を開いて、次のように修正します。
    • 2-5行目を削除します。
    • クラス名を AccountControllerTest から AccountsControllerTest に変更します。
    • setup メソッドの中で使われている、AccountControllerAccountsController に変更します。
    • test_routing メソッドを次のように修正します。
  def test_routing
    assert_generates '/account',
      { :controller => 'accounts', :action => 'show' }
    assert_generates '/account/edit',
      { :controller => 'accounts', :action => 'edit' }
    assert_generates '/account',
      { :controller => 'accounts', :action => 'update' }
  end

test:functionals タスクを実行すると…

92 tests, 315 assertions, 0 failures, 4 errors

失敗の数が 2 から 0 に減りました。残りは、エラー 4 個です。本日はここまでとしましょう。