0. はじめに
Railsで基本的なCSVインポートとエクスポートを行う
1. 事前準備
config/application.rb
require "csv"
app/views/users/index.html.erb
<%= form_with url: import_path do |form| %>
<%= form.file_field :file, accept: "text/csv" %>
<%= form.submit "CSVインポート" %>
<% end %>
2. CSVインポート
app/controllers/import_controller.rb
class ImportController < ApplicationController
def create
User.import_csv(file: params[:file]) if params[:file].present?
redirect_to users_path
end
end
app/models/user.rb
class User < ApplicationRecord
CSV_COLUMNS = %w[name age height].freeze
def self.import_csv(file:)
# トランザクション(CSVインポートの途中でエラーが出た場合はロールバック)
User.transaction do
CSV.foreach(file.path, headers: true) do |row|
create!(row.to_h.slice(*CSV_COLUMNS))
end
end
end
end
ここでN+1問題の解決
以下のgemを使う
gem 'activerecord-import'
app/models/user.rb
class User < ApplicationRecord
CSV_COLUMNS = %w[name age height].freeze
def self.import_csv(file:)
list = []
CSV.foreach(file.path, headers: true) do |row|
list << row.to_h.slice(*CSV_COLUMNS)
end
User.import!(list)
end
end
3. CSVエクスポート
app/views/users/index.html.erb
<%= link_to "CSVエクスポート", users_path(format: :csv) %>
app/controllers/users_controller.rb
class UsersController < ApplicationController
def index
@users = User.order(id: :asc)
respond_to do |format|
format.html
format.csv do
send_data(@users.generate_csv, filename: "users.csv")
end
end
end
end
app/models/user.rb
require "csv"
CSV_COLUMNS = %w[name age height]
class User < ApplicationRecord
def self.generate_csv
CSV.generate do |csv|
csv << CSV_COLUMNS
all.each do |user|
csv << CSV_COLUMNS.map { |col| user.send(col) }
end
end
end
end