问题
I am struggling to find a suitable solution for what should be a simple task. Essentially I have a category model which has many posts. The post belongs to the category.
I am displaying categories as part of a search form as well as a number of other places and do not want to display categories that have no associated posts. That seems kind of pointless.
I managed to solve this problem by adding the following method to my category model.
# Check if Category has associated results
def self.with_results
includes(:posts).where.not(posts: { id: nil })
end
That works fine allowing me to filter categories that have no results. The slightly more confusing bit is when I try to use scopes.
My Post has several scopes such as frontend_visible
which dictates whether it should be accessible from the frontend (non-admin).
scope :frontend_visible, -> { where(:state => ['approved', 'changes_pending_approval']) }
Equally I have other scopes to pull posts that are marked as private content only (members only).
The problem with my initial solution is that a category that contains posts which are not approved will not be shown, equally non-members will not be able to see posts that are marked as private although the category will still be shown.
The ideal solution would be something like:
Get all categories that have associated posts, if associated posts are not frontend visible, disregard category. If current_user can not access private content and all associated posts are marked private, disregard category.
I have the scopes but I am unsure how to use them from the associated model. Is this possible?
回答1:
As i understand, you need to select categories with posts visible to an user. For that you need to do two things:
- Make mapping between user’s roles and post’s visible scopes
- Select categories for posts visible by user. In your case it’s easier to select that categories in two queries, without joins.
Try this code:
class Category < ApplicationRecord
has_many :posts
scope :with_posts_for_user, -> (user) do
where(id: Post.categories_for_user(user))
end
end
class Post < ApplicationRecord
belongs_to :category
scope :frontend_visible, -> { where(:state => ['approved', 'changes_pending_approval']) }
scope :member_visible, -> { where(:state => ['approved', 'changes_pending_approval', 'private']) }
scope :categories_for_user, -> (user) do
(user.member? ? member_visible : frontend_visible).distinct.pluck(:category_id)
end
end
来源:https://stackoverflow.com/questions/43209400/rails-querying-an-associated-models-scope