Так что я использую рельсы вместе с CanCanCan. У меня есть пользователи, у которых есть доступ к 0 или более Проекты Каждый проект имеет или более подпроектов. У обоих проектов и подпроектов есть менеджеры Если вы являетесь менеджером проекта, вы можете увидеть все его подпроекты Если вы являетесь менеджером подпроекта, вы также можете увидеть проект (но не обязательно какие-либо другие подпроекты в рамках этого проекта)Яркая загрузка доступной области видимости в CanCanCan
class Project < ActiveRecord::Base
has_many :sub_projects
has_many :ordered_sub_projects, ->() { order('name') }
has_many :project_managers
end
class ProjectManagers < ActiveRecord::Base
belongs_to :user
belongs_to :sub_project
end
class Subproject < ActiveRecord::Base
belongs_to :project
has_many :subproject_managers
end
class SubProjectManagers < ActiveRecord::Base
belongs_to :user
belongs_to :sub_project
end
class Ability
def initialize(user)
can? :read, Project, { managers: user.id }
can? :read, Project, { sub_projects: { subproject_managers: user.id } } # To allow to see projects if you are manager of subproject
can? :read, SubProject, { subproject_managers: user.id }
can? :read, SubProject, { project: { project_managers: user.id } }
end
end
Теперь я хочу, чтобы отобразить все проекты для данного пользователя, который я могу сделать с:
Projects.all.accessible_by(ability)
Но на моей странице обзора я также хочу добавить QuickLinks ко всем (разрешенных) подпроектов (с использованием бутстрап выпадающего списка). Первоначально я использовал эквивалент ниже, на мой взгляд код:
Projects.all.accessible_by(ability).order(:name).each do |project|
project.sub_projects.accessible_by(ability).order(:name).each do |sub|
add_link sub.name, sub
end
end
Но это вызвало огромный N + 1 проблема при отображении многих проектов. [1] Итак, теперь я перешел на.
Projects.all.accessible_by(ability).
preload(:ordered_subprojects).order(:name).each do |project|
project.ordered_subprojects.each do |sub|
add_link sub.name, sub if can?(:read, sub)
end
end
, который намного быстрее, но менее чист. Также я подозреваю, что может? В этом случае метод относительно медленный.
В идеале можно было бы загрузить связанный файл has_many с загруженным правильным доступом. К сожалению, я не вижу способа сделать это
[1] На самом деле это было еще хуже, потому что у каждого подпроекта также были команды, в которых похожие семанты доступа были SubProject (каждая команда имела одного или нескольких мошенников, если вы может видеть, что команда вы можете увидеть SubProject и Project). Быстрые ссылки на команды также добавляются на страницу индекса проектов.