0
0

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 3 years have passed since last update.

Ruby on Rails と Vue.js で csv 出力したい

Last updated at Posted at 2021-06-02

背景

backend に rails 、 front に vuejs という環境で、vuejs 側に用意してあるボタンを押すと csv ファイルがダウンロードされるという機能を作成したい。

  • csv は excel で扱いたいため utf-8(bom付き) を使用する。
  • csv ファイルの作成は サーバー側で行う。
  • 利用ブラウザは Google Chrome を想定。

処理の流れ

  1. vuejs側でcsvダウンロードボタンを押す
  2. rails側でcsvファイルを作成する
  3. vuejs側にblobでファイルを受け渡しダウンロードする

つまづいたこと

rails側でcsvファイルを作成する際、以下のコードのように rails側で文字コードを utf-8(bom付き)に指定したファイルを作成した。
しかし、blob 経由の vuejs側でダウンロードするとただの utf-8 になっていた。

content.csv.ruby
require 'csv'
bom = "\uFEFF"
CSV.generate(bom) do |csv|
  csv << [
    'id','名前','作成日時'
  ]
  @contents.each do |content|
    csv_column_values = [
      content.id,
      content.name,
      content.created_at
    ]
    csv << csv_column_values
  end
end
sample.vue
<template>
  <div>
    <button @click="downloadContent()"> CSVダウンロード </button>
  <div>
</template>

   省略   

// contentコントローラーのuser_reviewアクションにpostしてcsvをblobでダウンロード
async downloadContent() {
  const response = await axios.post(`/contents/user_review.csv`, {}).catch((error) => {
       中略   
  });
  if(response) {
    const blob = new Blob([response.data], {type: 'text/csv'});
    this.downloadCsvBlob(blob, "Content.csv")
  }
},

// csvをダウンロードする(Chromeを想定)
downloadCsvBlob(blob, fileName) {
  const url = URL.createObjectURL(new Blob([blob], {type: 'text/csv'}));
  const linkEl = document.createElement('a');
  linkEl.href = url;
  linkEl.setAttribute('download', fileName);
  document.body.appendChild(linkEl);
  linkEl.click();
  URL.revokeObjectURL(url);
  linkEl.parentNode.removeChild(linkEl);
},

結論から言うと bom付きかどうかの指定は vuejs側の blob で行わなければいけなかった。

修正内容

rails側でcsvを作成するときはutf-8を指定する。

content.csv.ruby
require 'csv'
# bom = "\uFEFF" を削除
CSV.generate(encoding: Encoding::UTF_8) do |csv| # 変更 UTF-8 とだけ指定する
  csv << [
    'id','名前','作成日時'
  ]
  @contents.each do |content|
    csv_column_values = [
      content.id,
      content.name,
      content.created_at
    ]
    csv << csv_column_values
  end
end

bom付きかどうかは vuejs側の blob で行う。

sample.vue
   変更なしのため省略   

// contentコントローラーのuser_reviewアクションにpostしてcsvをblobでダウンロード
async downloadContent() {
       中略   
},

// csvをutf-8(bom付き)でダウンロードする(Chromeを想定)
downloadCsvBlob(blob, fileName) {
  const bom  = new Uint8Array([0xEF, 0xBB, 0xBF]); // 変更 先頭の3バイト(BOM)を変数 bom へ代入
  const url = URL.createObjectURL(new Blob([bom, blob], {type: 'text/csv'})); // 変更 データの先頭に bom を配置
  const linkEl = document.createElement('a');
     変更なしのため以下省略   

これでcsvファイルをbom付きでダウンロードできた。

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

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?