#CSVファイルとは
CSVファイルとはモデルのインスタンスの中身を外部へ出力したり、外部から入力するのに必要。具体的にいうと、出力は他のソフトウェアに出力するために使い、入力は他のソフトウェアからの大量データの一括などに使われる。
#####準備
require 'csv'
#アプリ全体でcsvが使えるようにライブラリを取り入れる
#インスタンスの中身をCSV出力する方法
今回の例ではtaskモデルの全インスタンスの中身をCSVファイルで出力する
#この関数ではcsv_attributesという配列変数を定義
def self.csv_attributes
["name", "description", "created_at", "updated_at"]
end
#CSV形式でインスタンスの中身を出力できるようにする
def self.generate_csv
#ここでcsv形式の配列csvを定義する、csv形式の配列に代入していくと列ベクトルができる?
CSV.generate(headers: true) do |csv|
#まずこのcsvに上記で定義したcsv_attributesを1行目として代入
csv << csv_attributes
all.each do |task| #taskを一つ一つ取り出して
#csvの次に行にtaskの値を代入していく
csv << csv_attributes.map{ |attr| task.send(attr) }
end
end
end
↓
定義したgenerate_csvを読み出すためにcontrollerに記述する
def index #名前付きURLは/tasks
.
.
.
respond_to do |format| #この意味はURLのformatによって、新たに変更を加えるよという意味
format.html #format.htmlの場合は、つまりURLが/tasksの時はという意味。format.htmlの後に処理が書かれていないため何もせず画面遷移する
format.csv { send_data @tasks.generate_csv, filename: "tasks-#{Time.zone.now.strftime('%Y%m%d%S')}.csv" }
#format.csvの場合は、つまり/task.csvになっている場合はという意味。その場合は後述の処理をする。ここではsend dataをしているので、データをブラウザからダウンロードされるようにしている
end
end
↓
では/task.csvでアクセスするにはどうしたらいいのか。以下のようなリンクならアクセス可能
= link_to 'エクスポート', tasks_path(format: :csv), class: 'btn btn-primary mb-5'
#CSVデータを入力してデータ保存する方法
モデルファイルの中で受け取った値をデータとして保存する関数を定義する
def self.import(file)
CSV.foreach(file.path, headers: true) do |row| #受け取ったCSVファイルを行ごとに取り出す、その時1行目headerには項目が書いてあるので、1行目は無視する
task = new #Task.newと同価
task.attributes = row.to_hash.slice(*csv_attributes) #taskの属性に順番にデータを格納していく。詳しくは調べてください
task.save!
end
end
↓
controllerの中で入力保存してリダイレクトするためのアクションを作る
def import
current_user.tasks.import(params[:file]) #現在のuserのtaskにimportを発動させる
redirect_to tasks_url, notice: "タスクを追加しました"
end
ちなみにimportの読み出し方がcurrent_user.tasks.importの理解が意外と難しいのでメモ。モデルファイルの中でself.メソッド名で定義したメソッドはクラスメソッドとなるため、インスタンスではなくても使用できる。
↓
現在taskモデルはuserモデルに従属しているのcurrent_user.tasksとすることで、今のユーザーのタスクモデル(クラス)のメソッドとして使用している。参考文献はRailsのmodelクラスのselfが曖昧だったので
↓
ルーティング設定
resources :tasks do
post :import, on: :collection
end
c写真など大きなデータはURLにidとして挟み込めないので、collecionを使用することで、URLの引数として受け取れるようになる
↓
入力画面設定
= form_tag import_tasks_path, multipart: true, class: 'mb-5' do
= file_field_tag :file
= submit_tag "インポート", class: 'btn btn-primary'
この入力でファイルを追加する時は拡張子が.csvになっていることを確認してからやりましょう。