Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationEventAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
0
Help us understand the problem. What are the problem?

複数Modelが絡んだCSV出力

はじめに

シンプルな関係の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になる)

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

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
0
Help us understand the problem. What are the problem?