Railsでルーティングがうまくいかないときに疑うべきこと

ちゃんと書いてるはずなのに、なんでこんなところへ飛ぶんだということで10分ほど悩みました。ほんとに10分で気がついてよかったです。

どんなこと?

こう(↓)いうコードを .html.erb に書いていたわけです。

  <script type="text/javascript">
    function show_contents() {
      <%= remote_function(:url => { :action => "update", :controller => 'items' },
                                    :update => "contents") %>
      $("contents").show();
    }
  </script>
      :
      :
      :
  <a href="javascript:show_contents()">内容表示</a>
  <div id="contents" style="display:none"></div>

AJAXを使ったリクエストだからどうだということは今回関係ありません。これでやりたいことはクリックされたら、/items/update に飛んで欲しいこと。ところが実際には、/items/show に飛んできています。

Processing ItemsController#show (for 127.0.0.1 at 2008-06-24 17:17:24) [POST]
  Session ID: BAh...7ac
  Parameters: {"authenticity_token"=>"dd5...922",
 "action"=>"show", "id"=>"update", "controller"=>"items"}

サーバの画面を見ると、こんなふう(↑)に確かに show で処理されています。ご丁寧に id が "update" になってるし。
生成された HTML はこんなふう(↓)になってて間違いないはずなのに。

  <script type="text/javascript">
    function show_contents() {
      new Ajax.Updater('contents_window', '/items/update',
                      {asynchronous:true, evalScripts:true,
                       parameters:'authenticity_token=' + codeURIComponent('dd5...922')})
        $("help_window").show();
    }
  </script>

こういうときは?

ルーティングでおかしいときは config/routes.rb を見るべき。

  map.connect 'items',        {:action => 'index',  :controller => 'items'}
  map.connect '',                                   :controller => 'items'
  map.connect 'items/:id',    {:action => 'show',   :controller => 'items'}
  map.connect 'items/update', {:action => 'update', :controller => 'items'}

今回追加したのは「map.connect 'items/update'」。追加したので一番最後につけたのですが、これが落とし穴。ちゃんとわかっているつもりでも、ついつい無意識にやってしまうのですね。

  map.connect 'items',        {:action => 'index',  :controller => 'items'}
  map.connect '',                                   :controller => 'items'
  map.connect 'items/update', {:action => 'update', :controller => 'items'}
  map.connect 'items/:id',    {:action => 'show',   :controller => 'items'}

正解はこちら(↑)。ルーティングは上から順番に処理されるので、上の方だと、/items/update は「map.connect 'items/:id'」にマッチしてしまうからです。:?? は一番最後におくべき。ちゃんと覚えておくこと。例えば、こんなの「map.connect ':controller/:action/:id.:format'」を先頭においたらみんなこれにマッチしてしまうので。