Help us understand the problem. What is going on with this article?

【10日間でポートフォリオ作成に挑戦】5日目:CKEditorへ画像アップロード機能を追加

概要

今回は、2019年のGW期間(10日間)を全て費やして取り組むポートフォリオの製作過程を取りまとめた内容を投稿させて頂きます。(投稿は毎日行う予定)

全体通した取り組みの詳細については、前回までの記事をご参照ください。

【10日間でポートフォリオ作成に挑戦】1日目:要件定義〜記事投稿のCRUD
【10日間でポートフォリオ作成に挑戦】2日目:アクセス制限〜コメントのCRUD機能
【10日間でポートフォリオ作成に挑戦】3日目:ページネーション~CKEditorの導入
【10日間でポートフォリオ作成に挑戦】4日目:テーブル分割〜CKEditorのフォームへの反映

今日一日の作業内容

ここからは、今日1日で取り組んだ作業内容をご説明します。

CKEditorへ画像アップロード機能を追加

先日実装したCKEditorで、画像を利用した編集が出来る様に画像アップロード機能を実装しました。

画像アップロードについてはshrineをベースに下記のgemを導入しています。

gem 'shrine'
gem 'image_processing'
gem 'mini_magick'

最終的に出来上がったものが、こちらです。

4ef17f9dada9d93de20e28ccb9084739.gif

'shrine'は初めて利用したという事もあり、かなり苦労しました。
その辺りのエピソードは、「今日の失敗」にてご紹介します。

テストコードの記述

テストについては、単体テスト(モデル・コントローラー)と統合テストの両方を書いて行きます。

テストには、Rspecを利用しています。

$ rails g rspec:install

まだ全てのテストを描ききれていませんが、参考にPostモデルのテストコードを掲載しておきます。

spec/models/post_spec.rb
require 'rails_helper'

RSpec.describe Post, type: :model do
  describe '#create' do
    let!(:user) { create(:user) }
    context 'can save' do
      it 'is valid with title' do
        expect(build(:post, user_id: 1)).to be_valid
      end
    end

    context 'can not save' do
      it 'is invalid without title' do
        messages = build(:post, title: nil, user_id: 1)
        messages.valid?
        expect(messages.errors[:title]).to include('を入力してください')
      end

      it 'is invaid without user_id' do
        messages = build(:post, user_id: nil)
        messages.valid?
        expect(messages.errors[:user]).to include('を入力してください')
      end
    end
  end
end

まだまだ触り程度ですが、やっぱりテストコードはいいですね!!ゲームみたいで書いていて楽しいです!!!!

今日の失敗

ここからは今日の失敗をまとめて行きます。

CKEditorへ画像アップロード機能追加で手間取る

401エラー

一通りコードを書いて、実際にアップロードを試そうとすると、下記の様なエラーが発生しました。

7323822fe54e1dc21fed059205e4c969.gif

ターミナルを見てみると、下記の様な処理結果が出ていました。

Started POST "/images?image_relation=DescriptionImages&csrf_token=" for ::1 at 2019-05-01 13:25:52 +0900
Processing by ImagesController#create as */*
  Parameters: {"upload"=>#<ActionDispatch::Http::UploadedFile:0x00007fbcffb81848 @tempfile=#<Tempfile:/var/folders/m0/h9_nmc1n5lg1ghdq5s4_4jc40000gn/T/RackMultipart20190501-49423-16e02tc.png>, @original_filename="pop_reiwa_hatsu.png", @content_type="image/png", @headers="Content-Disposition: form-data; name=\"upload\"; filename=\"pop_reiwa_hatsu.png\"\r\nContent-Type: image/png\r\n">, "ckCsrfToken"=>"xJ5fKnWr0dw2IepjwvbFBWvHbJ7o3TqH9qpYKyK7", "image_relation"=>"DescriptionImages", "csrf_token"=>""}
Completed 401 Unauthorized in 1ms (ActiveRecord: 0.0ms)

401エラーは認証に失敗している事を表しますが、慌ててページを更新すると、ログイン状態が解除されていました。

そういえば、初期データを投入し直した(bin/setup)ので、その時にログインが解除されていたのですが、ページを更新していなかったので、それに気づかなかったという間抜けなエラーです・・・

image_processingの導入漏れ

次にログインしてアップロードを試しましたが、同じ動きになりました。
再度ターミナルを見ると、下記の様なエラーでした。

Completed 500 Internal Server Error in 16ms (ActiveRecord: 0.4ms)

LoadError (cannot load such file -- image_processing/mini_magick):

app/uploaders/image_uploader.rb:1:in `<top (required)>'
app/models/image.rb:2:in `<class:Image>'
app/models/image.rb:1:in `<top (required)>'
app/controllers/images_controller.rb:6:in `create'

また、gemの導入漏れです・・・何回やったら気が済むのでしょう・・・

imageableの追加漏れ

次に発生したエラーは下記の内容です。

Screen Shot 2019-05-01 at 14.37.05.png

ちなみにエラーが発生した箇所は、下記のコントローラーのimage.saveです。

controllers/images_controller.rb
def create
  image = Image.new(
      image: params[:upload],
      image_relation: params[:image_relation]
  )
  if image.save
    render json: {
        url: image.image[:standard].url,
        uploaded: true
    }
  else
    render json: {
        error: {
            message: image.errors.full_messages
        },
        uploaded: false
    }
  end
end

今回、Imageテーブルは、Postの画像以外にも、Userのアイコンなどでも利用する可能性がある事から、ポリモーフィック関連付けを使用しています。

なので、生成したImageインスタンスには、imageable_typeimageable_idのデータを持たせる必要があるのですが、pryで生成されたインスタンスの中身を確認してみるとnilになっていました。

Screen Shot 2019-05-01 at 15.09.22.png

正直、このポリモーフィック関連付けの仕組みを理解しておらず、

本来はPostDescriptionの情報を持たせるべきなのでしょうが、新しく記事を投稿する際など、idが確定していない状態で、どの様に紐づければ良いのか、判断が付きませんでした・・・

なので、一旦current_userの情報を持たせることにしました。

controllers/images_controller.rb
def create
  image = current_user.images.new(
      image: params[:upload],
      image_relation: params[:image_relation]
  )
  if image.save
(中略)

とりあえずUserのアイコンは、現時点で実装の予定は無いので、一先ずはこれで動作する状態に持って行きたいと考えています。

Turbolinksの干渉

下記の通り、新しく編集ページを開くと、CKEditorが表示されず、再読み込みを行うと表示されるというバグが発生しました。

cdf35c945cbbd1eae22f052a9444db2e.gif

コンソールのエラーを確認すると、どうやらTurbolinksが干渉している様でした。

Screen Shot 2019-05-01 at 17.26.56.png

なので、一旦Turbolinksは外しています。

明日の予定

  • 現時点で実装済みの機能のテストコードを全て記述
  • 検索機能(ransack)の実装
  • いいね機能実装の下準備

ransackは使った事が無いのですが、またそれで予定が狂いそうな予感がしています・・・
見積もりスキルをきちんと伸ばしたいですね。

※追記:六日目を投稿しました
【10日間でポートフォリオ作成に挑戦】6日目:テストコードの実装

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away