みんなの「作ってみた」

【10日間でポートフォリオ作成に挑戦】4日目:テーブル分割〜CKEditorのフォームへの反映

2019/04/30

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

概要

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

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

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

今日一日の作業内容

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

工数の見直し

まず、かなり大雑把に見積もった為、現実の進捗との乖離が大きくなってきた工数の見積もりを修正しました。

とりあえず、必須だけは、何とか10日間で終わらせたいと考えています。

テーブルの分割

Postテーブルに寄せていたdescriptionを、当初のER図の通り、別テーブルに分けました。

なお、切り出したPostDescriptionについてはaccepts_nested_attributes_forを利用して、親レコードであるPostが保存された時に、同時に保存される様にしています。

models/post.rb
class Post < ApplicationRecord
  belongs_to :user
  has_many :post_comments, dependent: :destroy
  has_one :post_description, dependent: :destroy
  accepts_nested_attributes_for :post_description, allow_destroy: true
end
models/post_description.rb
class PostDescription < ApplicationRecord
  belongs_to :post
end
controllers/post_controller.rb
(中略)
  def post_params
    params.require(:post).permit(:id, :title, post_description_attributes: [:description])
  end

こうする事で、下記の様に親モデルのインスタンスを保存する処理の記述だけで済みます。

posts_controllers.rb
〜(前略)〜

  def create
    @post = current_user.posts.build(post_params)
    if @post.save
      redirect_to posts_path, notice: t('common.message.post_create')
    else
      render :new
    end
  end

〜(中略)〜

  def update
    if @post.update(post_params)
      redirect_to edit_post_path, notice: t('common.message.post_update')
    else
      render :new
    end
  end

〜(後略)〜

分割するにあたって、色々と問題が発生したのですが、それは「今日の失敗」で紹介します。

CKEditorの実装

昨日導入したCKEditorを使える状態にしました。

views/post/_form.html.haml
= javascript_include_tag 'https://cdn.ckeditor.com/ckeditor5/11.2.0/classic/ckeditor.js'

:javascript
  const image_relation = document.querySelector( '#image_relation' ).value;
  const csrf_token = document.querySelector( '#csrf_token' ).value;

  window.ClassicEditor
    .create( document.querySelector( '#editor' ), {
      ckfinder: {
        uploadUrl: '/images?image_relation=' + image_relation + '&csrf_token=' + csrf_token
      },
      toolbar: [ 'heading', '|', 'bold', 'italic', 'link', 'Blockquote', 'bulletedList', 'numberedList', 'ImageUpload', 'undo', 'redo'],
      heading: {
        options: [
          { model: 'paragraph', title: 'paragraph', class: 'ck-heading_paragraph' },
          { model: 'heading1', view: 'h1', title: 'heading1', class: 'ck-heading_heading1' },
          { model: 'heading2', view: 'h2', title: 'heading2', class: 'ck-heading_heading2' }
        ]
      },
      image: {
        toolbar: [ 'imageStyle:full' ],
        styles: [ 'full' ]
      }
    })
    .then( editor => {
      editor.ui.view.editable.editableElement.style.height = '800px';
    } );

(中略)

    = f.fields_for :post_description do |ff|
      = ff.label :description
      = ff.text_field :description, id: 'editor'
      = f.hidden_field :image_relation, value: 'DescriptionImages', id: 'image_relation'
      = f.hidden_field :csrf_token, value: @csrf_token, id: 'csrf_token'
      = ff.object.errors.full_messages_for(:description).join(',')

とは言え、viewに直接スクリプトを埋め込んでいるのと画像アップロード機能との紐付けなどはまだなので、その辺りは明日のタスクとしています。

今日の失敗

ここからは、本日の失敗談を紹介します。

テーブル分割で色々と手こずる

Postテーブルから、descriptionを切り出したのですが、アソシエーションで凡ミスを繰り返してしまい、かなり時間をロスしてしまいました。

まず、エラーの現象としては、保存をしても、変更内容が反映されないという状況になりました。

ターミナルの処理結果を見ると、パラメーターが許可されていないというエラーが出ていました。

Unpermitted parameter: :post_description

しかし、ストロングパラメーターはきちんと設定してありました。

なんだかんだ調べて見ると、一対一のアソシエーションなのに、一対多で組んでいました・・・

models/posts.rb
  has_many :post_descriptions, dependent: :destroy

それを修正したのですが、直りません。
もう一度確認すると、なぜか親モデルもbelongs_toで組んでました・・・もうめちゃくちゃです・・・

models/posts.rb
  belongs_to :post_description, dependent: :destroy

そして最終的に正しいのが、こちら。

models/posts_controllers.rb
  has_one :post_descriptions, dependent: :destroy
但し、次はこんなエラーが出ました。

よくよく確認すると、fields_forのモデルの記述方法が間違っていたので修正しました。

views/post/_form.html.haml
= f.fields_for :post_description do |ff|

そうこうしてようやく完成。
これに至るまでに「2時間以上」掛かってしまいました・・・

相談出来る相手も居ない為、一度ハマってしまうと、中々抜け出すことが出来ないのが、個人開発の難しいところだと、改めて感じました。

Railsの日本語化対応が全て完了していなかった

開発の過程で、何度か下記の様なエラーに遭遇しました

translation missing: ja.activerecord.errors.messages.record_invalid

これは前回デフォルトの言語を日本語にしたのですが、他言語に対応させる為のgemを導入し忘れていました。

gem 'rails-i18n'

明日の予定

  • 画像のアップロード機能(Shrine)
  • CKEditorによる記事の編集機能

明日にはこの二つを完成させるところまで持って行きたい。
そしてテストコードを書きます。書かないと本当に駄目だ・・・無理・・・

  • 記事の検索機能(ransack)

そして、ransackの導入くらいまでは進めたいと考えてます。

※追記:五日目の記事を投稿しました
【10日間でポートフォリオ作成に挑戦】5日目:CKEditorへ画像アップロード機能を追加