LoginSignup
1

More than 1 year has passed since last update.

<Active Record> has_manyのsourceオプションはいつ使うのか

Last updated at Posted at 2022-09-19

has_manyメソッドのsourceオプションは次の場合に使用します。

  1. 多対多のアソシエーションに別名をつける
  2. has_manyで指定するモデル名が重複している

例として、ユーザーが投稿を作成・いいねできる関連付けを行います。

いいねした投稿を取得する

#models/user.rb
class User < ApplicationRecord
  has_many :posts
  has_many :likes
end

#models/like.rb
class Like < ApplicationRecord
  belongs_to :user
  belongs_to :post
end

#models/post.rb
class Post < ApplicationRecord
  has_many :likes
  belongs_to :user
end

上記のモデルにいいねした投稿を取得しようとhas_many :postsとしても、すでに存在するので書くことはできません。

そこで、has_many :like_postsと命名した上で、中間テーブルのLikesテーブルを通してPostsテーブルからデータを取得できるようにします。

#models/user.rb
class User < ApplicationRecord
  has_many :posts
  has_many :likes
+ has_many :like_posts, through: :likes, source: :post
end

qiita-image.png

この時、like.rbのbelongs_to :postを参照してくれます。

自由に関連付け名を指定した場合、どこのテーブルからデータを取得すれば良いかを判断してくれないので、sourceオプションで指定してあげることで解決できます。

投稿にいいねしているユーザーを取得する

また、ある投稿にいいねしているユーザーを取得したい場合は、

#models/post.rb
class Post < ApplicationRecord
  has_many :likes
  belongs_to :user
+ has_many :users, through: :likes
end

とします。
この場合、命名が重複しないのでusersのままでも大丈夫ですが、命名を変更する場合はsourceオプションを指定する必要があります。

sourceオプションは多対多のアソシエーションの場合ですが、一対多のアソシエーションの場合はclass_nameオプションで解決できます。

class_nameオプション

上記の例をそのまま使用し、仮にmodels/user.rbでhas_many :postshas_many :create_postsとしなければならなかったとします。

この場合、userテーブルとpostテーブルの関係は一対多なので、

#models/user.rb
class User < ApplicationRecord
- has_many :posts
+ has_many :create_posts, class_name: 'Post', foreign_key: :user_id
  has_many :likes
end

class_name: 'Post'とし、どこのテーブルを参照するのか、どの外部キーを参照するのかを指定する必要があります。

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
1