LoginSignup
1
0

More than 1 year has passed since last update.

複数Modelが絡んだCSV出力

Last updated at Posted at 2021-05-30

はじめに

シンプルな関係のModelで出力はみかけるのですが、少し複雑な関係のModelからCSVを出力しようと思ったときに少しはまってしまいました。

#シンプルな(親子)関係のModel
class Office
  has_many :users

class User
  belongs_to :office

上記のような関係のModelから取り出すときは比較的簡単にかけると思います。
Office(id: 1)に所属しているUserを取得したい場合

users = User.joins(:office).where(offices: { code: 1 })

=> #<ActiveRecord::Relation [#<User id: 1, name: "ほげ", office_id: 1>,
                              #<User id: 2, name: "ふが", office_id: 1>,  ~~ 略 ~~]

usersをeachで回してCSVにすればいっちょ上がりですね。

けど、複雑な関係の場合はそうもいきませんでした。(自分の考え方が甘いだけかもですが)

モデルの関係図

image.png
上記(簡素化してます)で、result_detailsに結合していってデータを引っ張ってくることとします。

どうやったか

結論から言ってしまうと、下記の内容でControlerに直書きしました。
本当はModelに切り分けをした方がいいのですが、早く使いたいということでしたので切り分けはまた後日。

  def data_create_to_csv
    respond_to do |format|
      format.html
      format.csv do |csv|
        started_on = Date.new(params[:started_on]["date(1i)"].to_i, params[:started_on]["date(2i)"].to_i, 1)
        # responceは後から追加したので、左外部結合で入力されていないデータも引っ張る
        details =
          ResultDetail.joins(:reson, result: [diary: { user: { office: :area}}]).
          eager_load(:reson, :responce, result: [diary: { user: { office: :area}}]).
          where(users: { employee_code: User.active.pluck(:employee_code) }).
          where(results: { result_on: started_on..started_on.end_of_month })

        filename = started_on.strftime("%Y年%m月")
        csv_data = CSV.generate do |csv|
          columns_name = %w(##ここにはカラム名を本当は入れます。)
          csv << columns_name
          details.each do |detail|
            values =
              [
                detail.result.result_on,
                detail.result.user_id,
                detail.result.diary.user.name,
                detail.result.diary.user.role,
                detail.result.diary.user.office_id,
                detail.result.diary.user.office.name,
                detail.result.memo,
                detail.visited_time.strftime("%H:%M"),
                detail.stay_time,
                detail.destination_code,
                detail.destination_name,
                detail.destination_address,
                detail.visitor,
                detail.content,
                detail.reson_id,
                detail.reson.name,
                detail.responce_id,
                detail.responce&.name
              ]
            csv << values
          end
        end
        send_data csv_data.encode(Encoding::SJIS, invalid: :replace, undef: :replace), filename: "#{filename}.csv"
      end
    end
  end

会社の固有名称とかあるのでそこは外させてもらいました。

send_dataとsend_fileでちょっとだけはまりました。(send_fileだといったん保存しないとerrorになる)

だいぶ駆け足でしたが、参考になれば幸いです。

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