こんばんは、まどぎわですφ(..)
皆さんは画像アップロード処理はどうやって実装していますか?
RailsだとCarrierWaveを使った実装がメジャーだと思いますが、今回はあえてGemを使わずに画像アップロード処理を実装する方法をメモしておきます。
※railsのバージョンは、5.1.2
を使用しています。
画像アップロード
画像をアップロードする方法には、大きく分けて2つの方法があります。
- 任意のディレクトリに配置する
- DBにバイナリとして保存する
それぞれ方法をみていきましょう!
任意のディレクトリに配置する
今回はアップロードのみを行う画面を用意して任意のディレクトリに配置するケースを想定してみました(・∀・)
View側のポイントは、form_tagの引数にmultipart: true
を設定することと、file_field_tag
を使うことです。
view
<%= form_tag(upload_process_path, method: 'post', multipart: true) do %> <label> ファイルを指定: <%= file_field_tag :upfile %> </label> <%= submit_tag 'アップロード' %> <% end %>
controller
def upload_process # パラメータからファイルを取得 file = params[:upfile] # ファイル名を取得 name = file.original_filename # 出力先のパスを設定※今回は、public/docs配下に配置 output_path = Rails.root.join('public/docs', name) # ファイルを出力 File.open(output_path, 'wb'){ |f| f.write(file.read) } end
DBにバイナリとして保存する
今回はUserの編集画面でプロフィール画像を設定し、それをDBに保存するようなケースを想定してみました(・∀・)
ポイントは、string型のctype
とbinary型のphoto
プロパティを持たせることと、それぞれに下記値を設定してあげることです。
- ctype = アップロードファイルのcontent_type
- photo = アップロードファイルの中身
view(抜粋)
<%= form_with(model: user, local: true, multipart: true) do |form| %> <div class="field"> <%= form.label :photo %> <%= form.file_field :photo, id: :author_photo %> </div> <div class="actions"> <%= form.submit %> </div> <% end %>
controller(抜粋)
def create @user = Author.new(author_params) if @user.save redirect_to @user, notice: 'User was successfully created.' else format.html { render :new } end end def user_params if params[:user][:photo] # ctypeをパラメータに設定されたアップロードファイルから設定 params[:user][:ctype] = params[:user][:photo].content_type # photoにアップロードファイルの中身を設定 params[:user][:photo] = params[:user][:photo].read end params.require(:user).permit(:name, :birth, :address, :ctype, :photo) end
おまけ:DBに保存した画像を表示する方法
まずは画像を表示するアクションを定義します。
send_data
を使うことで、ファイルそのものを返却することが出来ます(・∀・)
controller(抜粋)
def show_image send_data @user.photo, :type => @user.ctype, :disposition => 'inline' end
そしてそのメソッドへのroutingを定義します。
これによりusers/id/show_image
でユーザーのプロフィール画像にアクセス出来るようになりました!
routes
resources :users do member do get 'show_image' end end
$ rake rotes show_image_user GET /users/:id/show_image(.:format) users#show_image
最後にviewのimageのurlに先程作成したroutingを設定すれば、画像を表示することが出来ます(・∀・)
<p> <strong>Photo:</strong> <%= image_tag(show_image_user_path(@user), :width => 300) %> </p>
↓こんな感じ
おわりに
今回は、gemを使わずにファイルアップロード機能を実現する方法を整理してみました。
試してはないですが、herokuにリリースする際に画像アップロードする機能は、careerwaveを使って普通に実装すると24時間で消えてしまいますが、今回のようにDBに保存するようにすれば消えずに残すことが出来る気がしました。φ(..)
簡単なユーザーのアイコン等の容量が小さく、簡単なアップロード処理であればgemを使わずに実装してみても良いかもしれませんね(・∀・)