-
I'm so happy with CanCanCan. My Rails views are so easy to understand now. Thanks. However on one page I have an ugly case of N+1 queries. And I fail to find a solution. Help would be very welcome. The application runs https://screenshots.debian.net/ – a web site managing screenshots for Debian/Linux software packages that I have been maintaining for the community for ~10 years. I basically have two models:
A Package has_many :screenshots. Screenshots can be in different states. They can be new and need to be moderated (approved=false). They might be hidden temporarily (hidden=true). So depending on whether you are logged in and who you are, you may see different screenshots. My ability file looks like: # Everybody can see public screenshots
can :view, Screenshot, approved: true, hidden:false
if user.present? # Logged-in users
# Allow to view own uploads (even not-yet-approved)
can :view, Screenshot, user_id: user.id
# Admins can see any screenshots
if user.admin_role?
can :view, Screenshot
end
end In the view you see at https://screenshots.debian.net/packages?show=with the logic is basically: @packages = Package.where…
@packages.each do |pkg|
= image_tag(pkg.screenshots.accessible_by(current_ability, :view).first) The first line gets packages: SELECT "packages".* FROM "packages" WHERE… The third line however is the culprit that does N+1 queries like: SELECT "screenshots".* FROM "screenshots"
WHERE "screenshots"."package_id" = $1 AND "screenshots"."approved" = $2 AND "screenshots"."hidden" = $3
LIMIT $4 [["package_id", 150800], ["approved", true], ["hidden", false], ["LIMIT", 1]] So the obvious question is: how would I properly use .accessible_by while avoiding N+1? Thank you very much in advance for any input. I've been stuck on this for days. …Christoph |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment 3 replies
-
Your issue is not related to cancancan specifically. You want to eager load an association with scope. I wrote about this some time ago: https://medium.com/@coorasse/eager-load-associations-with-parameters-in-rails-6e9fd7b65923 I expect something like: packages = Package.where(...)
ActiveRecord::Associations::Preloader.new.preload(packages, : screenshots, Screenshot.accessible_by(...)) |
Beta Was this translation helpful? Give feedback.
Your issue is not related to cancancan specifically. You want to eager load an association with scope. I wrote about this some time ago: https://medium.com/@coorasse/eager-load-associations-with-parameters-in-rails-6e9fd7b65923
I expect something like: