Reputation: 2821
CONTEXT:
In my setup Users have many Communities through CommunityUser, and Communities have many Posts through CommunityPost. If follows then, that Users have many Posts through Communities.
has_many :community_users
has_many :communities, through: :community_users
has_many :posts, through: :communities
Given the above User.rb, Calling "current_user.posts" returns posts with one or more communities in common with current_user.
QUESTION:
I'm looking to refine that association so that calling "current_user.posts" returns only those posts whose communities are a complete subset of the current_user's communities.
So, given a current_user with community_ids of [1,2,3], calling "current_user.posts" would yield only those posts whose "community_ids" array is either 1, [2], [3], [1,2], [1,3], [2,3], or [1,2,3].
I've been researching scopes here, but can't seem to pinpoint how to accomplish this successfully...
Upvotes: 13
Views: 8994
Reputation: 6366
You don't show the model and relationship definitions for for Community
or CommunityPost
so make sure you have a has_many :community_posts
and a has_many :posts, through: :community_posts
on your Community
model and a belongs_to :community
and a belongs_to :post
on CommunityPost
. If you don't need to track anything on ComunityPost
you could just use a has_and_belongs_to_many :posts
on Community
and a join table communities_posts
containing just the foreign keys community_id
and post_id
.
Assuming you have the relationships setup as I describe you should be able to just use current_user.posts
to get a relation that can be further chained and which returns all posts for all communities the user is associated with when you call .all
on it. Any class methods (such as scope methods) defined your Post model will also be callable from that relation so that is where you should put your refinements unless those refinements pertain to the Community
or CommunityPost
in which case you would put them on the Community
or CommunityPost
models respectively. Its actually rare to need an AR relationship extension for scopes since usually you also want to be able to refine the model independently of whatever related model you may use to get to it.
Upvotes: 0
Reputation: 76774
Nice question...
My immediate thoughts:
--
ActiveRecord Association Extension
These basically allow you to create a series of methods for associations, allowing you to determine specific criteria, like this:
#app/models/user.rb
has_many :communities, through: :community_users
has_many :posts, through: :communities do
def in_community
where("community_ids IN (?)", user.community_ids)
end
end
--
You could use conditions in your association, like so:
#app/models/user.rb
has_many :posts, -> { where("id IN (?)", user.community_ids) }, through: :communities #-> I believe the model object (I.E user) is available in the association
--
I originally thought this would be your best bet, but looking at it more deeply, I think it's only if you want to use a different association name
Specifies the source association name used by has_many :through queries. Only use it if the name cannot be inferred from the association. has_many :subscribers, through: :subscriptions will look for either :subscribers or :subscriber on Subscription, unless a :source is given.
Being honest, this is one of those questions which needs some thought
Firstly, how are you storing / calling the community_ids
array? Is it stored in the db directly, or is it accessed through the ActiveRecord method Model.association_ids
?
Looking forward to helping you further!
Upvotes: 12