Railsで明細行の一括登録・更新
参考ページ:leave a note [message] behind on Rails: 明細行のtext_fieldなどをフォームで配列化する on Rails
目的:部署別の売上を一括登録する
Railのバージョン:2.0.2
Scaffoldで生成されるメンテナンス画面でもいいけど、一つずつ選択して登録・更新するのは面倒なので、一括して入力できる画面を作る。こんな感じの画面。
上の図は次のテーブルの内容を一括して登録・更新する感じ。(codeはユニークとしておく)
CREATE TABLE UNIT_SALES ( id serial NOT NULL, code haracter varying(4) NOT NULL, name haracter varying(4) NOT NULL, amount integer, )
初期表示のためにunit_salesテーブルからデータを取得し@units変数へ入れておく処理をコントローラに追加。
def index @units = UnitSale.find(:all) end
次に、index.rhtmlで参考ページにあるようなやり方でデータを表示させる。
<% form_for :sample, :url => {:action => :update } do |f| %> <table border="1" cellspacing="0"> <tr> <td colspan="3"><%= f.submit "更新" %> </tr> <tr bgcolor="#fecde5"> <th>部署コード</th> <th>部署名</th> <th>売上</th> </tr> <% @units.each_with_index{|@r, idx| %> <tr> <td><%=h @r.code %></td> <td><%=h @r.name %></td> <td> <%= hidden_field 'r', :code, :index => idx %> <%= text_field 'r', :amount, :size => 13, :maxlength => 11, :index => idx, :style=>"text-align:right" %></td> </tr> <%}%> </table> <% end %>
以下の部分は、コントローラで取得した@unitsの中身を連番(idx)と一緒に取り出して(@r)いる。@unitsの一レコードのデータはインスタンス変数@rとしないといけないらしい(rの部分はどんな名前でもよい)。
<% @units.each_with_index{|@r, idx| %>
テキストボックス、HIDDENフィールドの部分は次のようにしておく。hidden_field,text_fieldの第1引数に上記の変数@rを指定(@は書かない)。:indexには上記idxを指定する。(参考にしたページには text_field 'r'・・というようにを指定していたけど、なくてもできた)
<%= hidden_field 'r', :code, :index => idx %> <%= text_field 'r', :amount, :size => 13, :maxlength => 11, :index => idx, :style=>"text-align:right" %>
こうすることで生成されるHTMLは以下のようになる。
<input id="r_0_code" name="r[0][code]" type="hidden" value="0001" /> <input id="r_0_amount" maxlength="11" name="r[0][amount]" size="13" style="text-align:right" type="text" value="12354" />
name="r[0][code]"のようにidxの部分がr[]の中に設定される。
この値をコントローラで受け取って、登録・更新を行う。
def update update_data = params[:r] update_data.each {|key, value| unit = UnitSale.find(:first, :conditions => ['code = ?', value.code]) unless unit # データがなかった場合、新規登録するためオブジェクトを生成する unit = UnitSale.new(value) end unit.amount = value.amount # 売上を設定 unit.save } end
ここで、params[:r]で受け取ったデータは以下のようなHashの配列になっている。
[ {"0" => {"code" => "0001", "amount" => "12345"}}, {"1" => {"code" => "0002", "amount" => "3232"}}, ・・・省略 ]
そこで、これらの配列の中身をひとつずつ処理していくとき、キーの部分と値の部分に分けて処理していく。
update_data.each {|key, value|
ここで、keyには「0,1,2・・」という値が入り、valueには{"code" => "0001", "amount" => "12345"}という値が入ることになる。あとは、取得したデータからレコードを検索し、存在したら更新、存在しなかったら新規登録という処理を追加する。