[Ruby on Rails 5] Exporting records to TSV in Rails 5.1
MIME type の追加など、手順を忘れていたので記事に起こしておきます。
% rails --version
Rails 5.1.4
こちらを参考にさせて頂きました。
Contents
rails generate
省略。
rails g
でこのようなプロジェクトを作成してあります。
ActiveRecord::Schema.define(version: 20180118080513) do
create_table "data", force: :cascade, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8" do |t|
t.integer "depth"
t.string "title"
t.string "filename"
t.text "description"
t.string "keywords"
t.text "content_1"
t.text "content_2"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
end
TSV Download
TSV は CSV.generate(col_sep: "\t")
で作成します。
View
ダウンロードボタンをビューの一覧に追加します。
.btn-group
= link_to 'Download TSV', data_path(format: 'tsv'), class: 'btn btn-primary'
Controller
respond_to を利用して、フォーマットに応じた出力をコントローラで指定します。
class DataController < ApplicationController
# GET /data
# GET /data.json
# GET /data.tsv
def index
@data = Datum.all
respond_to do |format|
format.html
format.json { render json: @data }
format.tsv { send_data @data.to_csv(col_sep: "\t") }
end
end
end
Model
モデルに to_csv
メソッドを用意します。
class Datum < ApplicationRecord
def self.to_csv(options = {})
CSV.generate(options) do |csv|
csv << column_names
all.each do |data|
csv << data.attributes.values_at(*column_names)
end
end
end
end
Config
require 'csv'
をします。
require 'csv'
また未設定の場合、下記のようなエラーが表示されて、Rails Guides を見て MIME type を登録してね、と言われます。
To respond to a custom format, register it as a MIME type first: http://guides.rubyonrails.org/action_controller_overview.html#restful-downloads. If you meant to respond to a variant like :tablet or :phone, not a custom format, be sure to nest your variant response within a format response: format.html { |html| html.tablet { ... } }
MIME type も追加しておきます。
Mime::Type.register 'text/tab-separated-values', :tsv
サーバを再起動するとダウンロードが可能になります。
補遺
View を用意するパターン。
- RailsでMVCを意識してシンプルにCSV出力 – Qiita
「Railsプロジェクトの作成」部分のメモ。- RailsでCSV/Excelのダウンロード機能の実装方法 – Rails Webook
# app/models/manufacture.rb
class Manufacture < ActiveRecord::Base
has_many :products
end
# app/contollers/products_contoller.rb
class ProductsController < ApplicationController
def index
# N+1問題のため、allではなくincludes
@products = Product.includes(:manufacture)
end
end
# app/models/product.rb
class Product < ActiveRecord::Base
belongs_to :manufacture
end