Ruby on Rails 【画像アップロード】PaperClipを利用する


投稿日:2020年08月27日 (木)
Ruby on Railsで画像をアップロードするためには以前からPaperClipが利用されています。
Ruby on Rails5.2以降からActiveStorageが標準となり、PaperClipが非推奨となりました。

当サイトではプロジェクト「民泊サイトを構築する(Rails5.0)」で利用方法を詳しく解説していますが、Ruby on Rails6.0でもまだ使えるということを証明するためRuby on Rails6.0でPaperClipを利用する手順を解説していきます。

MacOSXではHomebrewでImageMagickをインストールすることで比較的簡単に実装できますので、今回はWindowsの環境で説明します。

まずはImageMagickのインストールを行います。
ダウンロードは以下のサイトからできます。
ww.npackd.appspot.com

インストールは以下の手順でお願いします。
途中、「install legacy utilities」と「install development」にチェックを入れて下さい。
mrradiology.hatenablog.jp

WindowsではRailsからImageMagickを動作させるために「GnuWin」を使う必要があります。


「GnuWin」のダウンロードは以下のサイトからできます。


「GnuWin」のインストールは以下の手順でお願いします。

開発の環境が整いましたのでGemfileに記述を追加します。
gem "paperclip", "~> 6.0.0"

bundleでインストールします。
bundle


「config\environments\development.rb」ファイルに以下の記述を追加します。
Paperclip.options[:command_path] = "C:\Program Files\ImageMagick-7.0.10-Q16;C:\Program Files (x86)\GetGnuWin32\bin"


「config\environments\development.rb」ファイルの全文です。
Rails.application.configure do

  Paperclip.options[:command_path] = "C:\Program Files\ImageMagick-7.0.10-Q16;C:\Program Files (x86)\GetGnuWin32\bin"

  # Settings specified here will take precedence over those in config/application.rb.

  # In the development environment your application's code is reloaded on
  # every request. This slows down response time but is perfect for development
  # since you don't have to restart the web server when you make code changes.
  config.cache_classes = false

  # Do not eager load code on boot.
  config.eager_load = false

  # Show full error reports.
  config.consider_all_requests_local = true

  # Enable/disable caching. By default caching is disabled.
  # Run rails dev:cache to toggle caching.
  if Rails.root.join('tmp', 'caching-dev.txt').exist?
    config.action_controller.perform_caching = true
    config.action_controller.enable_fragment_cache_logging = true

    config.cache_store = :memory_store
    config.public_file_server.headers = {
      'Cache-Control' => "public, max-age=#{2.days.to_i}"
    }
  else
    config.action_controller.perform_caching = false

    config.cache_store = :null_store
  end

  # Store uploaded files on the local file system (see config/storage.yml for options).
  config.active_storage.service = :local

  # Don't care if the mailer can't send.
  config.action_mailer.raise_delivery_errors = false

  config.action_mailer.perform_caching = false

  # Print deprecation notices to the Rails logger.
  config.active_support.deprecation = :log

  # Raise an error on page load if there are pending migrations.
  config.active_record.migration_error = :page_load

  # Highlight code that triggered database queries in logs.
  config.active_record.verbose_query_logs = true

  # Debug mode disables concatenation and preprocessing of assets.
  # This option may cause significant delays in view rendering with a large
  # number of complex assets.
  config.assets.debug = true

  # Suppress logger output for asset requests.
  config.assets.quiet = true

  # Raises error for missing translations.
  # config.action_view.raise_on_missing_translations = true

  # Use an evented file watcher to asynchronously detect changes in source code,
  # routes, locales, etc. This feature depends on the listen gem.
  config.file_watcher = ActiveSupport::EventedFileUpdateChecker

  config.action_mailer.default_url_options = { host: 'localhost', port: 3000 }
end



「config\initializers」フォルダに「paperclip_media_type_spoof_detector_override.rb」ファイルを新規作成します。

「config\initializers\paperclip_media_type_spoof_detector_override.rb(新規作成したファイル)」を以下のように編集します。
require 'paperclip/media_type_spoof_detector'

module Paperclip
  class MediaTypeSpoofDetector
    def spoofed?
        false
    end
  end
end


設定はこれで完了です。
実際に写真をアップロードする機能を実装していきます。


写真モデルを作成します。
今回は作成済みのユーザーモデルに関連付けをする流れで解説します。

rails g model Photo user:references

rails g paperclip photo image


作成された「db/migrate/20200827081848_add_attachment_image_to_photos.rb」ファイルを編集します。
1行目に[6.0]の記述を追加して下さい。
class AddAttachmentImageToPhotos < ActiveRecord::Migration[6.0]
  def self.up
    change_table :photos do |t|
      t.attachment :image
    end
  end

  def self.down
    remove_attachment :photos, :image
  end
end



マイグレートします。
rails db:migrate


「app/models/user.rb」ファイルに以下の記述を追加します。
has_many :photos


「app/models/user.rb」ファイルの全文です。
class User < ApplicationRecord

  has_many :photos

  # Include default devise modules. Others available are:
  # :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :validatable
end


「app\models\photo.rb」ファイルを以下のように編集します。
class Photo < ApplicationRecord
  belongs_to :user

  has_attached_file :image, styles: { medium: "300x300>", thumb: "100x100>" }
  validates_attachment_content_type :image, content_type: /\Aimage\/.*\z/  
end



「config\routes.rb」ファイルに以下の記述を追加します。
  resources :users do
    resources :photos, only: [:create, :destroy]
  end


「config\routes.rb」ファイルの全文です。
Rails.application.routes.draw do
  devise_for :users
  root 'pages#home'
  # For details on the DSL available within this file, see https://guides.rubyonrails.org/routing.html

  resources :users do
    resources :photos, only: [:create, :destroy]
  end


end




写真コントローラを作成します。


「app\controllers」フォルダに「photos_controller.rb」ファイルを新規作成します。

「app\controllers\photos_controller.rb(新規作成したファイル)」を以下のように編集します。
class PhotosController < ApplicationController
    def create
      @user = User.find(params[:user_id])
  
      if params[:images]
        params[:images].each do |img|
          @user.photos.create(image: img)
        end
  
        @photos = @user.photos
        redirect_back(fallback_location: request.referer, notice: "保存しました。")
      end
    end

    def destroy
        @photo = Photo.find(params[:id])
        @user = @photo.user
        @photo.destroy
        @photos = Photo.where(user_id: @user.id)
        redirect_to request.referrer
    end    

end


「app\controllers」フォルダに「users_controller.rb」ファイルを新規作成します。

「app/controllers/users_controller.rb(新規作成したファイル)」を以下のように編集します。
class UsersController < ApplicationController
  
    def show
      @user = User.find(params[:id])
      @photos = @user.photos
  
    end
 
end
  


「app\views」フォルダに「users」フォルダを新規作成します。
作成した「users」フォルダに「show.html.erb」ファイルを新規作成してください。


「app/views/users/show.html.erb(新規作成したファイル)」を以下のように編集します。
Bootstrapで記述しているので導入していない方は型が崩れるかもしれません。
<br/>
<div class="container">
    <div class="card" style="width: 60rem;">
        <div class="card-body">
            <h5 class="card-title">お写真</h5>
            <br/>
            <!-- 写真アップロード -->
            <%= form_for @user, url: user_photos_path(@user), method: 'post', html: {multipart: true} do |f| %>
                    <div class="row">
                        <div class="form-group">
                            <span class="btn btn-default btn-file text-babu">
                                <%= file_field_tag "images[]", type: :file, multiple: true %>
                            </span>
                        </div>
                    </div>
                    <br/>
                    <%= f.submit "写真追加", class: "btn btn-danger" %>
            <% end %>
                
            <div id="photos"><%= render 'photos/photos_list' %></div>
        </div>
    </div>
</div>


「app\views」フォルダに「photos」フォルダを新規作成します。
作成した「photos」フォルダに「_photos_list.html.erb」ファイルを新規作成します。


「app/views/photos/_photos_list.html.erb(新規作成したファイル)」を以下のように編集します。
<% if @photos.count > 0 %>
  <br/><br/>
  <div class="row">
    <% @photos.each do |photo| %>
        <%= image_tag photo.image.url(), class: "w-25 p-3" %>

        <%= link_to user_photo_path(photo.user_id, photo), remote: true, method: :delete, data: {confirm: "本当に削除してよろしいですか?"} do %>
            <button type="button" class="btn btn-warning">削除</button>
          <% end %>        

    <% end %>
  </div>
<% end %>


これで写真のアップロードと削除ができるようになっているはずです。

ブラウザで確認してみます。
http://localhost:3000/users/1


写真の追加(複数同時追加もできます)と削除ができるようになりました。









Rails6.0 Windows MacOSX

動画学習サイトの構築 Rails6.0

  0 (0)

タスク   128

2,000円

    サンプルサイトは初期起動に15秒ほどかかります。

 
Rails6.0 Windows MacOSX

民泊サイトの構築 Rails6.0

  0 (0)

タスク   128

3,000円

    サンプルサイトは初期起動に15秒ほどかかります。

 
Rails5.0 Windows MacOSX

動画学習サイトの構築 Rails5.0

  0 (0)

タスク   100

1,000円

    サンプルサイトは初期起動に15秒ほどかかります。

 
Rails6.0 Windows MacOSX

お仕事売買サイトの構築 Rails6.0

  0 (0)

タスク   146

3,000円

    サンプルサイトは初期起動に15秒ほどかかります。

 
Rails5.0 Windows MacOSX

民泊サイトの構築 Rails5.0

  0 (0)

タスク   136

2,000円

    サンプルサイトは初期起動に15秒ほどかかります。