2020.02.26
中間テーブルのリレーション(コメント機能、いいね機能)について備忘録
モデルの関連付けで躓いてしまったので、忘れないよう纏めておきます。
単純ですが、今のリレーションはこんな感じになっています。
reference型と普通にカラム追加をする場合の違い
中間テーブルに関連付けする際に、各々に紐付くidを生成する必要があります。
その時、reference型で指定する方法と、普通にカラム追加する2パターンあったのですが、どちらも同じ処理っぽい。
どちらでやっても同じですが、reference型で指定したほうが、後からmigrationファイルを確認した際ぱっと見でわかりやすいのかな??
$ rails g model comment content:string user:references image:references
migrationファイル reference型でやる場合↓
def change
create_table :comments do |t|
t.string :content
t.references :user, foreign_key: true
t.references :image, foreign_key: true
end
end
migrationファイル 普通にカラム追加する場合(外部キー制約もつける場合)↓
def change
create_table :comments do |t|
t.string :content
t.integer :user
t.integer :image
end
add_foreign_key :images, :users
end
インデックスを付与するメリットは検索が高速になるとのこと。何万行とかになるとその恩恵を受けるらしい。
投稿された記事についたコメント数をカウントする
例えば今回のように、投稿された記事にそれぞれコメントが付くような仕様の場合、モデルにcounter_cacheを設定することで関連するテーブルのレコード数を取得できるとのこと。(Qiita参照)
comment.rb
class Comment < ApplicationRecord
belongs_to :user
belongs_to :image, :counter_cache => true
end
image.rb
class Image < ApplicationRecord
belongs_to :user
has_many :comments, dependent: :destroy
end
記事と紐づいているコメントを投稿する場合の処理
ルーティングにて、imagesテーブル(記事)の中にcommentsテーブル(コメント)をネストさせています。
images(記事)が投稿されたとき、commentsでコメントできるようになるみたいなイメージ。
Routes.rb
resources :images, only: [:new, :create, :destroy] do
resources :comments, only: [:create]
end
form_withでネストする時、Imageのshowアクションでインスタンス変数を定義します。
images_controller.rb
def show
@image = Image.find(params[:id])
@comment = @image.comments.build
end
@imageでコメントする記事のIDを取得しています。
@commentは@imageに関連したインスタンスを生成します。(buildとnewは意味は同じですが、buildは慣習的に関連付けに使うのがベターらしい)
アクションでインスタンス変数を定義したら、viewファイルにフォームを実装していきます。
show.html.erb
<%= form_with(model: [@image, @comment], local: true) do |f| %>
<%= f.text_area :content, class: "form-control" %>
<%= button_tag type: "submit", class: "btn btn-success float-right mt-1" do %>
<i class="fa fa-commenting-o"></i> コメントする
<% end %>
<% end %>
model: [@image, @comment]でネストすれば、個々の記事に対してコメントを付けることができるようになります。
ややこしくて落とし込むのに苦労しましたがなんとかアウトプットしてみました。まだ関連付けについて書いていないことはあるので、後々追記していく予定です!