LoginSignup
0
1

More than 3 years have passed since last update.

Railsチュートリアル 第13章 ユーザーのマイクロポスト - 基本的な画像アップロード

Posted at

作成中のアプリケーションから、画像アップローダー「CarrierWave」を使えるようにする

画像投稿機能を実装するために必要な画像アップローダーとして、今回は、「CarieerWave」という画像アップローダーを用います。CarrierWaveをRailsアプリケーションで用いるためには、Railsアプリケーション側にcarrierwaveというgemが必要となります。

早速Gemfileを更新していきましょう。

Gemfile
  source 'https://rubygems.org'

  gem 'rails',                   '5.1.6'
  gem 'bcrypt',                  '3.1.12'
  gem 'faker',                   '1.7.3'
+ gem 'carrierwave',             '1.2.2'
+ gem 'mini_magick',             '4.7.0'
  gem 'will_paginate',           '3.1.6'
  ...略

  group :production do
    gem 'pg',  '0.20.0'
+   gem 'fog', '1.42'
  end

  ...略

とりあえず現時点で必要になるのはcarrierwaveのみです。mini_magickやfog`というgemは、今後追加していく機能で使用するgemです。

Gemfileを更新したので、当然ながらbundle installを実行する必要があります。

# bundle install
...略
Fetching gem metadata from https://rubygems.org/........
Fetching gem metadata from https://rubygems.org/.
Resolving dependencies....
...略
Fetching mime-types-data 3.2019.1009
Installing mime-types-data 3.2019.1009
Fetching mime-types 3.3.1
Installing mime-types 3.3.1
Fetching carrierwave 1.2.2
Installing carrierwave 1.2.2
...略
Fetching mini_magick 4.7.0
Installing mini_magick 4.7.0
...略
Bundle complete! 29 Gemfile dependencies, 88 gems now installed.
Gems in the group production were not installed.
Bundled gems are installed into `/usr/local/bundle`

bundle installは特に問題なく完了できたようです。

Railsのジェネレーターで画像アップローダーを生成する

# rails generate uploader Picture
Running via Spring preloader in process 15235
      create  app/uploaders/picture_uploader.rb

少なくともcarrierwave(または他の画像アップローダー)gemがインストールされていないと、rails generate uploaderコマンドは正常に完了しません。

アップロードされた画像をMicropostモデルに関連付けるようにする

マイクロポストに画像を関連付けるために必要な属性の追加

マイクロポストの画像投稿機能は「画像はマイクロポストに紐付けされる」という実装内容になるため、アップロードされた画像はMicropostモデルに関連付けられるのが自然な実装モデルです。実際には、「RDB上micropostsテーブルのpictureカラムに、アップロードされた画像のファイル名を格納する」という形の実装をします。pictureカラムにはファイル名が入るので、型はstringとなります。

pictureカラムを追加した新たなマイクロポストのデータモデルは、以下のようになります。

Micropost.png

データモデルに変更を加えたので、対応するマイグレーションファイルの生成、ならびに生成したマイグレーションのRDBへの適用が必要となります。なお今回は、生成したマイグレーションファイルの内容に手を加える部分はありません。

# rails generate migration add_picture_to_microposts picture:string
Running via Spring preloader in process 15244
      invoke  active_record
      create    db/migrate/20200105225338_add_picture_to_microposts.rb

# rails db:migrate
== [timestamp] AddPictureToMicroposts: migrating ===========================
-- add_column(:microposts, :picture, :string)
   -> 0.0183s
== [timestamp] AddPictureToMicroposts: migrated (0.0199s) ==================

Micropostモデル側でCarrierWaveを使うために必要な実装

画像と関連付けたモデルをCarrierWave側に伝えるためには、モデル側でmount_uploaderメソッドを呼び出します。mount_uploaderの第1引数は「属性名を指すシンボル」、第2引数は「アップローダーのクラス名」を取ります。例えば「モデル側の属性名がpicture、アップローダー名がPictureUploader」であれば、mount_uploaderメソッドは以下のように呼び出されます。

mount_uploader :picture, PictureUploader

app/models/micropost.rb全体の変更内容は以下のようになります。

app/models/micropost.rb
  class Micropost < ApplicationRecord
    belongs_to :user
    default_scope -> { order(created_at: :desc) }
+   mount_uploader :picture, PictureUploader
    validates :user_id, presence: true
    validates :content, presence: true, length: { maximum: 140 }
  end

現時点で、テストスイートは全体が成功するはずです。

# rails test
Running via Spring preloader in process 15277
Started with run options --seed 12165

  61/61: [=================================] 100% Time: 00:00:13, Time: 00:00:13

Finished in 13.04142s
61 tests, 329 assertions, 0 failures, 0 errors, 0 skips

マイクロポスト投稿フォームに画像アップローダーを追加する

Homeページに画像アップローダーを表示させるためには、マイクロポスト投稿フォームに画像アップローダーを追加するのが自然です。このような場合に使うのはfile_fieldメソッドとなります。早速app/views/shared/_micropost_form.html.erbに画像アップローダーの実装を追加しましょう。

app/views/shared/_micropost_form.html.erb
  <%= form_for(@micropost) do |f| %>
    <%= render 'shared/error_messages', object: f.object %>
    <div class="field">
      <%= f.text_area :content, placeholder: "Compose new micropost..." %>
    </div>
    <%= f.submit "Post", class: "btn btn-primary" %>
+   <span class="picture">
+     <%= f.file_field :picture %>
+   </span>
  <% end %>

MicropostモデルのWebから更新できる属性に、新たにpictureを追加する

Webから画像をアップロードしてマイクロポストに紐付けられるようにするためには、Micropostコントローラーで用いているStrong Parameters機能で、Webからの更新を許可するパラメーターにpictureを追加する必要があります。変更対象のファイルはapp/controllers/microposts_controller.rbですね。

app/controllers/microposts_controller.rb
  class MicropostsController < ApplicationController
    ...略

    private

      def micropost_params
-       params.require(:micropost).permit(:content)
+       params.require(:micropost).permit(:content, :picture)
      end

      ...略
  end

マイクロポストの画像表示を追加する

マイクロポストに画像を関連付けても、その画像がフィード画面に表示されないのでは意味がありません。というわけで、Micropostパーシャル側にも「マイクロポストの画像表示」のための新たな実装が必要となります。Micropostパーシャルの実体であるapp/views/microposts/_micropost.html.erbは、以下のように変更していきます。

app/views/microposts/_micropost.html.erb
  <li id="micropost-<%= micropost.id %>">
    <%= link_to gravatar_for(micropost.user, size: 50), micropost.user %>
    <span class="user"><%= link_to micropost.user.name, micropost.user %></span>
-   <span class="content"><%= micropost.content %></span>
+   <span class="content">
+     <%= micropost.content %>
+     <%= image_tag micropost.picture.url if micropost.picture? %>
+   </span>
    <span class="timestamp">
      Posted <%= time_ago_in_words(micropost.created_at) %> ago.
      <% if current_user?(micropost.user) %>
        <%= link_to "delete", micropost, method: :delete, data: { confirm: "You sure?" } %>
      <% end %>
    </span>
  </li>

「マイクロポストに画像が関連付けられていなければ、画像を表示する部分の描画そのものを行わない」というのがポイントです。「マイクロポストに画像が関連付けられているか否か」というのは、picture?というメソッドの戻り値によってわかるようになっています。

picture?メソッドは、CarrierWaveによって自動的に生成されるメソッドです。メソッド名は、モデル側で定義した画像の属性名をもとにして、CarrierWaveによって自動的に決定されます。

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