Let's say I have the following moduls:
Category
has_many :products
Product
has_many :tags
Tag
has_one :author
Author
has default scope
default_scope { where(active: true) }
Now when showing categories, I want to show also all products and tags within the product, but I also want to include tags from inactive users.
The most straightforward solution is to remove default scope and create explicit scope instead and use it on all places. But issue is there is a bunch of places where I would need to add that, so that solution is not viable.
The other option is to add new scope to Product
def all_tags
Tag.joins(:author).unscope(author: { where: :active }).where(product_id: id)
end
This works, but it can lead to N+1 issue If there are 10 products within each company with 5 tags in average per product, it would run 50 queries to DB and that's not what I want.
Is there any elegant way to solve N+1 issue?
Of course, I could lead all relevant tags in a controller, something like
@tags_per_product = Tag.joins(:author).unscope(author: { where: :active }).where(product_id: product_ids).group_by(&:product_id)
and then reuse tags_per_product
in a view, but that looks a bit dirty
In Rails, it's always important to find neat and elegant way, so I would like to have it here
Thanks in advance
I solved it like this
In tag.rb
has_one :author, lambda {
unscope(where: :active)
}
So basically this would work and in all context we'd return authors that are excluded by default scope
If for some reason, we need to include those excluded only in certain contexts, I may do it by introducing new
has_one :author_user
or something like this