TIS ENGINEER NOTE

ITエンジニアのためのキャリア向上ノウハウブログ

プログラミング

Ruby on RailsでCSV一覧出力する3つの方法

更新日:

ユーザーが画面に表示されている一覧情報をダウンロードしたい、という場合によく使われるのがcsv形式。

Ruby on Railsでcsv出力をしようとして、情報を集めていると色々な実装手順を見かけました。使っているライブラリなどはほとんど変わらないのですが、実装箇所が異なっているので、ちょっと混乱してしまいました。

今回は自分が調べた結果のまとめとしてRuby on Railsでcsv出力を行う際の3つのアプローチをご紹介していきます。

前提

基本的にRubyのライブラリであるCSV.generateを利用します。もっともシンプルにcsvの出力を行えます。

名前(name),説明(description),価格(price)という情報を持った製品(product)モデルのデータを表示させるとしましょう。

csv_data = CSV.generate do |csv|
  csv_column_names = ["製品名","製品説明","価格"]
  csv << csv_column_names
  @products.each do |product|
    csv_column_values = [
      product.name,
      product.description,
      product.price,
    ]
    csv << csv_column_values
  end
end

上記のように配列を渡していく形で、直感的に1行ずつcsv形式でデータを出力することができます。

注意しておいて欲しいのが、CSV.generate自体はcsvファイルを出力するのではなく、csv文字列を作成しているだけであるということです。上の例だとcsv_dataに入るのはStringのデータとなります。

また、これから話す手順のうち1と2はcsv出力用のviewファイルし、3はコントローラー内でcsvの作成と出力を行います。

いずれの方法も実際に動作確認済みです。

ではそれぞれの手順を見ていきましょう。

①csv出力用のアクションを作成する方法

まずは一番わかりやすいcsv出力用のアクションを作成する実装方法です。

この方法のメリット

  • わかりやすい

この方法のデメリット

  • REST設計に背く形となる

REST設計についての詳細はこちらを参考ください。

実装コード

コントローラー

一覧出力したいモデルのコントローラーにcsv出力専用のアクションを新規作成する。

class ProductsController < ApplicationController
  def csv_output
    @products = Product.all
    send_data render_to_string, filename: "products.csv", type: :csv
  end
end

ルーティング

他の基本アクションも実装する前提とすると以下の通り。collectionの中に作成したいアクションを含めます。

Rails.application.routes.draw do
  root 'products#index'
  resources :products do
    collection do
      get 'csv_output'
    end
  end
end

csv出力ファイル(ビュー)

最後に出力処理本体となるrubyファイル。link_toのパスにformat: :csvを設定すると自動で呼び出されます。なぜこの拡張子なのかは不明。

require 'csv'

CSV.generate do |csv|
  csv_column_names = ["製品名","製品説明","価格"]
  csv << csv_column_names
  @products.each do |product|
    csv_column_values = [
      product.name,
      product.description,
      product.price,
    ]
    csv << csv_column_values
  end
end

ダウンロードリンク

最後にファイル出力を行うためのリンク。できればかっこいいボタンに仕上げましょう。今回は無骨にただのリンク。ポイントはformat: :csvです。

# 省略
<%= link_to "csv出力",csv_output_products_path(format: :csv) %>
# 省略

所感

RESTにこだわる方から石を投げられそうな実装です。確かにindexで実装できそうな内容を新しくルーティングして作るというのは微妙。しかし複数のモデルにまたがる出力をしたい時などは使い所がありそうではあります。あとはどうしてもindexアクションに修正を加えたくない時とか。

②indexアクションからcsv出力ビューへ

一覧出力したいモデルのコントローラーのindexアクションから、formatを判定して、処理を分岐し、csv出力ファイルをレンダリングする形になります。csv出力ファイル(csv_output.csv.ruby)の内容は①と同様。

この方法のメリット

  • REST設計に則っている

この方法のデメリット

  • indexアクションに修正が必要

実装コード

コントローラー

respond_toで呼び出し時のformatを判定し、csvの場合、csv出力ファイルを呼び出します。それ以外の場合は通常通り、html.erbファイルが呼び出されます。

class ProductsController < ApplicationController
  def index
    @products = Product.all
    respond_to do |format|
      format.html
      format.csv do
        send_data render_to_string, filename: "products.csv", type: :csv
      end
    end
  end
end

ルーティング

ルーティングに特別な設定は不要です。indexが呼び出されるルートが設定されていればOKです。

Rails.application.routes.draw do
  resources :products
end

csv出力ファイル(ビュー)

①と同様のソースでOKです。

ダウンロードリンク

いつも通りのindex指定にformat: :csvを付け足すだけです。ボタンはかっこよく仕上げましょう。

<%= link_to "csv出力",products_path(format: :csv) %>

所感

一番ベーシックな実装ではないかと思います。特に欠点も見当たりませんし。もしcsv処理をコントローラーに一任したい場合は③の方法をオススメします。

③indexアクションのみで実装

indexアクション内、またはメソッドを作成してその中でcsvの作成と出力を行います。

この方法のメリット

  • 処理がコントローラー内で完結する

この方法のデメリット

  • コントローラーが複雑になる可能性がある

実装コード

コントローラー

respond_toで呼び出し時のformatを判定する部分までは②と同様。ただし、csv出力ファイルをレンダリングするのではなく、別実装したメソッドにてcsv生成と出力を行います。

一旦CSV.generateを変数に格納し、send_dataでファイルを出力しています。

class ProductsController < ApplicationController
  def index
    @products = Product.all
    respond_to do |format|
      format.html
      format.csv do
        products_csv
      end
    end
  end
  private
  def products_csv
    csv_date = CSV.generate do |csv|
      csv_column_names = ["製品名","製品説明","価格"]
      csv << csv_column_names
      @products.each do |product|
        csv_column_values = [
          product.name,
          product.description,
          product.price,
        ]
        csv << csv_column_values
      end
    end
    send_data(csv_date,filename: "product3.csv")
  end
end

ルーティング

②と同様に特別なルーティングは必要ありません。

csv出力ファイル(ビュー)

csv出力ファイルを作成する必要はありません。

ダウンロードリンク

②と同様です。かっこよく仕上げましょう。

所感

csvをビューに実装するということに気持ち悪さを感じる人にはいい実装方法かと思われます。個人的にはスタイリッシュで嫌いではないです。

おまけ

文字コードを指定したい

CSV.generateにオプションを指定するだけでOKです。①の実装例で試すとこんな感じ。

require 'csv'

CSV.generate(encoding: Encoding::SJIS) do |csv|
  csv_column_names = ["製品名","製品説明","価格"]
  csv << csv_column_names
  @products.each do |product|
    csv_column_values = [
      product.name,
      product.description,
      product.price,
    ]
    csv << csv_column_values
  end
end

タイトルや空白行を出力したい

以下の通りの実装で行けます。渡す値が配列であれば問題ありません。こちらも①の実装例で。

require 'csv'

CSV.generate do |csv|
  # タイトル
  csv << ["製品一覧"]
  # 空白行
  csv << []
  csv_column_names = ["製品名","製品説明","価格"]
  csv << csv_column_names
  @products.each do |product|
    csv_column_values = [
      product.name,
      product.description,
      product.price,
    ]
    csv << csv_column_values
  end
end

出力されるファイルは以下のようになります。

製品一覧

製品名,製品説明,価格
product1,this is product1,1000

まとめ

いかがだったでしょうか。あなた自身や開発現場のコーディング方針に適した手法を選択していただければ。

閲覧いただき、ありがとうございました。

オススメ記事
文系出身エンジニアが26才でフリーランスになった感想

こんにちは。フリーランスエンジニアのてぃすです。 フリーランスエンジニアということは、つまりエンジニアとして独立しているということになり、すごい敷居が高い印象を持っている人が多いです。 けど僕は文系大 ...

続きを見る

よく読まれている記事

エンジニア独立

2019/5/29

プログラマーという働き方を見限る前に見ておくべき記事

プログラマーとかSEってちょっと前まで最先端の働き方って感じで世間でもてはやされていましたが、今ではブラック業界の代表格と言われるようになっていますよね。エリート社畜の巣窟とか。 実際SIer系の案件であったり、システム会社を名乗る派遣企業によって希望を持って入ってきた若者が食いつぶされてきたわけですから、当然の帰結ともいえます。 実際僕がこれまで正社員として働いてきた会社も、みなし残業という名の残業未払いであったり、都内にも関わらず勤続2年目で手取り17万円とかいう扱いを平気でやってきました。鬼畜の所業 ...

続きを読む

エンジニア独立

2019/4/15

他のエンジニアと差をつけるための面談前の下準備

こんにちは、フリーエンジニアのてぃすです。 僕は正社員から派遣、フリーランスへと転身する際に、絶対に妥協したくないという意志の元、半年ほどの間に10件近くの面談を体験してきました。 今日はその時の体験を元に、エンジニアが面談を受ける前に下調べしておくべきコンテンツについて紹介していこうと思います。 なぜ下調べが必要か エンジニアって面談を軽視している人が多いんですよね。 ある程度の経歴があるエンジニアは、売り手市場であることも手伝い、まあまあ満足できる就業先を得られるのでそこまで面談対策をじっくりしている ...

続きを読む

エンジニア独立

2019/4/25

【正社員並みの保証】安心フリーランスエージェント・Midworksを徹底分析

こんにちは、フリーエンジニアのてぃすです。 今やフリーランスエンジニアという働き方もだいぶカジュアルになってきています。僕自身 文系大学卒 大したキャリアもコネもない という一般的には心もとない状態から独立しましたが、正社員時代と比べて収入も5倍ほどになり、リモート中心で非常にストレスのない毎日を過ごせています。 先日エンジニアの集まりに参加して、そこにもフリーランスエンジニアが何人かいたのですが、その人たちの多くからMidworksというエージェントを使っているという話を聞きました。 気になって調べてみ ...

続きを読む

エンジニア独立

2019/5/29

エンジニアが会社員のままでいるのはヤバいなと感じた理由

現在会社員エンジニアからフリーランスエンジニアへの転身を目論んで活動中のてぃすです。 今回は僕が感じた会社に雇われた状態でエンジニアを続けることのデメリットについて語っていきます。 エンジニアは多くの現場で幅広い技術を習得するべきである 会社員としてエンジニアを続けることの最大のマイナスポイント。 それはキャリアのコントロールしにくいという点です。 エンジニアが携わるITの世界というのは、技術の流行り廃りが他の業界に比べて断トツで早いんですよね。 そうなるとその技術で生計を立てていくエンジニアという存在は ...

続きを読む

エンジニア独立

2018/8/12

ITエンジニアがスーツ勤務を強要する現場を避けるべき理由

こんにちは、フリーエンジニアのてぃすです。 プラグラマやインフラ担当などと言ったITエンジニアとしての一般的な働き方として、客先に常駐して業務を行うというものがあります。 そんなとき、現場を選ぶ判断基準の一つとして服装が自由か否かというものが上げられます。 僕は決まって私服勤務可能な現場を選ぶようにしています。それはなぜか。エンジニアをスーツ勤務させる客先にロクなところがないから。 これまでスーツ勤務・私服勤務の現場を経験した上で、エンジニアがスーツを勤務を強要する現場を避けるべき理由を書いて行こうと思い ...

続きを読む

-プログラミング
-,

Copyright© TIS ENGINEER NOTE , 2022 All Rights Reserved Powered by AFFINGER5.