LoginSignup
2
1

More than 5 years have passed since last update.

汎用的なCSV出力機能を作る#1

Posted at

背景

サービスを運営していく上で、ユーザのリストが欲しい、エクセル形式で欲しいみたいなことが多々ある。
今回はなるべく管理が入らず、後々はUIから項目をカスタマイズできるCSV出力機能の実装を目指します。

いざ、実装してみる

コントローラを生成

自分の場合、管理画面に追加する想定なのでdashboard/となってます。

rails g controller dashboard/csv_export index create

index を作る

class Dashboard::CsvExportController < Dashboard::BaseController
  def index
    @models = all_model_array
  end

  def create
  end

  private

  def all_model_array
    tables = ActiveRecord::Base.connection.tables
    tables -= ["ar_internal_metadata", "schema_migrations"]
    tables.map! {|table| table.classify }
  end
end

モデル一覧を取得してます。

index.html.slim

.page-header
  h1 CSV出力

table.table.table-striped
  tr
    th モデル名
    th 出力

  - @models.each do |model|
    tr
      td = model
      td = link_to 'CSV出力', '/', class: 'btn btn-primary'

bootstrapを使っていれば、こんな感じなるはず

スクリーンショット 2017-11-02 14.40.28.png

createアクションを作る

さて、メインのCSV出力を実装します。

こちらの記事を参考させていただきました。
https://tisnote.com/ruby-on-rails-csv/


require 'csv'

class Dashboard::CsvExportController < Dashboard::BaseController
  def index
    @models = all_model_array
  end

  def create
    model = params[:model]
    csv_data = genarate_csv_for_model(model)
    send_data(csv_data, filename: "#{model}.csv")
  end

  private

  def all_model_array
    tables = ActiveRecord::Base.connection.tables
    tables -= ["ar_internal_metadata", "schema_migrations"]
    tables.map! {|table| table.classify }
  end

  def genarate_csv_for_model(model)
    csv_date = CSV.generate do |csv|
      csv_column_names = eval "#{model}.column_names"
      csv << csv_column_names
      models = eval "#{model}.all"
      models.each do |product|
        csv_column_values = []
        csv_column_names.each do |column|
          csv_column_values << product.send(column)
        end
        csv << csv_column_values
      end
    end
    csv_date
  end
end

index.html.slim

.page-header
  h1 CSV出力

table.table.table-striped
  tr
    th モデル名
    th 出力

  - @models.each do |model|
    tr
      td = model
      td = link_to 'CSV出力', dashboard_csv_export_create_path(format: :csv, model: model), class: 'btn btn-primary'

リンク先を修正すれば、機能自体は実装完了です。

リファクタリング

コントローラにロジックを書くのは、好きくないので今回はサービスクラスに移転してあげました。
しかし、メソッド、変数の命名が下手くそです....

ロジックをサービスクラスに移動

require 'csv'

class CsvService

  def initialize(column_names=[], records=[], file_name="example")
    @column_names = column_names
    @records = records
    @file_name = file_name
  end

  def self.initialize_by_model(model_name)
    column_names = eval "#{model_name}.column_names"
    records = eval "#{model_name}.all"
    CsvService.new(column_names, records, model_name)
  end

  def generate_csv
    CSV.generate do |csv|
      csv << @column_names
      @records.each do |record|
        column_values = []
        @column_names.map { |column| column_values << record.send(column) }
        csv << column_values
      end
    end
  end
end
class Dashboard::CsvExportController < Dashboard::BaseController
  def index
    @models = all_model_array
  end

  def create
    @model_name = params[:model]
    @csv_service = CsvService.initialize_by_model(@model_name)
    @csv_data = @csv_service.generate_csv
    send_data(@csv_data, filename: "#{@model_name}.csv")
  end

  private

  def all_model_array
    tables = ActiveRecord::Base.connection.tables
    tables -= %w(ar_internal_metadata schema_migrations)
    tables.map! { |table| table.classify }
  end
end

一旦こんな感じ

これから、項目の選択とか絞り込みみたいなことに挑戦していこうと思います。

2
1
1

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
2
1