0
0

Rails で CSV と TSV をダウンロード(失敗談)

Posted at

Rails で,あるモデルのデータ一覧を CSV でも TSV でもダウンロードできるようにするとき,ちょっとハマったのでメモ。

やりたかったこと

ItemsController の index アクションで

def index
  @items = Item.all
  respond_to do |format|
    format.html do
    end

    format.csv do
    end

    format.tsv do
    end
  end
end

みたいなことがしたかった。

要するに,リクエストが

  • /items なら HTML を
  • /items.csv なら CSV を
  • /items.tsv なら TSV を

返す,と。

んで,CSV の場合のテンプレートは Ruby で記述し /app/views/items/index.csv.ruby というファイルで提供する。

ここまではよくある話。

では TSV のテンプレートをどうするか?

最初にやった方法

TSV 用のテンプレートを CSV 用とは別に用意してもいいんだが,ほぼカラム区切りが違うくらい。CSV ライブラリーで使う col_sep オプションね。
だから,テンプレートを共通化したい。

テンプレート側ではインスタンス変数 @col_sep を参照することにしよう。
この変数はアクションメソッド側で与えるので

format.tsv do
  @col_set = "\t"
end

のようにするわけだが,これだけだとテンプレートファイル index.csv.ruby を見つけてくれない。
そこで,

format.tsv do
  @col_set = "\t"
  render "index.csv"
end

のように書いた。
これで,狙い通り CSV 用のテンプレートを使ってレンダリングしてくれる。

警告が出る

ただし,これだと

DEPRECATION WARNING: Rendering actions with '.' in the name is deprecated: items/index.csv 

といった警告が出る。テンプレートを指定するのに . を使っちゃいけないのだ。

ええっと,じゃあ望ましい書き方は?

試行錯誤

ここから迷走しだした。いろいろ試行錯誤してもうまくいかない。format オプションか?とか思って

render "index", format: "tsv"

とかやってもテンプレートを見つけてくれない。
文字列じゃなくてシンボルで与えるのか,とか,オプションは format じゃなくて formats(s がつく)だったか,とかは分かったのだけれど。

解決

しばらく格闘してふと気付いた。
レンダリングしてほしいのは TSV だが,呼び出したいテンプレートは CSV 用(のファイル名)だ。だから formats オプションには :tsv ではなく :csv を与えなければならなかったんである。そりゃそうだ!
これでようやく解決。

なお,いまの場合,アクションが index で,テンプレート名と一致しているから,render"index" を渡す必要はない。

つまり,最もシンプルには

render formats: :csv

と書けばよいのであった。

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