Ruby on rails いいね機能について


1.なぜこの記事を書いたのか?

アソシエーションについての理解が曖昧で、特に中間テーブルを介した時の理解が怪しい箇所があると思った。備忘録として残しておきたい。

初学者程度の知識を前提で書いているので、端折っている部分があります。間違い、改善点等ありましたらコメントもらえると助かります。


2.環境

  • ruby 3.2.2

  • Rails 7.1.2


3.アソシエーションについて

「関連付け(アソシエーション: association)」は、2つのActive Recordモデル同士のつながりを指します。(Railsガイドより)
これによりシンプルで直感的なコードを書くことが出来る。


4.中間テーブルについて

「多対多」の関係性を表現する為のテーブル。


5.1対多の関係

noteの様な投稿サイトを例とする。

ユーザー(user)は0つ以上の投稿(post)を持っている。ユーザーが削除されると紐づいている投稿も削除される。

1.E-R図

2.マイグレーションファイル

class CreateUsers < ActiveRecord::Migration[7.1]
  def change
    create_table :users do |t|
      t.string :name, null: false

      t.timestamps
    end
  end
end
class CreatePosts < ActiveRecord::Migration[7.1]
  def change
    create_table :posts do |t|
      t.string :title, null: false
      t.text :body, null: false
      t.references :user, null: false, foreign_key: true

      t.timestamps
    end
  end
end
  • userをreferences型にすることでuser_idを作成することが出来る。

  • `foreign_key: true`とすることでuser_idを外部キーとすることが出来る。

3.アソシエーションの設定

class User < ApplicationRecord
  has_many :posts, dependent: :destroy 
  # 相手が多数なので複数形(posts)で定義。
  # dependent: :destroy`とするとuserの削除で関連するpostも削除される。
end
class Post < ApplicationRecord
  belongs_to :user # userへ従属することを定義。
end

使用例: user.idが1のユーザーの投稿を取得したい。

user = User.find(1)
posts = Post.where(user_id: @user.id) #アソシエーション無しの取得
posts = @user.posts #アソシエーション有りの取得
  • アソシエーションを設定することで直感的で簡単なコードを使用出来る。


6.多対多の関係

5.1対多の関係」の投稿に対して、ユーザーは複数の投稿にいいね(like)することが出来る。投稿は複数のユーザーからいいねされる。

1.E-R図

「5.1対多の関係」のER図にlikesテーブルを追加した

2.マイグレーションファイル

class CreateLikes < ActiveRecord::Migration[7.1]
  def change
    create_table :likes do |t|
      t.references :user, null: false, foreign_key: true
      t.references :post, null: false, foreign_key: true

      t.timestamps
    end
    add_index :likes, [:user_id, :post_id], unique: :true
  end
end

3.アソシエーションの設定

class Like < ApplicationRecord
  belongs_to :user
  belongs_to :post
end
class User < ApplicationRecord
  has_many :posts, dependent: :destroy # 複数の投稿
  has_many :likes, dependent: :destroy # 複数のいいね
  has_many :like_posts, through: :likes, source: :post # 複数のいいねした投稿
end
  • has_many :like_posts, through: :likes」 likesテーブルに登録された投稿と定義出来る。

  • source:  :post」 like_postsというモデルはありません。なのでソース先のモデル(属性)?を記述する必要がある。

class Post < ApplicationRecord
  belongs_to :user # 1人のユーザー
  has_many :likes, dependent: :destroy # 複数のいいね
  has_many :like_users, through: :likes, source: :user # 複数のいいねしたユーザー
end 

4.解釈

user = User.find(1)
user.posts # userの投稿を全て表示
user.likes # userのいいねを全て表示
user.like_posts # userがいいねした投稿を全て表示

書いてみると、なぜここで詰まってしまったのかと思う位シンプルだった。頭の中で整理していたつもりでも書いてみることの大切さが分かった。

この記事が気に入ったらサポートをしてみませんか?