24
14

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

STIとポリモーフィックを利用したコメント機能の作成

Last updated at Posted at 2019-06-06

#はじめに
インターン先でSTIとポリモーフィックを利用したコメント機能を作成したときに
自分が求めてる情報が出てこなかったのと
ハマったことがいくつかあるのでメモ代わりに残していこうと思います:relieved:

ポリモーフィックやSTIについては
Railsのポリモーフィック関連とはなんなのか
みんなRailsのSTIを誤解してないか!?
などがとても丁寧でわかりやすく参考になります:open_hands:

今回は設計やコード中心なので概念などはそちらで理解していただければと思います:relaxed:
私も未熟なところがたくさんあるので、指摘等あれば教えていただけると嬉しいです:relaxed:

##設計について
今回の設計はざっとこんな感じです。
(いろいろ省いて主要部分だけの実装を行っていきます:man_tone1:)

ER図 (1).png

1つのcommentsテーブルに2種類のテーブルがSTIで継承されており
taskかprojectのどちらかが紐づくような設計となっております!:eyes:
常にprojectとtaskに紐づくcommentを作るわけではないので
projectとtaskからのびるcommentへのリレーションは点線で記述しました:fist:
(正しい書き方があるのかわからなかったです:sweat:

##実装
早速実装に入っていきます!

###テーブルの作成
commentsとtasksとprojectsテーブルの作成を行っていきます:relieved:
commentsテーブルにはSTIのためのtypeを作成し
ポリモーフィックのためのcommentable_typecommentable_idという〇〇_typeと〇〇_idというカラムも作ります:punch:

$ rails g model Comment content:string type:string commentable_type:string commentable_id:integer
$ rails g model Task title:string content:string 
$ rails g model Project name:string 

###モデルの設定

モデルのディレクトリ構造は写真のようにcommentをtaskとprojectが継承するように作成します:runner_tone1:
スクリーンショット 2019-05-29 18.01.28.png

こうすることによりSTIを行うことができます:raised_hands:
次はモデルにポリモーフィックなどの設定を行っていきます:point_up:

comment.rb
class Comment < ApplicationRecord
  belongs_to :commentable, polymorphic: true
end
project.rb
class Project < ApplicationRecord
  has_many :comments, class_name: 'Comment::Project', as: :commentable, dependent: :destroy
end
task.rb
class Task < ApplicationRecord
  has_many :comments, class_name: 'Comment::Task', as: :commentable, dependent: :destroy
end

commentを継承しているprojectとtaskは

.rb
class Comment::Task < Comment
end
.rb
class Comment::Project < Comment
end

と記述することにより、commentを継承してくれます:astonished:
モデルに記述することは以上です:slight_smile:

###ポリモーフィックとSTIができているかの確認
この時点でrails consoleで以下のコマンドたちを打ってみてください!:point_down:

 pry(main)> Comment::Task.new
=> #<Comment::Task:0x00007fbf75f1e668 id: nil, type: "Comment::Task", commentable_type: nil, commentable_id: nil>
 pry(main)> @task = Task.create(title: "test", content: "test")
 pry(main)> @task.comments.build
=> #<Comment::Task:0x00007fbf7b0ba418 id: nil, type: "Comment::Task", commentable_type: "Task", commentable_id: 4, content: nil, created_at: nil, updated_at: nil>

typeには継承しているmodelが入っていおり
commentable_typeにはcommentに紐づくmodelが入り
commentable_idにはcommentに紐づくidが入っております:thumbsup:
こうすることにより、commentという1つのモデルに2つのうちどちらか1つのモデルに紐づけることができます:clap:
この3つのカラムが作成できていたら、ポリモーフィックとSTIができています:sparkles:

###ルーティングとcontrollerの設定

routes.rb
Rails.application.routes.draw do
  resources :tasks do
    resources :comments, only: [:create], controller: 'task/comments'
  end
  resources :projects do
    resources :comments, only: [:create], controller: 'project/comments'
  end
end

コントローラーはタスク用とプロジェクト用で分けて作ります:woman_tone1:
スクリーンショット 2019-05-30 12.44.55.png

###タスクのコメント機能の作成
ここからはタスクのコメント機能について作成していきます:muscle:
まずはcontrollerです:open_hands:

controlelrs/tasks_controller.rb
@comment = Comment::Task.new

Comment::Taskのインスタンスを作成してtasksの詳細ページに投稿画面を作成します:v:

tasks/show.html.erb
<%= form_for @comment, url: task_comments_path(task_id: @task.id) do |f| %>
  <%= f.text_area :content %>
  <%= hidden_field_tag :type, @comment.type %>
  <%= f.submit 'コメントを投稿する' %>
<% end %>

タスクを継承しているコメントControllerでcreateを行っていきます:point_down:

controllers/task/comment_controller.rb
  def create
    @comment = @task.comments.build(comment_params)
    @comment.save
    redirect_to task_path(@task)
  end

  private

  def comment_params
    params.require(params[:type].underscore.gsub('/', '_').to_sym).permit(:content)
  end

パラメーターの受け取り方はStrong Parametersを動的に設定を参考にしました:dancer:

実はこれだけでもうコメントの作成はできております!:clap:

##終わりに
STIやポリモーフィック、最初全然理解は出来なかったですが、実際に手を動かすことで少し理解できたような気がします。
今はtaskとprojectにしか紐付かないのですが、もっといろんなモデルに紐づくものだと
紐づくために必要な外部キーを増やさなくて良かったり
新しくコメントに関するテーブルを作らなくていいので便利だと感じました。
でもなぜそういう使い方をしている記事がヒットしなかったんだろうという疑問が残りました。
最後まで見ていただきありがとうございました!
ご指摘あればどしどしおまちしております〜!

24
14
3

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
24
14

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?