[Ruby on Rails 5] Exporting Ransack results to CSV in Rails 5.1

Ransack の導入について、かんたんにまとめておきます。

Rails 5.1.4
ransack 1.8.6

こちらを参考にさせて頂きました。

rails generate

省略。下記の続きです。
正確には、この記事では TSV 出力を実装しています。

Installation

bundle install します。

Gemfile
gem 'ransack'

Search form

インデックスページにサーチフォームを追加します。

Controller

app/controllers/data_controller.rb
class DataController < ApplicationController
  # GET /data
  # GET /data.tsv
  def index
    @q    = Datum.ransack(params[:q])
    @data = @q.result(distinct: true)
    respond_to do |format|
      format.html
      format.tsv { send_data @data.to_csv(col_sep: "\t"), filename: "data-#{Time.zone.now.strftime('%d%m%Y%H%M')}.tsv" }
    end
  end

result

resutはActiveRecord::Relationを返すので、SQLは普通のActiveRecord同様遅延評価されますし、さらにwhereを繋げたり、kaminariでページングしたりすることもできます。また、to_sqlで発行されるSQLを確認することもできます。

Ransackのススメ – Qiita

distinct: true

View

search_form_for ヘルパーを利用します。
Haml と Bootstrap v4 でスタイリングすると、下記のようになります。

app/views/data/index.html.haml
= search_form_for(@q, class: 'form-inline') do |f|
  .form-group
    = f.label :title_or_filename_cont
    = f.search_field :title_or_filename_cont, class: 'form-control mx-sm-3 mb-2'
    = f.submit 'Submit', class: 'btn btn-primary mb-2'

検索条件の指定には、_or__cont のような Search Matchers を利用します。

CSV download

ダウンロードボタンを追加します。

View

Ransack の検索結果には、以下のようなパラメータが渡っていました。

{"utf8"=>"✓", "q"=>{"title_or_filename_cont"=>"tex"}, "commit"=>"Submit", "controller"=>"data", "action"=>"index"}

検索結果をダウンロードさせるには、link_to にパラメータが渡るように修正(q: request.params[:q])します。

app/views/data/index.html.haml
.btn-group
  = link_to 'Download TSV', data_path(q: request.params[:q], format: 'tsv'), class: 'btn btn-primary'

Sort link

テーブルのタイトルクリックで、昇順や降順表示をさせます。

View

sort_link ヘルパーを利用します。
このままで表示順も CSV download に反映されます。

app/views/data/index.html.haml
.table-responsive
  %table.table.table-striped
    %thead
      %tr
        %th= sort_link(@q, :depth)
        %th= sort_link(@q, :title)
        %th= sort_link(@q, :filename, 'Filename', default_order: :desc)
        %th Description
        %th Keywords
        %th Content 1
        %th Content 2
        %th
        %th
        %th
    %tbody
      - @data.each do |datum|