LoginSignup
1
2

More than 3 years have passed since last update.

has_manyで中間テーブルから親モデルの別のassociationを取ってきたい

Posted at

概要

Railsを使用してデータを扱う際、殆どこんな機会は訪れない(別の方法などで代替できることがほとんど)ですが、どうしよもない事情で中間テーブルから関連付けを貼る必要があったので備忘録としてメモっておきます。

事前知識

class User < ApplicationRecord
   has_many :group_users
   has_many :groups, through: :group_users
   has_many :comments
end

class Group < ApplicationRecord
  has_many :group_users
  has_many :users, through: :group_users
  has_many :comments
end

class Comment < ApplicationRecord
  belongs_to :user
  belongs_to :group
end

class GroupUser < ApplicationRecord
  belongs_to :group
  belongs_to :user
end

このようなクラスが存在しているとします。
通常であればGroupUserという中間テーブルを起点として何かすることはほとんどないですし、あったとしてもUserやGroup経由でCommentを取得することができるので、困ることはほとんどありません。

一方、GraphQLを使用していたり、何かアソシエーションのタイミングで整ったデータが欲しいなどの稀な事情でGroupUserのインスタンスからgroupとuserが絞り込まれたcommentの一覧が欲しい場合があったりしました。

普通にthroughをして取得しようとすると、例えば下記のようなコードになります。

class GroupUser < ApplicationRecord
  belongs_to :group
  belongs_to :user
  has_many :comments, through: :user #groupでもいい
end

ただ、この方法だとthroughしたどちらかのカラムの値では絞り込まれますが、もう片方のカラムでは絞り込みが行われません。

どちらでthroughしたとしても、userかgroupのどちらかでの絞り込みしか行われず、意図した値は取得できません。

解決策

じゃあどうするのかというと、socpeを使います。

class GroupUser < ApplicationRecord
  belongs_to :group
  belongs_to :user
  has_many :comments,->(group_user) { where(group_id: group_user.group_id) }, through: :user #groupならuserでwhere
end

has_manyはスコープの引数として自分自身だけは取ることができます。なので、このようにすることでgroup_userインスタンスのgroup_idとuser_idを持ったコメントの一覧を取得することができます。

どうしても中間テーブルを起点にして取得しなければいけない状況になった場合に役立てば幸いです。

1
2
0

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
2