2019/05/05
今回は、2019年のGW期間(10日間)を全て費やして取り組むポートフォリオの製作過程
を取りまとめた内容を投稿させて頂きます。(投稿は毎日行う予定)
全体通した取り組みの詳細については、前回までの記事をご参照ください。
【10日間でポートフォリオ作成に挑戦】1日目:要件定義〜記事投稿のCRUD
【10日間でポートフォリオ作成に挑戦】2日目:アクセス制限〜コメントのCRUD機能
【10日間でポートフォリオ作成に挑戦】3日目:ページネーション~CKEditorの導入
【10日間でポートフォリオ作成に挑戦】4日目:テーブル分割〜CKEditorのフォームへの反映
【10日間でポートフォリオ作成に挑戦】5日目:CKEditorへ画像アップロード機能を追加
【10日間でポートフォリオ作成に挑戦】6日目:テストコードの実装
【10日間でポートフォリオ作成に挑戦】7日目:検索機能〜いいね機能の実装
【10日間でポートフォリオ作成に挑戦】8日目:記事ストック機能〜ユーザーフォロー機能の実装
ここからは、今日1日で取り組んだ作業内容をご説明します。
先日、サーバーサイドのの実装が概ね完了したので、全く未着手だったフロントエンドの実装を行って行きます。
と言っても、私自身、実務でフロントの実装は全く経験していないのと、残り二日という短い期間なので、手早く実装できる手段を採用します。
そこで利用するのが、前回紹介したCSSフレームワークのMaterializeCSSです。
本当は、主流のBootstrapを利用したかったのですが、全く触った事が無いので、今回は諦めました。
使い方としては、公式のドキュメントから、使いたいパーツやデザインを探してきて、そのデザインを適用させる為のclass
を、任意の箇所に記述するだけで、実装が完了します。
なので、全くCSSを触らなくても、WEBサイトの体裁を整える事ができます。
↓公式ドキュメント
↓実装したコード
= f.submit value: t('common.button.submit'), class: 'waves-effect waves-light btn orange'
そうして、
↓記事の一覧表示
↓記事の作成ページ
↓検索機能
↓ログインページ
↓マイページ
即席なので、かなり粗だらけですが、ゆくゆくはCSSフレームワークは使わずに仕上げていきたいと考えています。Vue.jsも使ってみたいですし!
ここからは今日の失敗をまとめていきます
記事の一覧を表示する箇所ではページネーションを導入していたのですが、1ページの表示件数を指定する記述は、各コードにそれぞれ記述していました。
記事の一覧は、下記のコードで表した通り、「通常の一覧表示・検索結果の一覧・ストックの一覧・自身の投稿記事の一覧」の4箇所が該当します。
def index
@posts = Post.page(params[:page]).per(10).order(id: "DESC").includes(:user)
end
def search
@search = Post.ransack(params[:q])
@posts = @search.result.page(params[:page]).per(10)
@keyword = params[:q][:title_cont]
end
def show
@posts = Post.where(user_id: params[:id]).page(params[:page]).per(10).order(id: "DESC")
@user = User.find(params[:id])
end
def post_stocks
post_stocks = current_user.post_stocks.pluck(:post_id)
@posts = Post.where(id: post_stocks).page(params[:page]).per(10).order(id: "DESC")
end
流石に4箇所全てにベタ打ちは冗長なので、変数に置き換える事にしました。
今回は、コントローラーが別れているので、application_controller
に変数を定義しています。
PER = 10
これで、もし表示件数を変更する必要が出て来ても、application_controller
の記述だけ変更すれば良いので、メンテナンス性は高まります。
念のため、振り返りでER図を再掲します。
注目して頂きたいのが、記事に添付した画像を、どの様に管理しているか?です。
ER図では、PostDescription
と関連付けさせたimage
テーブルで管理する様にしています。
そして、今回の記事の編集はCKEditor
を利用していますが、CKEditorは、画像アップロードの操作をした時点で、画像を保存します。
↓この時点
つまり、記事の新規作成の場合、記事の作成より先に、画像がDBに保存されます。
なので、画像保存時に、記事との関連付けを行う事が出来ません(まだ存在しないデータと関連付けは出来ない)
CKEditorは、アップロードした画像のパスも含めて、入力した情報をHTML形式に変換して保存してくれるので、関連付けしていなくとも、編集や詳細表示は問題なく出来ます。
支障をきたすのが、記事の一覧表示で、画像を表示させる場合です。
関連付けしていないので、PostからもImageからも、互いにどのデータと紐づいているか判別出来ません。
それを解消させる為に、下記の様な手段を取りました。
1:postにimage_idカラムを新たに追加し、モデルには下記のアソシエーションを記述
has_one :image, dependent: :destroy
2:画像保存後に、保存されたレコードのIDをセッションで保持
def create
image = current_user.description_images.build(
image: params[:upload],
image_relation: params[:image_relation]
)
if image.save
render json: {
url: image.image[:standard].url,
uploaded: true
}
#画像のDBへの保存が完了したタイミングで、IDをセッションに保持
# 複数枚画像を投稿した際は、最初の画像を登録する様にnilガードで記述
session[:image_id] ||= image.id
else
render json: {
error: {
message: image.errors.full_messages
},
uploaded: false
}
end
end
3:記事保存時に、セッションに保持していたImageのIDも、外部キーとして一緒に保存する
def create
@post = current_user.posts.build(post_params)
@post[:image_id] = session[:image_id]
if @post.save
session[:image_id] = nil
redirect_to post_path(@post), notice: t('common.message.post_create')
else
render :new
end
end
こうする事で、あとは下記のコードで、記事一覧の中で画像も表示させる事が可能になります。
.nav-wrapper.container
%h5.header.orange-text
= t('common.header.post_index')
.row
-# 要素の数だけ繰り返し
= render @posts
= link_to post_path(post) do
.col.s6
.post.card
.card-image
- if post.image_id.present?
-# この記述で対象のpostと関連付いた画像を表示させる
-# (:standard)は任意で変更できる様にした画像リサイズのオプション
= image_tag post.image.image_url(:standard)
- else
= image_tag 'no_image.png'
.card-title
= post.title
.card-user
= "投稿者:#{post.user.name}"
もっと良い方法がRailsやCKEdtorにはあるのかもしれませんが、あまり調査に時間を掛ける余裕も無かったため、一旦この方法で実装しました。
これについては、追い追い調査して、効果的な方法を探りたいと考えています。
AWSへのデプロイが1ヶ月ぶりの作業になるのと、HTTPS化が初の試みなので、本当に明日1日だけで完成できるのか?かなり不安が残ります。
いずれにしても、この10日間の開発で終わりにするのではなく、今後も継続して開発は続けて行き、機能を更にブラッシュアップさせて行こうと考えています。
※追記:10日目を投稿しました
【10日間でポートフォリオ作成に挑戦】10日目:AWSでのデプロイ