やりたいこと
CSVファイルダウンロード機能をPOST送信で実現したい。
CSVファイルはブラウザから取り出すことができるので、ブラウザのHTMLからアクションを起こし、ブラウザにCSVデータを返却する方法が良さそう。また、セキュリティ的な観点で、CSVファイル生成に必要なデータは、サーバー側(controller側)でDBから引くようにします。
方法
①xxx.csvファイル
をgetアクセスで読み込んでダウンロード(CSV形式での返却ファイル指定する必要あり。)
↑はググってよく見る方法
②HTMLのform
からPOST送信のレスポンスをブラウザで受けとって、ダウンロード
既存のコードに追加する際に、最も綺麗に実装できそうな②をチョイスしました。
全体の大まかな流れ
・CSVファイルを生成するための条件をform
で送信
・controller
側で受け取った条件をもとに、必要なデータを用意する
・CSVファイルを用意し、書込みを行う
・書込みが完了したCSVファイルをブラウザ側に返却する
実装内容
view側
formヘルパー
はrails
のものを使うけど、送信方法はjavascript
で実行します。
※ f.submit
ではデータがブラウザに返却されない
form
には、CSVファイルを生成するための条件をセットします。
<%= form_with url: csv_download_path, method: :post, class: 'js-CsvDownload' do |f| %>
<%= f.text_field :evaluation_staff %> # 評価するスタッフ
<%= f.text_field :staff %> # タスクを実行するスタッフ
<%= f.date_select :from_date %> # 着手日
<%= f.date_select :to_date %> # 完了日
<button onclick="submitCsvData()">csvでダウンロード</button>
<% end %>
<script>
// ajaxレスポンスを取得してダウンロードする
function submitCsvData() {
// 送信
$('.js-CsvDownload').submit();
}
</script>
controller 側
send_data
はドキュメントに書かれている通り、view
のerbファイル
を作成せずにブラウザ側にデータを返却することができます。
また、ダウンロードしたファイルはExcelで開く予定だったので、encoding: Encoding::SJIS
によって、Excelでも解釈できるShift-JIS
でエンコードします。
def generate_csv
# csvファイルで使うデータを作成
# 2次元配列を用意 [[1行目], [2行目], ... [n行目]]
table_data = create_csv_data(csv_download_params)
# csvファイルのデータをセット
csv_data = CSV.generate(row_sep: "\n", encoding: Encoding::SJIS) do |csv|
table_data.each { |data| csv.add_row(data) }
end
# ブラウザにデータ送信
send_data(csv_data,
disposition: 'attachment',
filename: 'タスク管理シート.csv',
type: :csv)
end
def create_csv_data(csv_download_params)
# 略
end
CSV.generate
はrails
で標準に搭載されているメソッドで、与えられたデータをCSVオブジェクト
としてブロックに渡します。その後、ブロック内でCSVオブジェクト
に行を追加することができます。
データは、以下のような二次元配列で、CSVデータ
の行ごとに必要なデータを頑張って用意します。
※データ整形については割愛します。
[
['名前', '', '', '', '', ''],
['山田太郎', '', '', '', '', '' ],
['', '', '', '', '', '' ],
['着手日', '完了日', '担当者', '内容', '備考', '確認者' ],
['2022/10/01', '2022/12/01', 'rails太郎', 'railsの勉強をする', '特になし', 'rails鈴木' ],
]
その後、前述したtable_data.each { |data| csv.add_row(data) }
で1行ずつデータを挿入しています。
おまけ
最初は以下のようにjavascript
内でデータを送信する方法を試みました。
しかし、これではcontroller
にデータを送信できても、最終的なデータの返却先がjavascript
なのでダウンロードがうまく働きません。
$(function () {
$(".js-click-csvDownload").on("click", function () {
$.ajax({
url: <%= @csv_generate_url %>,
type: 'POST',
processData: false,
contentType: false,
data: <%= @data.to_json %>,
dataType: 'json'
})
})
});
【Ruby on Rails】【JavaScript】静的ファイルのダウンロードが出来ない。
を参考にしながら今の内容に至りました。
最後に
ここまで見ていただきありがとうございました。
自分の理解が足りていないところが山ほどありますので、
間違っているところがあればご指摘をいただけると嬉しいです m(__)m。