大阪のホームページ制作会社 i.M.Design INFORMATION MEDIA DESIGN ロゴ

06-6809-5021

Columnコラム

WEBサイト制作

2014.11.28

Rails4で実装するCSVのインポート / エクスポート

Rails4で実装するCSVのインポート / エクスポート

今回は Ruby on Rails 4 を使って、管理画面の機能として要望の多いCSVのインポート / エクスポートの機能を実装してみたいと思います。
RubyとRailsの柔軟な表現方法のおかげで簡単にわかりやすく実装できます。

はじめに

前回の記事で Rails と Bootstrap を利用して管理画面を実装しました。
今回はそちらで作ったアプリケーションをベースにして、ユーザー一覧のCSVインポート / エクスポートの機能を追加していきます。

・CSVファイルの仕様

WindowsのExcelで利用できるCSVにしたいと思います。

  • 文字コード: Shift-JIS
  • 改行コード: CR+LF

CSVエクスポート(出力)

DBに入っているユーザーデータをCSVでダウンロードする処理を実装します。 まずはCSVモジュールとNKFモジュールをrequireします。

・/config/application.rb
require 'csv'
require 'nkf'

次に index.csv.ruby というビューファイルを作成して、CSVの出力処理を実装します。

・/app/views/admin/users/index.csv.ruby(新規)
csv_str = CSV.generate do |csv|
  csv << @admin_users.column_names
    @admin_users.all.each do |user|
    csv << user.attributes.values_at(*@admin_users.column_names)
  end
end

NKF::nkf('--sjis -Lw', csv_str)

CSV#generateメソッドのパラメータで出力エンコードを指定できるらしいのですが、なぜか効かなかったのでNKFで SJIS, CR+LF に変換して出力しています。

これで “/admin/users.csv” にアクセスするとCSVファイルがダウンロードされます。
ちなみにテンプレートファイルに “.ruby” が使えるようになったのはRails4からのようです。
* 参考: Rails4になってcsvが出力しやすくなった

ユーザー一覧にダウンロードボタンをつければ完成です。

・/app/views/admin/users/index.html.erb
<%= link_to 'CSVダウンロード', params.merge({:format => :csv}), class: 'btn btn-success' %>

csv_export_2

CSVインポート(入力)

続いてCSVのインポートです。
まずルート追加。
“/admin/users/import” にPOSTでインポートできるようにします。

・/config/routes.rb
namespace :admin do
  resources :users do
    collection do
      post :import
    end
  end
end

Userのコントローラにimportメソッドを追加します。

・/app/controllers/admin/users_controller.rb
def import
  if params[:csv_file].blank?
    redirect_to(admin_users_url, alert: 'インポートするCSVファイルを選択してください')
  else
    num = Admin::User.import(params[:csv_file])
    redirect_to(admin_users_url, notice: "#{num.to_s}件のユーザー情報を追加 / 更新しました")
  end
end

次にコントローラで呼び出しているUser#importメソッドを追加します。
ここがCSVインポートの実際の処理ですね。

・/app/models/admin/user.rb
    # CSVファイルの内容をDBに登録する
    def self.import(file)

      imported_num = 0

      # 文字コード変換のためにKernel#openとCSV#newを併用。
      # 参考: http://qiita.com/labocho/items/8559576b71642b79df67
      open(file.path, 'r:cp932:utf-8', undef: :replace) do |f|
        csv = CSV.new(f, :headers => :first_row)
        csv.each do |row|
          next if row.header_row?

          # CSVの行情報をHASHに変換
          table = Hash[[row.headers, row.fields].transpose]

          # 登録済みユーザー情報取得。
          # 登録されてなければ作成
          user = find_by(:id => table["id"])
          if user.nil?
            user = new
          end

          # ユーザー情報更新
          user.attributes = table.to_hash.slice(
                              *table.to_hash.except(:id, :created_at, :updated_at).keys)

          # バリデーションOKの場合は保存
          if user.valid?
            user.save!
            imported_num += 1
          end
        end
      end

      # 更新件数を返却
      imported_num

    end

最後にテンプレートにCSVファイル登録用のフォームを追加して完了です。

・/app/views/admin/users/index.html.erb
<div class="panel panel-default">
  <div class="panel-body">
    <%= form_tag(import_admin_users_path, :method => :post, multipart: true) do %>
      <div class="form-group">
        <%= file_field_tag :csv_file %>
      </div>
      <%= submit_tag "CSVインポート", :class => "btn btn-primary" %>
    <% end %>
  </div>
</div>

csv_export_3

「山崎」さんはCP932の拡張文字の確認用に入れてみました。
(Shift-JISで読み込むと「崎」が化ける)

まとめ

RubyとRailsの機能のおかげでコード量も少なく実装できたと思います。
ただ、今回はエラー発生時のユーザーへの通知や、Shift-JIS以外のファイルの対応を行なっていないのでそのあたりの処理は工夫のしどころですね。

参考サイト

Exporting CSV and Excel
Rails4になってcsvが出力しやすくなった
CSV を文字コード変換しつつロード

この記事を共有する