2013年2月18日月曜日

Railsで表形式のデータを複数同時に更新するサンプル


Railsのscaffoldで作成されるedit画面は、1件のデータしか更新できない。
データの数が多い場合は、1件1件edit画面を開いて更新するのは面倒である。
一覧形式で複数件同時に更新できる画面を作成してみる。

まずはscaffold。
rails g scaffold ramen name:string price:integer
rake db:migrate
ラーメンでramenというクラス名にしてみたのだが、menがmanの複数形として判断されるので、クラスの単数形はramanとなってしまった。

まぁこれはこれで識別しやすいのでこのまま利用する。

次にroutes.rbの編集。以下を追加した。
  match '/ramen/update_all' => 'ramen#update_all'
  match '/ramen/confirm_all' => 'ramen#confirm_all'
  match '/ramen/edit_all' => 'ramen#edit_all', as: 'edit_all_raman', :via => :get
  resources :ramen
画面遷移としては、


という流れになる。

次にcontrollerを編集する。
  # GET /ramen
  # GET /ramen.json
  def index
    @ramen = Raman.all
    session[:ramen] = @ramen

    respond_to do |format|
      format.html # index.html.erb
      format.json { render json: @ramen }
    end
  end
まず一覧画面(index)の検索結果をセッション(session[:ramen])に入れておく。
複数同時更新画面(edit_all)では、DBからではなく、セッションから取得する。
  # GET /ramen/edit_all
  def edit_all
    @ramen = session[:ramen]
  end
セッションを使う理由は、確認画面(confirm_all)から更新画面(edit_all)に戻った場合に変更部分を維持するため。
確認画面(confirm_all)では、画面から送られたパラメータの値でRamanクラスを編集して再度セッションに格納している。
  # GET /ramen/confirm_all
  def confirm_all
    @ramen = Array.new
    for raman in params[:ramen]
      updated_raman = Raman.find(raman["id"])
      updated_raman.update_attributes(raman)
      @ramen << updated_raman
    end
    session[:ramen] = @ramen
  end
@ramenはRamanクラスの配列で、モデルで定義している型と同じではないために、パラメータの値をそのままクラスとして利用することができずに、ちょっと面倒なことをしている。

更新処理(update_all)では、セッションから値を取得してDBにsaveするのみ。
  # GET /ramen/update_all
  def update_all
    @ramen = session[:ramen]
    for raman in @ramen
      raman.save
    end
    render action: "index"
  end
複数同時更新画面(edit_all)のviewは下記の通り。
<h1>Editing all ramen</h1>

<%= form_tag :action => 'confirm_all' do %>

<table border="1">
  <tr>
    <th>ID</th>
    <th>Name</th>
    <th>Price</th>
  </tr>
  <% for raman in @ramen %>
    <tr>
      <td>
        <%= raman.id %>
        <%= hidden_field_tag("ramen[][id]", raman.id) %>
      </td>
      <td>
        <%= text_field_tag("ramen[][name]", raman.name) %>
      </td>
      <td>
        <%= number_field_tag("ramen[][price]", raman.price) %>
      </td>
    </tr>
  <% end %>
</table>
<%= submit_tag "入力確認" %>
<% end %>

<%= link_to 'Back', ramen_path %>
@ramenがRamanクラスの配列なので、ループを回して一つづつ取り出して、inputタグを作成している。
"ramen[][XXXX]"と記述すると、ramenという名前のパラメータの配列の項目名として扱ってくれるようだ。

確認画面(confirm_all)のviewは下記の通り。
<h1>Editing all ramen</h1>

<table border="1">
  <tr>
    <th>ID</th>
    <th>Name</th>
    <th>Price</th>
  </tr>
  <% for raman in @ramen %>
    <tr>
      <td>
        <%= raman.id %>
      </td>
      <td>
        <%= raman.name %>
      </td>
      <td>
        <%= raman.price %>
      </td>
    </tr>
  <% end %>
</table>

<%= form_tag :action => 'update_all' do %>
<%= submit_tag "更新" %>
<% end %>

<%= link_to 'Back', edit_all_raman_path %>
controllerが既にセッションに値を確認しているので、ここでは単純に表示するだけ。

実際の画面遷移の例は以下のようになる。

一覧画面(index)

更新画面(edit_all)
確認画面(confirm_all)
更新後の一覧画面(index)
今回作成したソースコードの参照はこちらから。

https://github.com/torafugu/mytest/tree/master/app/views/ramen
https://github.com/torafugu/mytest/blob/master/app/models/raman.rb
https://github.com/torafugu/mytest/blob/master/app/controllers/ramen_controller.rb

実際に動くサンプルはこちらから。(heroku上のサイト)

http://ancient-savannah-6605.herokuapp.com/ramen

今回参考にさせていただいたブログの記事。

Rails のフォームで配列形式のデータを扱う方法
http://webos-goodies.jp/archives/51387214.html

Ruby on Railsあれこれ/複数従業員情報の一括更新
http://winter-tail.sakura.ne.jp/pukiwiki/index.php?Ruby%20on%20Rails%A4%A2%A4%EC%A4%B3%A4%EC%2F%CA%A3%BF%F4%BD%BE%B6%C8%B0%F7%BE%F0%CA%F3%A4%CE%B0%EC%B3%E7%B9%B9%BF%B7

0 件のコメント:

コメントを投稿