10
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

【Rails】POST送信でCSVファイルをダウンロード

Last updated at Posted at 2022-10-25

やりたいこと

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ドキュメントに書かれている通り、viewerbファイルを作成せずにブラウザ側にデータを返却することができます。

また、ダウンロードしたファイルは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.generaterailsで標準に搭載されているメソッドで、与えられたデータをCSVオブジェクトとしてブロックに渡します。その後、ブロック内でCSVオブジェクトに行を追加することができます。

データは、以下のような二次元配列で、CSVデータの行ごとに必要なデータを頑張って用意します。
※データ整形については割愛します。

  [
    ['名前', '', '', '', '', ''],
    ['山田太郎', '', '', '', '', '' ],
    ['', '', '', '', '', '' ],
    ['着手日', '完了日', '担当者', '内容', '備考', '確認者' ],
    ['2022/10/01', '2022/12/01', 'rails太郎', 'railsの勉強をする', '特になし', 'rails鈴木' ],
  ]

その後、前述したtable_data.each { |data| csv.add_row(data) }で1行ずつデータを挿入しています。

最終的に以下のようなファイルを生成することができました。
image.png

おまけ

最初は以下のように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。

10
7
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
10
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?