LoginSignup
5
3

More than 3 years have passed since last update.

Rails gem rooを使って、エクセルファイルからデータ保存

Last updated at Posted at 2020-06-26

目的

ユーザーが複数のデータをアプリに投稿したいとき、エクセルファイルを選択するとデータベースに保存できるようにしたい。

実装

アプリ立ち上げ

rails new sample_app -d postgresql
rails db:create

rails newで新規アプリを作成、データベースも作成する。

コントローラー作成

rails g controller users index

indexアクションを持つUserコントローラーを作成。
ルーターとビューも一緒に作成される。

モデル作成

rails g model user name:string email:string
rails db:migrate

usersテーブルには、string型のnameとemailのカラムを作成。

ビュー

app/views/users/index.html.erb
<h1>ユーザー一覧</h1>

<table>
  <thead>
    <tr>
      <th>ID</th>
      <th>名前</th>
      <th>Eメール</th>
    </tr>
  </thead>
  <tbody>
    <% @users.each do |user| %>
      <tr>
        <td><%= user.id %></td>
        <td><%= user.name %></td>
        <td><%= user.email %></td>
      </tr>
    <% end %>
  </tbody>
</table>

<%= form_with url: import_users_path, local: true do |form| %>
  <%= form.file_field :file %>
  <%= form.submit %>
<% end %>

投稿フォーム生成。ファイル自体を保存するわけではなく、params[:file]を送ったアクション:importにてUserを登録できるようにする。

ルーター

config/routes.rb
Rails.application.routes.draw do
  resources :users do
    collection do
      post :import
    end
  end
end

UserにPostメソッドの:importアクション用のルーティングを追加する。

コントローラー

app/controllers/users_controller.rb
class UsersController < ApplicationController
  def index
    @users = User.all
  end

  def import
    User.import(params[:file])
    redirect_to users_url
  end
end

indexアクションはscaffoldを使ったときと同じで全レコードを取得し、@usersに代入。
importアクションは、params[:file]を受け取って、usersテーブルのレコードを作成するimportメソッドを使う。モデルには、importメソッドの定義を書く。

モデル

app/models/user.rb
class User < ApplicationRecord
  def self.import(file)
    xlsx = Roo::Excelx.new(file.tempfile)
    xlsx.each_row_streaming(offset: 1) do |row|
      user = self.new(id: row[0].value, name: row[1].value, email: row[2].value)
      next if self.pluck(:id).include?(user.id)
      user.save
    end
  end
end

Userモデルのモデルメソッドなので、def self.import の形で定義。params[:file].tempfileに送信したファイルのパスが入る。Roo::Excelx.new(file.tempfile)でファイルを読み取り、変数xlsxに代入。each_row_streamingメソッドで読み込んだファイルの行毎に処理を実行。
offsetオプションによって、処理を飛ばす行数を指定できる(一行目の項目欄を飛ばす)。
next if self.pluck(:id).include?(user.id)で同じidがusersテーブルに存在している場合は処理をスキップしている。

gem rooを使えるように準備をする。

gem rooを使う準備

Gemfile
gem "roo" #追記

ターミナルでbundle installする。また、config/application.rbにrequire "roo"を追記

config/application.rb
# 省略
require 'rails/all'
require "roo"
# 省略

これで、OK。

確認

サーバーを立ち上げ "http://localhost:3000/users" にアクセスして画面を確認する。

test.png
ファイルを選択を押して、次のようなエクセルファイルからデータを登録できる。
エクセル.PNG
登録後、次のように画面が変わっていることを確認する。
test.png

参考記事

https://qiita.com/seitarooodayo/items/c9d6955a12ca0b1fd1d4
https://qiita.com/guri3/items/f20487516311b2a3db37
本当に参考になりました!ありがとうございます!

後書き

応用して、社員表を一気に登録する機能をアプリに作ってみようと思います。

5
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
3