LoginSignup
0
0

Railsでファイルをアップロードする

Last updated at Posted at 2024-05-21

前提

自分の理解を深めるためのメモです。

やりたいこと

Railsでファイルをアップロードしたい。

実装

コントローラで受け取る

スクリーンショット 2024-05-21 午後0.17.01.png

POSTリクエストで送られるので、subject_dataコントローラのcreateアクションに送られる。
スクリーンショット 2024-05-21 午後0.18.24.png

subject_data_controller.rb
class SubjectDataController < ApplicationController
  def create
    uploaded_file = params[:file]
    binding.pry
  end
end

フォームで<%= file_field_tag :file %>と設定したので、params[:file]で受け取れる。

pry(#<SubjectDataController>)> uploaded_file
=> #<ActionDispatch::Http::UploadedFile:0x0000000122986098
 @content_type="text/rtf",
 @headers="Content-Disposition: form-data; name=\"file\"; filename=\"ファイルアップロードのサンプル.rtf\"\r\nContent-Type: text/rtf\r\n",
 @original_filename="ファイルアップロードのサンプル.rtf",
 @tempfile=#<File:/var/folders/l_/r0xf9zf9603bhy8ym0lqxsdc0000gn/T/RackMultipart20240521-14058-8hvjxb.rtf>>

指定のディレクトリに格納する

uploaded_file = params[:file]
excel_file_path = Rails.root.join("public/uploads/#{uploaded_file.original_filename}")
File.open(excel_file_path, 'w+b') do |file|
  file.write(uploaded_file.read)
end

Rails.rootでアプリのルートディレクトリを取得できる。
スクリーンショット 2024-05-21 午後1.55.56.png

続くjoinはRubyのjoinメソッドではなく、RailsのRails.root.joinでファイルパスを取得できる。

ファイルで送られたファイルデータをparams[:file]で受け取り、それをuploaded_fileに代入した。中身を見てみると、original_filenameプロパティーがある。それを使ってファイル名を取得する。
スクリーンショット 2024-05-21 午後1.57.51.png
そしてファイルパスをexcel_file_pathに代入。(必須ではないがコードが読みやすくなると考えて入れた)

File.open(excel_file_path, 'w+b') do |file|
  file.write(uploaded_file.read)
end

File.openの第1引数はファイルパス、第2引数はモード。
File.openは指定のファイルパスからファイルを取得するイメージだが、ファイルが存在しない場合も使える。
ファイルが存在しない場合は、新しくファイルを作成してオープンする。(今回はこっち)

読み込みモードだとエラーになります。書き込みモードのときだけでした。

ファイルを書き込みモードでオープンします。オープン時にファイルがすでに存在していればその内容を空にします。
https://docs.ruby-lang.org/ja/latest/method/Kernel/m/open.html

開いたファイルを|file|とブロックで受け取って処理を渡す理由は、ブロックだと処理が終わったあと自動でクローズしてくれるかららしい。

新しく作成してオープンしたファイルは中身が空なので、さっきフォームから受け取ったファイルの内容を文字列として読み取って、その内容で上書きする。

ファイルに上書きするところの処理で、文字コードのエラーが出た。
スクリーンショット 2024-05-21 午後1.18.30.png

なぜだろう?と思っていたが、そうか、File.openの第2引数の読み取りモードとか書き取りモードとか設定するところで、バイナリーモードを外していたからだ。さっきはバイナリーモードを設定していたからエラーにならなかったんだ。

これらのいずれに対しても "b" フラグを ("r+b"のように) つけることができます (整数なら File::BINARY )。この場合、バイナリモードでオープンします (ただし、DOS/Windowsのようにシステムがテキスト/バイナリでファイルを区別する場合に限ります)
https://docs.ruby-lang.org/ja/latest/method/Kernel/m/open.html

スクリーンショット 2024-05-21 午後1.36.55.png

完成したコード

subject_data_controller.rb
def create
  uploaded_file = params[:file]
  excel_file_path = Rails.root.join("public/uploads/#{uploaded_file.original_filename}")
  File.open(excel_file_path, 'w+b') do |file|
    file.write(uploaded_file.read)
  end
end
subject_data/index.rb
<%= form_with url: "/subject_data", multipart: true do |form| %>
  <%= file_field_tag :file %>
  <%= form.submit %>
<% end %>

参考

0
0
0

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