みんなの「作ってみた」

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

2019/05/01

ryoutaku
ryoutaku
2018年12月から3年間「毎日技術ブログ書く」と宣言して現在も継続中。IBMのWatsonきっかけでエンジニアに憧れて、28歳未経験で転職。バックエンドの開発を担当(Ruby,AWS)社会にインパクトを与えるプロダクトの開発に携わりたい一心で、愚直にアウトプットを継続。今の関心事は自然言語処理。

概要

今回は、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'

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

'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エラー

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

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

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の追加漏れ

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

ちなみにエラーが発生した箇所は、下記のコントローラーの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になっていました。

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

本来は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が表示されず、再読み込みを行うと表示されるというバグが発生しました。

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

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

明日の予定

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

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

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