I have the following models:
class User < ActiveRecord::Base
has_many :memberships
has_many :groups, :through => :memberships
end
class Group < ActiveRecord::Base
has_many :memberships
has_many :users, :through => :memberships
end
class Membership < ActiveRecord::Base
belongs_to :user
belongs_to :group
end
class Post < ActiveRecord::Base
belongs_to :group
end
I have to find all posts that belong to groups where user is a member. I have made it with this method:
@post = Post
.joins(:group => {:memberships => :user})
.where(:memberships => {:user_id => current_user.id})
but it produces unefficient SQL:
SELECT "posts".* FROM "posts"
INNER JOIN "groups" ON "groups"."id" = "posts"."group_id"
INNER JOIN "memberships" ON "memberships"."group_id" = "groups"."id"
INNER JOIN "users" ON "users"."id" = "memberships"."user_id"
WHERE "memberships"."user_id" = 1
I want to make a query like this:
SELECT posts.* FROM posts
INNER JOIN memberships ON memberships.group_id = posts.group_id
WHERE memberships.user_id = 1
How can I do this without using raw SQL?
You can get closer without changing your model at all, by removing the unused join from your call:
Post.joins(group: :memberships).where(memberships: { user_id: 1 })
compiles to SQL
SELECT "posts".* FROM "posts"
INNER JOIN "groups" ON "groups"."id" = "posts"."group_id"
INNER JOIN "memberships" ON "memberships"."group_id" = "groups"."id"
WHERE ("memberships"."user_id" = 1)
something like this should work for you, although it requires mixing in a little raw SQL
Post
.joins("INNER JOIN memberships ON memberships.group_id = posts.group_id")
.where(:memberships => {:user_id => current_user.id})
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With