学習日記

Ruby on Rails勉強してます

今日やったこと16

13.4 マイクロポストの画像投稿

投稿した画像を扱ったり、その画像をMicropostモデルと関連付けするために、CarrierWaveという画像アップローダーを使う。まずはcarrierwave gemをGemfileに追加する。画像をリサイズしたり、本番環境で画像をアップロードするために、mini_magick gemとfog gemsも追加する。

source 'https://rubygems.org'

gem 'rails',                   '5.1.4'
gem 'bcrypt',                  '3.1.11'
gem 'faker',                   '1.7.3'
gem 'carrierwave',             '1.2.2' #追加
gem 'mini_magick',             '4.7.0' #追加
gem 'will_paginate',           '3.1.5'
gem 'bootstrap-will_paginate', '1.0.0'
.
.
.
group :production do
  gem 'pg',  '0.20.0'
  gem 'fog', '1.42' #追加
  end
.
.
.
$ bundle install

CarrierWaveを導入すると、Railsのジェネレーターで画像アップローダーが生成できるようになる。

$ rails generate uploader Picture

関連付けされる属性には画像のファイル名が格納されるため、String型にしてpicture属性をMicropostモデルに追加する。

$ rails generate migration add_picture_to_microposts picture:string
$ rails db:migrate

CarrierWaveに画像と関連付けたモデルを伝えるためには、mount_uploaderというメソッドを使い、引数に属性名のシンボルと生成されたアップローダーのクラス名を取る。これをMicropostモデルに追加する。

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

Homeページにアップローダーを追加するために、マイクロポストのフォームにfile_fieldタグを追加。

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 %>        <!-- file_fieldタグを追加 -->
  </span>
<% end %>

micropost_paramsメソッドにpicture属性を追加する。

app/controllers/microposts_controller.rb

class MicropostsController < ApplicationController
  before_action :logged_in_user, only: [:create, :destroy]
  before_action :correct_user,   only: :destroy
  .
  .
  .
  private

    def micropost_params
      params.require(:micropost).permit(:content, :picture) # picture属性を追加
    end

    def correct_user
      @micropost = current_user.microposts.find_by(id: params[:id])
      redirect_to root_url if @micropost.nil?
    end
end

Micropostパーシャルのimage_tagヘルパーでアップロードされた画像を描画する。

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 %>
    <!-- image_tagヘルパーで画像を描画 -->
    <%= 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>