↓↓クリックして頂けると励みになります。
【25 | 仕事登録ビュー】 << 【ホーム】 >> 【27 | 仕事公開】
Dropzone.jsをRuby on Railsプロジェクトに統合することは、ファイルアップロードのユーザーエクスペリエンスを向上させ、アプリケーション全体の機能性と使いやすさを向上させるために非常に有益です。
Dropzone.jsは、ユーザーエクスペリエンスを向上させるために、ドラッグアンドドロップを使用してファイルをアップロードする方法を提供します。
ユーザーはファイルを選択するだけでなく、ファイルをブラウザウィンドウにドラッグしてアップロードできます。
これにより、使いやすさが向上し、アップロードプロセスがシームレスになります。
Rails6.0使用時はDropzoneをyarnでインストールしていましたが、「application.scss」ファイルからの読み込みがうまくいかないため、CDN経由でスクリプトとスタイルシートを読み込ませるようにします。
「app/views/layouts/application.html.erb」ファイルのheadタグに以下の記述を追加します。
<!-- Dropzone5.5.1 --> <script src="https://cdnjs.cloudflare.com/ajax/libs/dropzone/5.5.1/min/dropzone.min.js" integrity="sha512-jytq61HY3/eCNwWirBhRofDxujTCMFEiQeTe+kHR4eYLNTXrUq7kY2qQDKOUnsVAKN5XGBJjQ3TvNkIkW/itGw==" crossorigin="anonymous" referrerpolicy="no-referrer"></script> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/dropzone/5.5.1/min/dropzone.min.css" integrity="sha512-zoIoZAaHj0iHEOwZZeQnGqpU8Ph4ki9ptyHZFPe+BmILwqAksvwm27hR9dYH4WXjYY/4/mz8YDBCgVqzc2+BJA==" crossorigin="anonymous" referrerpolicy="no-referrer" />
記述追加 【app/views/layouts/application.html.erb】28行目
<!DOCTYPE html> <html> <head> <title>GigHub</title> <meta name="viewport" content="width=device-width,initial-scale=1"> <%= csrf_meta_tags %> <%= csp_meta_tag %> <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %> <%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %> <!-- bootstrap5.3 --> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-9ndCyUaIbzAi2FUVXJi0CjmCapSmO7SnpJef0486qhLnuZ2cdeRhO02iuK6FUUVM" crossorigin="anonymous"> <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js" integrity="sha384-geWF76RCwLtnZ8qwWowPQNguL3RmwHVBC9FhGdlKrxdiJJigb/j/68SIy3Te4Bkz" crossorigin="anonymous"></script> <!-- noty --> <script src="https://cdnjs.cloudflare.com/ajax/libs/noty/3.1.4/noty.min.js" integrity="sha512-lOrm9FgT1LKOJRUXF3tp6QaMorJftUjowOWiDcG5GFZ/q7ukof19V0HKx/GWzXCdt9zYju3/KhBNdCLzK8b90Q==" crossorigin="anonymous" referrerpolicy="no-referrer"></script> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/noty/3.1.4/noty.min.css" integrity="sha512-0p3K0H3S6Q4bEWZ/WmC94Tgit2ular2/n0ESdfEX8l172YyQj8re1Wu9s/HT9T/T2osUw5Gx/6pAZNk3UKbESw==" crossorigin="anonymous" referrerpolicy="no-referrer" /> <!-- Google Fonts --> <link rel="preconnect" href="https://fonts.googleapis.com"> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> <link href="https://fonts.googleapis.com/css2?family=Kaisei+Opti&family=Kosugi+Maru&family=Rampart+One&display=swap" rel="stylesheet"> <!-- Font Awesome --> <script src="https://kit.fontawesome.com/dd8c589546.js" crossorigin="anonymous"></script> <!-- Dropzone5.5.1 --> <script src="https://cdnjs.cloudflare.com/ajax/libs/dropzone/5.5.1/min/dropzone.min.js" integrity="sha512-jytq61HY3/eCNwWirBhRofDxujTCMFEiQeTe+kHR4eYLNTXrUq7kY2qQDKOUnsVAKN5XGBJjQ3TvNkIkW/itGw==" crossorigin="anonymous" referrerpolicy="no-referrer"></script> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/dropzone/5.5.1/min/dropzone.min.css" integrity="sha512-zoIoZAaHj0iHEOwZZeQnGqpU8Ph4ki9ptyHZFPe+BmILwqAksvwm27hR9dYH4WXjYY/4/mz8YDBCgVqzc2+BJA==" crossorigin="anonymous" referrerpolicy="no-referrer" /> </head> <body> <!-- ナビゲーションバー --> <%= render "shared/navbar" %> <!-- noty --> <%= render 'shared/notification' %> <%= yield %> </body> </html>
「app\controllers\gigs_controller.rb」ファイルを以下の手順で編集していきます。
1.85行目からの「upload_photo()」メソッド、「delete_photo()」メソッドの内容を以下の記述に編集します。
def upload_photo @gig.photos.attach(params[:file]) render json: { success: true } end def delete_photo @image = ActiveStorage::Attachment.find(params[:photo_id]) @image.purge redirect_to edit_gig_path(@gig, step: 4) end
2.3行目に「protect_from_forgery except: [:upload_photo]」の記述を追加します。
記述更新 app\controllers\gigs_controller.rb
class GigsController < ApplicationController protect_from_forgery except: [:upload_photo] before_action :authenticate_user!, except: [:show] before_action :set_gig, except: [:new, :create] before_action :is_authorised, only: [:edit, :update, :upload_photo, :delete_photo] before_action :set_step, only: [:update, :edit] def new @gig = current_user.gigs.build @categories = Category.all end def create @gig = current_user.gigs.build(gig_params) if @gig.save @gig.pricings.create(Pricing.pricing_types.values.map{ |x| {pricing_type: x} }) redirect_to edit_gig_path(@gig), notice: "保存しました" else redirect_to request.referrer, flash: { error: @gig.errors.full_messages } end end def edit @categories = Category.all end def update if @step == 2 gig_params[:pricings_attributes].each do |index, pricing| if @gig.has_single_pricing && pricing[:pricing_type] != Pricing.pricing_types.key(0) next; else if pricing[:title].blank? || pricing[:description].blank? || pricing[:delivery_time].blank? || pricing[:price].blank? return redirect_to request.referrer, flash: {error: "価格が無効です"} end end end end if @step == 3 && gig_params[:summary].blank? return redirect_to request.referrer, flash: {error: "詳細を空白にすることはできません"} end if @step == 4 && @gig.photos.blank? return redirect_to request.referrer, flash: {error: "写真がありません"} end if @step == 5 @gig.pricings.each do |pricing| if @gig.has_single_pricing && !pricing.basic? next; else if pricing[:title].blank? || pricing[:description].blank? || pricing[:delivery_time].blank? || pricing[:price].blank? return redirect_to edit_gig_path(@gig, step: 2), flash: {error: "価格が無効です"} end end end if @gig.summary.blank? return redirect_to edit_gig_path(@gig, step: 3), flash: {error: "詳細を空白にすることはできません"} elsif @gig.photos.blank? return redirect_to edit_gig_path(@gig, step: 4), flash: {error: "写真がありません"} end end if @gig.update(gig_params) flash[:notice] = "保存しました" else return redirect_to request.referrer, flash: {error: @gig.errors.full_messages} end if @step < 5 redirect_to edit_gig_path(@gig, step: @step + 1) else redirect_to dashboard_path end end def show end def upload_photo @gig.photos.attach(params[:file]) render json: { success: true } end def delete_photo @image = ActiveStorage::Attachment.find(params[:photo_id]) @image.purge redirect_to edit_gig_path(@gig, step: 4) end private def set_step @step = params[:step].to_i > 0 ? params[:step].to_i : 1 if @step > 5 @step = 5 end end def set_gig @gig = Gig.find(params[:id]) end def is_authorised redirect_to root_path, alert: "あなたには権限がありません。" unless current_user.id == @gig.user_id end def gig_params params.require(:gig).permit(:title, :video, :summary, :active, :category_id, :has_single_pricing, pricings_attributes: [:id, :title, :description, :delivery_time, :price, :pricing_type]) end end
ルートの設定を以下の内容に更新します。
記述更新 config\routes.rb(14行目)
resources :gigs do member do delete :delete_photo post :upload_photo end end
config\routes.rb
Rails.application.routes.draw do # ルートを app\views\pages\home.html.erb に設定 root 'pages#home' # get get 'pages/home' get '/dashboard', to: 'users#dashboard' get '/users/:id', to: 'users#show', as: 'user' # post post '/users/edit', to: 'users#update' resources :gigs do member do delete :delete_photo post :upload_photo end end # device devise_for :users, path: '', path_names: {sign_up: 'register', sign_in: 'login', edit: 'profile', sign_out: 'logout'}, controllers: {omniauth_callbacks: 'omniauth_callbacks', registrations: 'registrations'} # For details on the DSL available within this file, see https://guides.rubyonrails.org/routing.html end
Step4
「app/views/gigs/_step4.html.erb」ファイルに記述を追加します。
app/views/gigs/_step4.html.erb
<% if @step == 4 %> <div class="container mt-4"> <div class="mt-4 mb-4"> <%= link_to '戻る', edit_gig_path(@gig, step: @step - 1), class: "btn btn-secondary" %> <%= link_to '次へ', edit_gig_path(@gig, step: @step + 1), class: "btn btn-danger" %> </div> <div class="card mb-4"> <div class="card-body"> <h4 class="mt-4 mb-4"><b>写真アップロード</b></h4> <!-- 写真アップロード --> <div class="dropzone" id="myDropzone" style="height: 200px; border: dashed 1px #333; border-radius: 10px; text-align: center; padding-top: 1rem;" action="/gigs/<%= @gig.id %>/upload_photo"></div> <div class="container"> <div class="row"> <% @gig.photos.each do |photo| %> <div class="col-4"> <div class="card mt-2"> <%= image_tag url_for(photo), class: "card-img-top" %> <div class="card-body"> <p class="card-text"> <%= link_to '削除', delete_photo_gig_url(photo_id: photo.id, id: @gig.id, step: @step), method: :delete, data: { confirm: "本当に削除してよろしいですか?" }, style: "z-index: 100;", class: "btn btn-outline-danger btn-sm" %> </p> </div> </div> </div> <% end %> </div> </div> </div> </div> <div class="mt-4 mb-4"> <%= link_to '戻る', edit_gig_path(@gig, step: @step - 1), class: "btn btn-secondary" %> <%= link_to '次へ', edit_gig_path(@gig, step: @step + 1), class: "btn btn-danger" %> </div> </div> <% end %> <script> Dropzone.options.myDropzone = { paramName: "file", maxFilesize: 5, acceptedFiles: "image/*", dictDefaultMessage: "ここに写真をドラッグ&ドロップして下さい。<br/>または、クリックすることで写真を選択することもできます。", init: function() { this.on('complete', function (file) { location.reload(); }) } } </script>
これで写真のアップロード、削除ができます。
複数の写真も同時にアップロードできます。
動作を確認して下さい。
ブラウザ確認
http://localhost:3000/gigs/1/edit?step=4
【25 | 仕事登録ビュー】 << 【ホーム】 >> 【27 | 仕事公開】
↓↓クリックして頂けると励みになります。