背景
サービスを運営していく上で、ユーザのリストが欲しい、エクセル形式で欲しいみたいなことが多々ある。
今回はなるべく管理が入らず、後々は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を使っていれば、こんな感じなるはず
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
一旦こんな感じ
これから、項目の選択とか絞り込みみたいなことに挑戦していこうと思います。