Railsで一度に全部処理するときのRoutes問題

2014-06-25
Railsで一度に全部処理するときのRoutes問題

TODO管理をするとして「すべてのタスクを削除したい」とか「すべてのタスクを終了にしたい」っていう要件、普通によくありますね。
これって簡単なくせに「どうあるべきなの?」と迷うことが多くて悩んでいたところ、@tkawaさんがサクッと解決してくれたのでここに残しておきます。

考え方と使われ方

すべてのリソースに対するアクションなのでDELETE /tasksとかPUT /tasksで済ませたいというREST脳が働きますね。
どうやって使いたいか、というと、こんな感じ。

app/views/tasks/index.html.erb

普段はHamlですけど、今回はERBで(手抜き)

<h1>Listing Tasks</h1>

<table>
  <thead>
    <tr>
      <th>Name</th>
      <th>Memo</th>
      <th>Done</th>
      <th colspan="3"></th>
    </tr>
  </thead>

  <tbody>
    <% @tasks.each do |task| %>
      <tr>
        <td><%= task.name %></td>
        <td><%= task.memo %></td>
        <td><%= task.done %></td>
        <td><%= link_to 'Show', task %></td>
        <td><%= link_to 'Edit', edit_task_path(task) %></td>
        <td><%= link_to 'Destroy', task, method: :delete, data: { confirm: 'Are you sure?' } %></td>
      </tr>
    <% end %>
  </tbody>
</table>

<br>

<%= link_to 'New Task', new_task_path %>
<%= link_to 'Destroy All', tasks_path, method: :delete %>
<%= link_to 'Done All', tasks_path(task: {done: true}), method: :put %>

もちろん注目すべきはココですね。

<%= link_to 'New Task', new_task_path %>
<%= link_to 'Destroy All', tasks_path, method: :delete %>
<%= link_to 'Done All', tasks_path(task: {done: true}), method: :put %>

はい、これがシンプルです。
これがやりたいです。
これにしましょう。

Routesの設計

まず「すべて削除」「すべて更新」をconfig/routes.rbで表現します。
これはtasksというリソースに対するDELETEおよびPUT操作ですので、次のように書きました。

config/routes.rb

Rails.application.routes.draw do
  resources :tasks
  delete :tasks, to: 'tasks#destroy_all'
  put :tasks, to: 'tasks#update_all'
  root to: 'tasks#index'
end

これがどのようなURLになるか、見てみましょう。

$ rake routes
   Prefix Verb   URI Pattern               Controller#Action
    tasks GET    /tasks(.:format)          tasks#index
          task   /tasks(.:format)          tasks#create
 new_task GET    /tasks/new(.:format)      tasks#new
edit_task GET    /tasks/:id/edit(.:format) tasks#edit
     task GET    /tasks/:id(.:format)      tasks#show
          PATCH  /tasks/:id(.:format)      tasks#update
          PUT    /tasks/:id(.:format)      tasks#update
          DELETE /tasks/:id(.:format)      tasks#destroy
          DELETE /tasks(.:format)          tasks#destroy_all
          PUT    /tasks(.:format)          tasks#update_all
     root GET    /                         tasks#index

注目はココ。

          DELETE /tasks(.:format)          tasks#destroy_all
          PUT    /tasks(.:format)          tasks#update_all

とってもスッキリですね!
なお、昔は次のように書いていました。

# モヤモヤver
Rails.application.routes.draw do
  resources :tasks do
    collection do
      delete :destroy_all
      put :update_all
    end
  end
  root to: 'tasks#index'
end

これでも同じように使えるとは思いますが、Generateされるhelperにすごいモヤモヤ感がありました。なので、いまでは最初に書いたやり方にしています。

# モヤモヤver
destroy_all_posts DELETE /posts/destroy_all(.:format) posts#destroy_all
 update_all_posts PUT    /posts/update_all(.:format)  posts#update_all

コントローラ側の実装

さて、コントローラを実装します。 ここでは大雑把にやりますが、実際に作りこむ際は次の点を注意するようにしましょう。

app/controllers/tasks_controller.rb

class TasksController < ApplicationController
  # ...

  def destroy_all
    Task.destroy_all
    redirect_to root_path
  end

  def update_all
    Task.update_all(task_params)
    redirect_to root_path
  end

  # ...

  private

  def task_params
    params.require(:task).permit(:name, :memo, :done)
  end
end

なお、検証環境は以下のとおりです。

  • Ruby 2.1.2
  • Rails 4.1

関連記事

  • このエントリーをはてなブックマークに追加
comments powered by Disqus