第9回: タスクの完了

2010/05/15

前回は、タスクを追加するアクションを実装しました。

今回は、タスクを完了させる finish アクションを実装します。

ルーティングの修正

エディタで config/routes.rb を開いて、次のように修正してください。

Nchak::Application.routes.draw do
  resources :tasks, :only => [ :index, :create ] do
    put :finish, :on => :member
  end
end

標準の 7 つのアクション(index, show, new, edit, create, update, destroy)以外のアクションを登録するには、do ... end ブロックの内側で get, post, put, delete メソッドを呼びます。これらのメソッドは HTTP メソッドの名前に対応しています。また、これらのメソッドの :on オプションには、アクションが特定の単一レコードを対象とする場合は :member、アクションがレコードの集合を対象とする場合は :collection を指定します。

この修正の結果、/tasks/123/finish という URL パスに対して PUT メソッドでリクエストすると、tasks コントローラの finish アクションが実行されるようになります。

なお、Rails 2.x では次のように記述していました。

ActionController::Routing::Routes.draw do |map|
  map.resources :tasks, :only => [ :index, :create ], :member => { :finish => :put }
end

あまり変化していないように見えますが、非標準アクションの数が多くなってくると、Rails 3.0 の新しい書き方は大変便利です。

ActionController::Routing::Routes.draw do |map|
  map.resources :tasks, :only => [ :index, :create ],
    :member => { :finish => :put, :unfinish => :put },
    :collection => { :done => :get }
end

と、こんな風に書くより、

Nchak::Application.routes.draw do
  resources :tasks, :only => [ :index, :create ] do
    put :finish, :on => :member
    put :unfinish, :on => :member
    get :done, :on => :collection
  end
end

の方がすっきりしていますよね。

finish アクションの実装

app/controllers/tasks_controller.rb を次のように修正します。

class TasksController < ApplicationController
  (省略)
  
  def finish
    @task = Task.find(params[:id])
    @task.update_attribute(:done, true)
    redirect_to :back
  end
end

まず完了したいタスクを変数 @task に入れ、その done カラムの値を true にセットし、元のページにリダイレクトしています。

HTML テンプレートの修正

app/views/tasks/index.html.erb を次のように修正します。

(省略)

<table class="tasks">
  <col class="name" />
  <col class="due_date" />
  <col class="commands" />
  <%= render @tasks %>
</table>

app/views/tasks/_task.html.erb を次のように修正します。

<tr>
  <td><%= task.name %></td>
  <td><%= task.due_date %></td>
  <td><%= link_to '完了', [ :finish, task ], :method => :put %></td>
</tr>

link_to はハイパーリンク(つまり、a タグ)を生成するメソッドですが、:method オプションを指定すると GET 以外の HTTP メソッドでブラウザにアクセスさせることができます。

この書き方は Rails 2.x から変化していませんが、生成される HTML コードの形は大きく変化しています。Rails 2.x では、やや長い JavaScript コードが HTML コードの中に埋め込まれていました。

しかし、Rails 3.0 では、次のように単なる a タグが生成されます。

<a href="/tasks/1/finish" data-method="put" rel="nofollow">完了</a>

この a タグがちゃんと「動く」のは、Rails 3.0 で導入された /public/javascripts/rails.js が存在するためです。JavaScript に詳しい方は、中身を覗いてみると面白いでしょう。

ブラウザで動作確認

タスク一覧ページを開き直します。

画面キャプチャ1

「Task 1」の「完了」リンクをクリックします。

画面キャプチャ2

done の値が true になったタスクは一覧から消えています。