Railsのファイルダウンロード機能の実装で学んだこと

FBCのチーム開発でイベントをical形式で出力するissueに取り組んでいます。

ファイルが出力されてカレンダーと同期できるところまでは一旦実装はできました。 しかし、私の要件確認ミスで考慮漏れがあったため追加対応中なのですが、一旦実装が終わったRailsでのファイルダウンロード機能について簡単にまとめておきたいと思います。

リファクタ前:renderメソッドのオプションで対応していた

実装当初は以下のように render メソッドを使ってファイル出力の処理を書いていました。

※カレンダーのフォーマット処理の詳細は割愛します。

def index
    respond_to do |format|
      format.html
      format.ics do
        cal = IcalFormatExporter.export_calendar(set_export)

       render plain: cal.to_ical
      end
    end
  end

render メソッドはブラウザに表示されるファイルの元となるファイルを指定できるメソッドです。 例えばcontrollerの update メソッドで更新ができなかった場合に、以下のように edit のテンプレートを呼び出すことができたり

def update
  @event = Event.find(params[:id])
  if @event.update(event_params)
    redirect_to(@event)
  else
    render "edit"
  end
end

以下のように書くとjsonレンダリングできます。

render json: @event

カレンダーの出力も render メソッドでレンダリング元のファイルを指定して、それが画面描画ではなく、ファイルで出力できるようにしました。 でもよくよく考えたら、今回やりたいことはファイルダウンロードであってレンダリングのファイルを指定することじゃないよなと考え直し、関連するコードを調べて修正しました。

リファクタ後:send_dataメソッドを使用する形で修正

ファイル出力といえばCSVを出力する実装はたくさんサンプルがあります。 その際によく利用されているのが send_data メソッドでした。

def index
    respond_to do |format|
      format.html
      format.ics do
        cal = IcalFormatExporter.export_calendar(set_export)

        send_data((cal.to_ical), filename: 'カレンダー.ics', type: 'text/calendar; charset=UTF-8')
      end
    end
  end

これでレンダリングではなくファイルの出力として実装が可能です。

まとめ

リファクタ前のコードは実装前にCSV出力のサンプルなどを調べていれば書かなかったかもしれませんが、render メソッドやそのオプションの意味を改めて調べる機会になって結果的には良かったです。

伊藤さんのアウトプットに関する発表で3日前の自分が喜ぶことを書こうという内容があり、初歩的な内容ではあるのですが備忘録的な意味も込めてリファクタ前後のコードを書いてみました(変なところはフィードバックいただけると嬉しいです!)

logmi.jp

これからも書いて動かして調べてを積み重ねます〜!