Top > Ruby on Railsあれこれ > 複数従業員情報の一括削除

#freeze
#contents

* 内容 [#abbfab86]
** 概要 [#n5404c7c]
複数従業員情報の一括削除機能を追加します。画面遷移は以下のようなものです。

&ref(db_tuto_bdel_1.jpg);

一覧画面(index.html.erb)&br;
&ref(db_tuto_bdel_2.jpg);&br;
↓&br;
削除対象選択画面(edit.html.erb)&br;
&ref(db_tuto_bdel_3.jpg);&br;
↓&br;
確認画面(confirm.html.erb)&br;
&ref(db_tuto_bdel_4.jpg);&br;
↓(編集内容を確認して、【更新】ボタンクリック)&br;
一覧画面(index.html.erb)&br;
&ref(db_tuto_bdel_5.jpg);&br;

** サンプルのポイント [#uca95f9e]
-フォームの配列化&br;
-トランザクション制御

** サンプルの使い方 [#if26e934]
サンプルはあらかじめ用意していないので、以降の項目を参照にして、自分で作成しなければいけません。作成後に、ブラウザからhttp://127.0.0.1:3000/bulk_deleteにアクセスしましょう(ポート番号"3000"は適宜、環境に応じて読み替えて下さい)。

** ファイル構成 [#i2c513c1]
本項で作成・変更するファイル&br;
|ファイル名|種類||h
|index.html.erb|ビュー|作成|
|choose.html.erb|ビュー|作成|
|confirm.html.erb|ビュー|作成|
|department.rb|モデル|作成|
|employee.rb|モデル|変更|
|application_helper.rb|ヘルパー|変更|
|bulk_delete_controller.rb|コントローラー|作成|

** 一覧画面(ビュー) [#pccec3fd]
"ror-db-tutorial\app\views\bulk_delete\index.html.erb"を以下の内容で作成します。
#code(ruby){{
<html>
<head>
  <title>Tutorial: Employee Bulk Delete</title>
  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
  <%= stylesheet_link_tag 'ror' %>
</head>
<body>
<h2>Tutorial: Employee Bulk Delete</h2>
<table border="1">
  <tr style="background-color:pink">
    <th>Id</th><th>Name</th><th>JobType</th><th>Salary</th><th>Department</th>
  </tr>
  <% for e in @employees %>
  <tr style="background-color:<%= cycle('white', 'yellow') %>">
    <td align="right"><%=h e.id %></td>
    <td><%=h e.name %></td>
    <td><%=h e.job_type %></td>
    <td align="right"><%= number_with_delimiter(e.salary, delimiter=",") %></td>
    <td><%=h e.department.name %></td>
  </tr>
  <% end %>
</table>
  
<% form_tag({:action => 'choose'}) do %>
  <%= submit_tag "一括削除処理へ" %>
<% end %>
  
</body>
</html>
}}

** 削除対象選択画面(ビュー) [#m7d21529]
削除対象選択画面を作成しましょう。おまけ、Javascriptによるチェックボックスの一括チェック、解除の機能を付けています。
"ror-db-tutorial\app\views\bulk_delete\choose.html.erb"ファイルを以下の内容で作成します。
#code(ruby){{
<html>
<head>
  <title>Tutorial: Employee Bulk Delete</title>
  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
  <%= stylesheet_link_tag 'ror' %>
  <% javascript_tag do %>
   function checkAll(form, pattern, checked){
     reg = new RegExp(pattern);
     for(i=0;i<=form.length-1;i++){
       if(form.elements[i].type * "checkbox" && form.elements[i].name.match(reg) ){
         form.elements[i].checked = checked;
       }
     }
   }
  <% end %>
</head>
<body>
   
<h2>一括削除入力</h2>
  
  <% form_tag({:action => "confirm"}, {:name => "ChooseForm"}) do %>
  <%= button_to_function "全選択", "checkAll(this.form, 'delete_check', true)" %>
  <%= button_to_function "全解除", "checkAll(this.form, 'delete_check', false)" %>
    <table border="1">
      <tr>
        <th>&nbsp;</th>
        <th>Name</th>
        <th>JobType</th>
        <th>Salary</th>
        <th>Department</th>
      </tr>
      <% @departments = Department.find(:all) %>
      <% for @employee in @employees %>
      <tr>
        <td>
          <%= hidden_field("employee[]", "id") %>
          <%= check_box("employee[]", "delete_check") %>
        </td>
        <td><%=h @employee.name %></td>
        <td><%=h @employee.job_type %></td>
        <td><%=h @employee.salary %></td>
        <td><%=h r_label(@employee.department_id, @departments, "id", "name") %></td>
      </tr>
      <% end %>
    </table>
    <br />
    <%= submit_tag "削除内容確認" %>
    <%= submit_tag "戻る", {:type => "button", :onClick => "this.form.action='/bulk_delete/index'; this.form.submit();"}%>
  <% end %>
  </body>
</html>
}}

** 確認画面(ビュー) [#qd3247c4]
確認画面を作成しましょう。
"ror-db-tutorial\app\views\bulk_delete\confirm.html.erb"ファイルを以下の内容で作成します。
#code(ruby){{
<html>
<head>
  <title>Tutorial: Employee Bulk Delete</title>
  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
  <%= stylesheet_link_tag 'ror' %>
</head>
<body>
   
<h2>一括削除内容確認</h2>
 
<table border="1">
  <tr style="background-color:pink">
    <th>Id</th><th>Name</th><th>JobType</th><th>Salary</th><th>Department</th>
  </tr>
  <% for e in @employees %>
  <% next if e.delete_check != "1" %>
  <tr style="background-color:<%= cycle('white', 'yellow') %>">
    <td align="right"><%=h e.id %></td>
    <td><%=h e.name %></td>
    <td><%=h e.job_type %></td>
    <td align="right"><%= number_with_delimiter(e.salary, delimiter=",") %></td>
    <td><%=h r_label(e.department_id, @departments, "id", "name") %></td>
  </tr>
  <% end %>
</table>
  
<% form_tag :action => 'delete' do %>
  <%= submit_tag "削除", {:confirm => '後悔しない?'} %>
  <%= submit_tag "戻る", {:type => "button", :onClick => "this.form.action='/bulk_delete/choose'; this.form.submit();"}%>
<% end %>
  
</body>
</html>
}}

** Employeeモデル [#xf05608e]
"ror-db-tutorial\app\models\employee.rb"に以下の属性を追加します。
#code(ruby){{
attr_accessor :delete_check
}}

で、こうなります。
#code(ruby){{
class Employee < ActiveRecord::Base
 
  belongs_to :department, :foreign_key => 'department_id'
  belongs_to :address, :foreign_key => 'address_id'
  
  validates_presence_of :name, :salary, :message => "を入力して下さい"
  
  attr_accessor :update_check, :delete_check
  
  #バリデーションエラーメッセージ内のプロパティ名を日本語にマッピングします。
  class << self
    HUMANIZED_ATTRIBUTE_KEY_NAMES = {
      "name" => "氏名",
      "salary" => "給与額"
    }
  
    def human_attribute_name(attribute_key_name)
      HUMANIZED_ATTRIBUTE_KEY_NAMES[attribute_key_name] || super
    end
  end
  
end
}}

** Departmentモデル [#o61b7e9b]
"ror-db-tutorial\app\models\department.rb"ファイルを以下の内容で作成します。既にあれば何もしなくてOK!
#code(ruby){{
class Department < ActiveRecord::Base
end
}}

** ヘルパーメソッド [#xe992c05]
"ror-db-tutorial\app\helpers\application_helper.rb"ファイルに以下のように"r_label"メソッドを追加します。既にあれば何もしなくてOK!
#code(ruby){{
  #SAStrutsのf:labelと同じ機能のメソッド
  #id→nameの変換を行います。
  #パラメータ説明
  # target_id : nameに変換したいid
  # objs : idとnameを持つモデルのリスト
  # id_method : モデルからidを取得するためのメソッド名(=プロパティ名)
  # name_method : モデルからnameを取得するためのメソッド名(=プロパティ名)
  def r_label(target_id, objs, id_method, name_method)
  
    for obj in objs
      #オブジェクトのメソッドの動的な呼び出しを行っています。
      #id_methodに設定されている名前のメソッドを呼び出します。
      id = obj.__send__(id_method)
      if id * target_id
        return obj.__send__(name_method)
      end
    end
    return ""
  end
}}

** コントローラー [#i6d19e07]
"ror-db-tutorial\app\controllers\bulk_delete_controller.rb"を以下の内容で作成します。
#code(ruby){{
class BulkDeleteController < ApplicationController
  
  #一覧画面表示
  def index
    @employees = Employee.find(:all, :include=>:department)
    session[:employees] = @employees;
    render :action => 'index.html.erb'
  end
  
  #編集画面表示
  def choose
    @employees = session[:employees]
    render :action => 'choose.html.erb'
  end
  
  #確認画面表示
  def confirm
    @employees = convert(sort(params[:employee]))
    if @employees.size * 0
      render :action => 'choose.html.erb'
      return
    end  
    
    session[:employees] = @employees
    @departments = Department.find(:all)
    render :action => 'confirm.html.erb'
  end
  
  #データベース更新
  def delete
    @employees = session[:employees]
    
    begin
      #トランザクション開始
      ActiveRecord::Base.transaction {
        for e in @employees
          next if e.delete_check != "1"
          #削除
          e.destroy
        end
      }
    rescue => ex
      #例外発生時の処理を記述します。
      render :text => ex
      return
    ensure
      session[:employees] = nil
    end
    index
  end
  
  #リクエスト→モデルに変換メソッド(private)
  def convert(objects)
    employees = Array.new
    objects.each { |o|
      e = Employee.find(o[1]["id"])
      e.id = o[1]["id"]
      e.delete_check = o[1]["delete_check"]
      employees.push(e)
    }
    return employees
  end
  private :convert
  
  #Formから送られてくると、順番がおかしくなっているので
  #画面の表示順番通りになるようにソートする(private)
  def sort(objects)
    objects = objects.sort{|a, b|
     a[0].to_i <=> b[0].to_i
    }
    return objects
  end
  private :sort
  
end
}}

    ホーム 一覧 単語検索 最終更新 バックアップ リンク元   ヘルプ   最終更新のRSS