has_manyメソッドのsourceオプションは次の場合に使用します。
- 多対多のアソシエーションに別名をつける
- 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
この時、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 :posts
をhas_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'
とし、どこのテーブルを参照するのか、どの外部キーを参照するのかを指定する必要があります。