私は2つのモデルを持っています
class User < AR
has_many :friends
end
class Friend < AR
# has a name column
end
「ジョー」と「ジャック」の両方と友達であるすべてのユーザーを見つける必要があります
Railsでこれを行う方法はありますか?
私は2つのモデルを持っています
class User < AR
has_many :friends
end
class Friend < AR
# has a name column
end
「ジョー」と「ジャック」の両方と友達であるすべてのユーザーを見つける必要があります
Railsでこれを行う方法はありますか?
1 つのオプションは、各名前を個々の INNER JOINS の引数として配置することです。SQL では、次のようになります。
SELECT users.* FROM users
INNER JOIN friends AS f1
ON users.id = f1.user_id
AND f1.name = 'Joe'
INNER JOIN friends AS f2
ON users.id = f2.user_id
AND f2.name = 'Jack'
INNER JOINSなのでf1とf2の両方でusersテーブルを結合できる結果しか表示されません。
Rails で使用するには、次のようにします。
class User < AR
has_many :friends
def self.who_knows(*friend_names)
joins((1..friend_names.length).map{ |n|
"INNER JOIN friends AS f#{n} ON users.id = f#{n}.user_id AND f#{n}.name = ?" }.join(" "),
*friend_names)
})
end
end
次に、次のように呼び出すことができます。
@users = User.who_knows("Joe", "Jack")
DanneManne によって提案されているようにハードコードされた SQL を使用することは、ほとんどの場合うまくいき、おそらくあなたが望む方法ですが、必ずしも構成可能ではありません。テーブル名をハードコーディングするとすぐに、ActiveRecord がテーブルのエイリアスを決定する可能性のある他のクエリにそれを結合するという問題に遭遇する可能性があります。
したがって、余分な複雑さを犠牲にして、次のように ARel を使用してこれを解決できます。
f = Friend.arel_table
User.
where(:id=>f.project(:user_id).where(f[:name].eq('Joe'))).
where(:id=>f.project(:user_id).where(f[:name].eq('Jack')))
これは、ジョブを実行するためにサブクエリのペアを使用します。
結合を使用した ARel ソリューションもあると確信していますが、ARel でそのクエリを作成する方法を理解することはできますが、そのクエリを ActiveRecord クエリの基礎として使用して User モデル インスタンスを取得する方法はわかりません。
考えられる方法:User.all(:joins => :friends, :conditions => ["friends.name IN (?,?)", "Joe", "Jack"], :group => "users.id")
次に、配列を反復処理して、2 人の友人を持つユーザーを見つけます。
これは、自分で同様の問題を解決しようとしたときに得た最良の解決策です。純粋な sql または ActiveRecord でそれを行う方法を見つけたら、お知らせください。