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 %>";