STEP 4: レコードの詳細表示と削除

2010/01/30

タスク管理機能の実装を続けます。

まずは、詳細ページです。


Tasks コントローラに show アクションを追加します。

$ edit app/controllers/tasks_controller.rb
class TasksController < ApplicationController
  def index
    @tasks = Task.all(:order => 'due_date')
  end

  def show
    @task = Task.find(params[:id])
  end
end

show アクション用のテンプレートを作ります。

$ edit app/views/tasks/show.html.erb
<h1>タスク詳細</h1>

<table class="attributes">
  <tr>
    <th>件名</th>
    <td><%= h @task.subject %></td>
  </tr>
  <tr>
    <th>期日</th>
    <td><%= @task.due_date.strftime('%Y/%m/%d') %></td>
  </tr>
  <tr>
    <th>完了</th>
    <td><%= @task.done? ? 'Yes' : '' %></td>
  </tr>
  <tr>
    <th>注記</th>
    <td><%= simple_format @task.note %></td>
  </tr>
</table>

CSS ファイルに詳細ページ用の記述を追加します。

$ edit public/stylesheets/application.css
(省略)

table.attributes {
  border-collapse: collapse;
  margin: 5px auto;
  width: 500px;
}

table.attributes td, table.attributes th {
  border: 1px solid #000;
  padding: 2px;
}

table.attributes th {
  text-align: right;
  background-color: #cc4;
}

タスク一覧ページに詳細ページへのリンクを設定します。

12行目の

      <%= content_tag :td, h(task.subject) %>

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

      <%= content_tag :td, link_to(h(task.subject), task) %>

タスク一覧ページを再読込すると、件名の部分が下線付きで表示されています。

画面キャプチャ1

件名をクリックすると、タスクの詳細が表示されます。

画面キャプチャ2


index.html.erb で修正した部分のソースコードの意味を考えてみましょう。

$ link_to(h(task.subject), task)

これが、次のような HTML コードに変換されます。

<a href="/tasks/917745139">件名01</a>

変数 task は、特定の Ruby オブジェクトを参照しています。このオブジェクトは、レコードオブジェクト と呼ばれ、tasks テーブルの特定のレコードに対応しています。そのレコードの主キー(id)は 917745139 です。

link_to メソッドの第1引数には、リンク文字列(下線付きで表示される文字列)を指定します。

第2引数には、いろんな種類のオブジェクトを指定できるのですが、この例のようにレコードオブジェクトを指定した場合、そのオブジェクトのクラス名("Task")と主キーの値から URL パスを生成してくれます。

Rails アプリケーションがレコードオブジェクトから URL パスを生成する仕組みを理解するには、ルーティングやリソースに関する深い知識が必要になります。まだ、これに触れるにはちょっと早いと思います。雰囲気だけつかんで、次に進みましょう。


タスクの追加と編集は後回しにして、次は削除機能を作りましょう。

今回は、「削除」リンクを先に作ります。

15行目の

      <%= content_tag :td, '' %>

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

      <%= content_tag :td, operations_on_task(task) %>

ヘルパーメソッド operations_on_task を作ります。

$ edit app/helpers/tasks_helper.rb
module TasksHelper
  def operations_on_task(task)
    links = []
    links << link_to('編集', '#')
    links << link_to('完了', '#')
    links << link_to('削除', task, :method => :delete)
    links.join(' | ')
  end
end

link_to メソッドの第3引数に指定された :method => :delete オプションの意味については、もう少し先のステップで説明します。

とりあえず、このオプションによって show アクションではなく destroy アクションにリンク先が切り替わる、とだけ理解してください。

タスク一覧ページを再読込すると、編集、完了、削除のリンクが現れます。

画面キャプチャ3


「削除」リンクをクリックすると、次のようなエラーメッセージが表示されます。

画面キャプチャ4

これはいい反応です。エラーメッセージは「destroy アクションが存在しない」と主張しています。まだ実装していませんので、これは当然の結果です。

destroy アクションを作りましょう。

$ edit app/controllers/tasks_controller.rb
class TasksController < ApplicationController
  (省略)

  def destroy
    @task = Task.find(params[:id])
    @task.destroy
    redirect_to :tasks
  end
end

削除すべきレコードオブジェクトを見つけて、削除して、タスク一覧ページにリダイレクトしています。

では、実際にやってみましょう。

「件名01」の行の「削除」をクリックすると…。確かに、削除されますね。


しかし、「仕様書」(前回の冒頭で説明しました)によれば、削除の前に確認のポップアップウィンドウが表示されることになっていました。

最後にこの仕様を実装して終わりにしましょう。

$ edit app/helpers/tasks_helper.rb
module TasksHelper
  def operations_on_task(task)
    links = []
    links << link_to('編集', '#')
    links << link_to('完了', '#')
    links << link_to('削除', task, :method => :delete,
      :confirm => '本当に削除しますか?')
    links.join(' | ')
  end
end

「削除」リンクをクリックすると、次のようなポップアップウィンドウが表示されます。

画面キャプチャ5

ここで「キャンセル」をクリックすれば何も起こりません。「OK」をクリックするとタスクが削除されます。