RailsとReactでCSVダウンロード機能を実装する例
はじめに
業務関係でCSVの実装について把握する必要があったためダミーコードでまとめていきたいと思います。
実装したことがなかったので大枠が理解できれば良きです。
CSVファイルサンプル
こちらのCSVサンプルサイトから拝借したデータを型にしてダウンロード機能の実装例をまとめます。
CSVをRubyで出力する
/api/v1/hoge/export.csv.ruby - CSV
CSVデータを生成するためのRubyコードを含むビューファイルです。
Ruby CSV 公式: https://docs.ruby-lang.org/ja/latest/class/CSV.html
require "csv" # CSVヘッダーの設定 def header %w[ 全国地方公共団体コード 郵便番号 都道府県名_カナ 市区町村名_カナ 町域名_カナ 都道府県名 市区町村名 町域名 ] end # CSVの各行に出力する内容を設定 def body(data) [ data.region_code, data.postal_code, data.prefecture_name_kana, data.city_name_kana, data.town_name_kana, data.prefecture_name, data.city_name, data.town_name ] end # BOMの設定(Windowsなどでは、このコードがあることでUTF-8として認識される) bom = "\uFEFF" # CSVデータの生成 output = CSV.generate(bom, force_quotes: true) do |csv| csv << header # ヘッダー行の出力 # データ(一覧)のそれぞれについて、CSVの新しい行を出力 @data.each do |data| csv << body(data) end end # 文字コードをUTF-8に指定し、無効な文字列を置き換える output.encode("utf-8", invalid: :replace, undef: :replace)
このファイルでは、CSVのヘッダとボディが定義され、実際のCSVデータが生成されます。
/api/v1/hoge/addresses_controller.rb - コントローラー
先程記載したビューファイルを使ってCSVデータを生成し、クライアントにレスポンスとして返します。
class Api::V1::AddressesController < ApplicationController def export #... # データを取得したり、ビジネスロジックを実行したりするコード #... # respond_to メソッドを使って、クライアントの要求に応じて異なるフォーマットでレスポンスを返すことが可能です。 respond_to do |format| format.csv { render 'export' } # ここで export.csv.ruby ビューが呼び出されます end end end
Railsはアクション名(例:export
)とフォーマット(例:csv
)に基づいて適切なビューテンプレートを見つけようとします。
そのアクション名と.csv
拡張子を組み合わせたファイル名(例:export.csv.ruby
)をビューディレクトリに配置すれば、Railsはそのビューファイルを自動的に見つけてレンダリングします。
/config/routes.rb - ルーティング
Rails.application.routes.draw do namespace :api do namespace :v1 do resources :addresses do collection do get :export end end end end end
GETリクエストの /api/v1/addresses/export
というURLを AddressesController
の export
アクションにマッピングします。
フロント側 - ダウンロードボタン
フロントの方も用意してみます。
onClickなどでダウンロード実行
「Download CSV」というボタンを作成しており、このボタンがクリックされるとonDownload
という関数が実行されます。
import React from 'react'; interface DownloadButtonProps { onDownload: () => void; } const DownloadButton: React.FC<DownloadButtonProps> = ({ onDownload }) => { return ( <button onClick={onDownload}>Download CSV</button> ); } export default DownloadButton;
ダウンロード実行内容 - onDownload
サーバからCSVデータを取得し、ブラウザ上でダウンロードを実現するコードです。
エラーハンドリングは適当です。
import axios from 'axios'; import { saveAs } from 'file-saver'; const onDownload = async () => { try { const response = await axios.get('/api/v1/addresses/export', { responseType: 'blob' }); const blob = new Blob([response.data], { type: 'text/csv' }); saveAs(blob, 'addresses.csv'); } catch (error) { console.error('ダウンロードに失敗しました。:', error); } };
axios.getを使ってサーバからCSVデータを取得します。
responseTypeオプションをblobに設定することでレスポンスボディがBlobオブジェクトとして返されます。
今回はfile-saver
というライブラリを使用しています。
Blobオブジェクトをfile-saver
のsaveAs
関数に渡すことでファイルをダウンロードすることができます。
Blob
Blobは、JavaScriptでバイナリデータを表現するためのオブジェクトで、ファイルのようなイミュータブル(不変)な生のデータを表現します。
ファイル操作、HTTP操作、画像操作など、多岐にわたる用途に使用されます。
ブラウザ上でダウンロードを実装する場合は、大きく分けると二通りです。
- BlobからオブジェクトURLを生成し、それをa要素のhref属性に設定してダウンロードリンクを作成する
- file-saverのようなライブラリを使って、Blobからダウンロードファイルを直接生成する
どちらの方法も、JavaScriptをサポートするすべてのブラウザで機能します。
おしまい
本記事の内容は以上になります! 実装したことが今までなかったため、イメージが固まってよかったと思います。
プログラミングスクールのご紹介 (卒業生より)
お世話になったプログラミングスクールであるRUNTEQです♪
こちらのリンクを経由すると1万円引きになります。
RUNTEQを通じて開発学習の末、受託開発企業をご紹介いただき、現在も双方とご縁があります。
もし、興味がありましたらお気軽にコメントか、TwitterのDMでお声掛けください。