人生のロケハン #経験してきたあれこれ

「これってなに?これってどうやるの?」の参考になるようなブログを目指します

Rails: CSVファイルをダウンロードした後に、ページをリロードする

CSVファイルをダウンロードした後に、リロードしたいんですけど、

ユーザーの情報をCSVファイル形式でダウンロードした後に、画面をリロードしてユーザーのステータスを見た目上変わるようにしてほしいと言われた時の開発メモ

CSVダウンロードした後にリロードしたいなら、アクションの中でredirectすればいいじゃない」と思い、安易にredirectしたが、Double renderと怒られ、うまくいかない

send_data はそれ自体がレンダリングをしているので、send_dataの後にredirectとかするとエラーになるらしいですね

ん〜じゃあどうすれば?ということで、色々調べて実装してみました。

cookieを利用する

前提:jquery.js, jquery.cookie.js を使用している

controller

CSVをダウンロードしてユーザーの更新をするアクションを定義

このアクションの中でcookie を作成

cookies[:exported] = { value: ‘yes’, expires: 1.minutes.from_now }

JSで、このcookieの有無を判定して画面のリロード(ページ遷移)をする

# controller

  def output_users_info
    filename = "適当なファイル名"

    users = 適当なユーザーを取得する ( ex: User.where(created_at: Date.today, admin: nil) )

    send_data(csv_generate(users), filename: filename, type: :csv)

    users.each do |user|
       ユーザーに対しての更新処理 ( ex: user.update!( ) )
    end

    cookies[:exported] = { value: 'yes', expires: 1.minutes.from_now  }
  end

  private
    def csv_generate(users)
      csv_data = CSV.generate(force_quotes: true) do |csv|
        users.each.with_index(1) do |user, index|
          csv << [index] + [適当なデータを入れる]
        end
      end
      csv_data.encode("utf-8")
    end
  end

view

viewにフォームを定義

submit時にJSを発火させたいので、適当にjs-***とクラスをつけておく

# view

= form_tag path(format: 'csv'), method: :get, class: 'js-download-csv' do
  = submit_tag "ユーザー情報をcsvファイル形式でダウンロード"

JS

submit時に発火し、cookieが作成されていれば、ページ遷移をする

# js.coffee

$('.js-download-csv').submit ->
      setInterval((->
        if $.cookie('exported')
          $.removeCookie 'exported', path: '/'
          location.href = path
      ), 1000)

js.erbファイルの中で、htmlを書き換えて見た目上の表示を変える

ユーザーの更新とCSVファイルのダウンロードとでアクションを分ける

まず、ユーザーの更新を行い、テンプレートを呼び出す

controller

# controller
  def request_check
    begin
      users = 適当なユーザーを取得する

      # テンプレートに
      @user_ids = users.pluck("id")

      users.each do |user|
        ユーザーに対しての更新処理
      end
      @url = output_users_info_path(params)
      respond_to :js
    end
  rescue => e
    redirect_to path
  end

  def output_users_info
    filename = "適当なファイル名"

    users = 適当なユーザーを取得する
    send_data(csv_generate(users), filename: filename, type: :csv)
  end

template

htmlを書き換えてから、CSVファイルをダウンロードするアクションを呼び出す

リロードに比べると力技感がいなめないが、とりあえず表示の変更は可能

# js.erb

<% @user_ids.each do |id| %>
$("書き換える対象").text("適当な文字列")
<% end %>

# CSVダウンロードのアクションを呼び出す
window.location.href = "<%= @url %>";