2013年2月19日火曜日

Railsで表形式のデータを複数同時に更新するサンプル(削除対応版)


前回作成したサンプルで、複数件の更新はひとまず対応できた。
今回は、選択した行のデータを削除できる機能を追加してみたい。

まずはscaffold。クラスの名前を変えただけで、フィールドは同じ。(nameとprice)
rails g scaffold imp_ramen name:string price:integer
rake db:migrate
次にroutes.rbの編集。これも前回と同様。画面遷移も同じになる。
  match '/imp_ramen/update_all' => 'imp_ramen#update_all'
  match '/imp_ramen/confirm_all' => 'imp_ramen#confirm_all'
  match '/imp_ramen/edit_all' => 'imp_ramen#edit_all', as: 'edit_all_imp_raman', :via => :get
  resources :imp_ramen
modelに新たにdelete_checkというフィールドを追加する。
class ImpRaman < ActiveRecord::Base
  attr_accessor :delete_check
end
次にcontroller。index、edit_all、confirm_allは前回から変更なし。
update_allを下記のように編集。
  # GET /imp_ramen/update_all
  def update_all
    @imp_ramen = session[:imp_ramen]
    for imp_raman in @imp_ramen
      if imp_raman.delete_check
        to_destory_raman = ImpRaman.find(imp_raman.id)
        to_destory_raman.destroy
      else
        imp_raman.save
      end
    end
    session[:imp_ramen] = nil
    respond_to do |format|
      format.html { redirect_to imp_ramen_url }
      format.json { head :no_content }
    end
  end
delete_checkがtrueの場合に、該当行のデータのdestroyを実行。

to_destory_ramanに代入し直しているのは、imp_ramanはループ中の配列の要素なので、ここでdestoryするとエラーが発生してしまうため。

DBに反映後は、セッションはもう不要なので、nilを代入してクリア。

indexのviewを指定してレンダリングすると変更が反映されない中途半端な状態で表示されてしまうので、indexのURLへリダイレクトしている。

複数同時更新画面(edit_all)のviewは下記の通り。
<h1>Editing all imp_ramen</h1>

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

<table border="1">
  <tr>
    <th>削除</th>
    <th>Name</th>
    <th>Price</th>
  </tr>
  <% for imp_raman in @imp_ramen %>
    <tr>
      <td>
        <%= hidden_field_tag("imp_ramen[][id]", imp_raman.id) %>
        <%= check_box_tag("imp_ramen[][delete_check]", true, imp_raman.delete_check) %>
      </td>
      <td>
        <%= text_field_tag("imp_ramen[][name]", imp_raman.name) %>
      </td>
      <td>
        <%= number_field_tag("imp_ramen[][price]", imp_raman.price) %>
      </td>
    </tr>
  <% end %>
</table>
<%= submit_tag "入力確認" %>
<% end %>

<%= link_to 'Back', imp_ramen_path %>
check_boxはチェックされている場合のみ値が送信されるので、チェックされていない行があると位置がズレてしまう。
hidden_fieldをcheck_boxの前に持ってくると、位置ズレを防ぐことができる。

check_box_tagでは、3番目の引数(チェックされた場合に送信される値)で明示的にtrueをしておかないと、デフォルトでは"on"という妙な値が送信されるので、controller側で編集のために余計なコードが必要になる。

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

<table border="1">
  <tr>
    <th>削除</th>
    <th>Name</th>
    <th>Price</th>
  </tr>
  <% for imp_raman in @imp_ramen %>
    <tr>
      <td>
        <% if imp_raman.delete_check %>
          <%= '削除' %>
        <% end %>
      </td>
      <td>
        <%= imp_raman.name %>
      </td>
      <td>
        <%= imp_raman.price %>
      </td>
    </tr>
  <% end %>
</table>

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

<%= link_to 'Back', edit_all_imp_raman_path %>
delete_checkの値をチェックして、trueであれば「削除」を表示している。

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

一覧画面(index)

更新画面(edit_all)

確認画面(confirm_all)

更新後の一覧画面(index)


今回作成したソースコードの参照はこちらから。

https://github.com/torafugu/mytest/tree/master/app/views/imp_ramen
https://github.com/torafugu/mytest/blob/master/app/models/imp_raman.rb
https://github.com/torafugu/mytest/blob/master/app/controllers/imp_ramen_controller.rb

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


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


0 件のコメント:

コメントを投稿