目的
ユーザーが複数のデータをアプリに投稿したいとき、エクセルファイルを選択するとデータベースに保存できるようにしたい。
実装
アプリ立ち上げ
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のカラムを作成。
ビュー
<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を登録できるようにする。
ルーター
Rails.application.routes.draw do
resources :users do
collection do
post :import
end
end
end
UserにPostメソッドの:importアクション用のルーティングを追加する。
コントローラー
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メソッドの定義を書く。
モデル
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を使う準備
gem "roo" #追記
ターミナルでbundle installする。また、config/application.rbにrequire "roo"を追記
# 省略
require 'rails/all'
require "roo"
# 省略
これで、OK。
確認
サーバーを立ち上げ "http://localhost:3000/users" にアクセスして画面を確認する。
ファイルを選択を押して、次のようなエクセルファイルからデータを登録できる。
登録後、次のように画面が変わっていることを確認する。
参考記事
https://qiita.com/seitarooodayo/items/c9d6955a12ca0b1fd1d4
https://qiita.com/guri3/items/f20487516311b2a3db37
本当に参考になりました!ありがとうございます!
後書き
応用して、社員表を一気に登録する機能をアプリに作ってみようと思います。