Railsでいいね機能
個人開発しているサービスにいいねボタンをつけるためのメモ。
イメージ
- 親テーブル
- posts
- comments
- 子テーブル
- likes
投稿にもコメントにも「いいね」できるようにしたい。
課題
親テーブルが複数ある時にテーブル設計をどうするか。
参考: 複数のテーブルに対して多対一で紐づくテーブルの設計アプローチ|日本橋のシステム開発会社|スパイスファクトリー株式会社
アプローチ方法
- ポリモーフィック関連
- 複数の関連テーブル(中間テーブル)
- 親テーブルの作成
- テーブルの分割
どれを選択するか。悩んだのでSQLアンチパターンを買って読みました。
- 作者: Bill Karwin,和田卓人,和田省二,児島修
- 出版社/メーカー: オライリージャパン
- 発売日: 2013/01/26
- メディア: 大型本
- 購入: 9人 クリック: 698回
- この商品を含むブログ (45件) を見る
合わせてmastodonも参考にしました。 mastodonでは、ポリモーフィック関連を採用しているようでした。
create_table "notifications", id: :serial, force: :cascade do |t| t.integer "account_id" t.bigint "activity_id" t.string "activity_type" t.datetime "created_at", null: false t.datetime "updated_at", null: false t.integer "from_account_id" t.index ["account_id", "activity_id", "activity_type"], name: "account_activity", unique: true t.index ["activity_id", "activity_type"], name: "index_notifications_on_activity_id_and_activity_type" end
なるべくRailsに沿ってつくりたかったので、今回はmastodonを参考にPolymorphicで実装することにしました。
実装
命名については、ableを語基の後ろに付けるものと抽象名詞を使うものとがあるようでした。
参考:Rails ポリモーフィック関連の関連名の命名 - 130単位
このあと通知機能の実装も検討していて、そこでもpolymorphicを使用する可能性があったので、汎用性が高い抽象名詞を利用することにしました。
$ rails g model like activity:references{polymorphic}:index user:references
class CreateLikes < ActiveRecord::Migration[5.0] def change create_table :likes do |t| t.references :activity, polymorphic: true t.references :user, foreign_key: true t.timestamps end end end
$ rake db:migrate
class Like < ActiveRecord::Base belongs_to :activity, polymorphic: true belongs_to :user validates :user_id, uniqueness: { scope: [:activity_type, :activity_id] } end class Post < ActiveRecord::Base has_many :likes, as: :activity end class Comment < ActiveRecord::Base has_many :likes, as: :activity end