ポリモーフィック・コメントの実装

routesの設定

アーティクルとオピニオンにコメントを追加します。入れ子の形で追加しましょう。

# routs.rb

resources :opinions do
  resources :likes, :comments
end
resources :articles do
  resources :comments
end

コントローラの設定

新規のコメントオブジェクトを作成する為に、コントローラに設定を追加します。以下のように記述して下さい。

# comments#create

def create
  resource, id = request.path.split('/')[1, 2]
  @commentable = resource.singularize.classify.constantize.find(id)
  @comment = @commentable.comments.new(comment_params.merge(user: current_user))
  respond_to do |format|
    if @comment.save
      format.html { redirect_to url_for(@commentable) 

では、それぞれのコードについて説明します。最初の3行(resource~current_user)では、パスからコメントの親モデルを取得してそれに紐づくコメントであるという事をコメントレコードに含めるよう指定しています。また、ユーザー情報も含まれるようにしています。

最初の以下部分で、パスから親モデル・レコードを取得しています。

resource, id = request.path.split('/')[1, 2]

request.pathというのは、pathを取得出来るメソッドです。idが2のアーティクルレコードへのコメントの場合、以下のようなpathが取得されます。

"/articles/2/comments"

このpathのスラッシュ部分を区切り文字と考えて、要素を分割している部分がsplit("/")です。以下のように4つの要素に分割されます。

["", "articles", "2", "comments"]

そして、上記の1個目と2個目の要素をresource, idにそれぞれ代入しています。

resource, id => ["articles", "2"]

次に、以下部分で@commentableに親レコードを代入しています。

@commentable = resource.singularize.classify.constantize.find(id)

現時点では、resourceに代入されているのはarticlesという表記の文字列です。これをArticleという表記に直しているのが、以下部分です。

resource.singularize.classify

singularizeで単数形・複数形を切り替えて、classifyでモデルクラス名に変換しています。

resource.singularize
"article"
resource.singularize.classify
"Article"

そして、constantizeで文字列であるArticleを定数に変換しています。

"Article" → Article

これで、以下コードと同じ処理を行う事が出来ているのです。

Article.find(2)

次に、以下部分です。ここまでで取得した親モデルレコードに紐づくコメントレコードを作成しています。値には、comment_paramsの内容が入るようにしています。それに加えて、mergeというメソッドを使いcomment_paramsとユーザー情報を統合し、1つのハッシュとしています。

@comment = @commentable.comments.new(comment_params.merge(user: current_user))

これで、親モデルレコードに紐づいたユーザー情報を含むコメントレコードが作成できました。それを、@comment.saveで保存するようにして成功すれば@commentable、つまり親モデルレコードページにリダイレクトするようにしています。

パーシャルの作成

パーシャルを作成してその中にコメント一覧とコメントフォームのコードを記述します。1つのパーシャルをアーティクルとオピニオンで共有し使用します。

ポイントは変数を渡す事です。@article、@opinionなどの変数を渡すとそれぞれの処理が出来るようにします。

では、コメント一覧とフォームをパーシャル化しましょう。以下のように作成して下さい。

# comments/_comments.html.erb

<% commentable.comments.each do |comment| %>
  <%= comment.body %><hr>
<% end %>
<%= form_with model: [commentable, Comment.new] do |form| %>
  <%= form.text_area :body %><br>
  <%= form.submit %>
<% end %>

パーシャルを呼び出す

作成したパーシャルをopinions/show.html.erbで呼び出します。以下のように記述して下さい。

# opinions/show.html.erb

<%= render partial: 'comments/comments', locals: { commentable: @opinion } %>

articles/show.html.erbでも。同じパーシャルを呼び出します。

# articles/show.html.erb

<%= @article.body %>
<%= render partial: 'comments/comments', locals: { commentable: @article } %>

課題

以下の作業を行いHerokuにデプロイしましょう。

$ git add . 
$ git commit -m "Create Like and Comment"
$ git checkout master
$ git merge create-like
$ git push
$ git push heroku master
$ heroku run rails db:migrate

まとめ

ここでは、ライク機能やコメント機能を追加しました。また、Ajaxというページを更新せず一部分を変更できる技術や、ポリモーフィックなどの関連付けについて学びました。

ポリモーフィックは特定の親モデルを持たずに、いろいろな親モデルを持つことができる関連付けの仕組みです。関連付けが多くなっていくとコードも増えてしまいますが、同じ機能を持つモデルの場合ポリモーフィックを使えば1つで済むので簡潔に書くことが出来ます。

無料ビデオ講座のお知らせ

Skillhub [スキルハブ]では無料の動画講座を多数公開しています。他校だと数万円するような講座が無料で受講できます。

無料講座一覧を見る

×