所以我使用rails和CanCanCan一起使用。 我有即有機會獲得0或更多的項目 每個項目都有或多個子項目的用戶。 這兩個項目和子項目都有經理 如果您是項目經理,則可以查看其所有子項目 如果您是子項目的經理,還可以看到項目(但不是任何其他項目中的其他子項目)在CanCanCan中加載accessible_by作用域
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)
但我的概述頁面上我也想快速鏈接添加到所有(允許)子項目引導下拉菜單)。 原來我用下面的等效在我看來代碼:
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
這是更快但不太乾淨。我還懷疑可以嗎?在這種情況下,方法也相對較慢。
理想情況下,將有可能與eagerload加載正確的accessible_by相關的has_many。不幸的是我沒有看到這樣做的方法
事實上,它更糟糕,因爲每個子項目也有團隊在其中與子項目類似的訪問semantas(每個團隊有一個或多個mangerrs,如果你可以看到團隊,你可以看到子項目和項目)。快速鏈接到團隊也添加到項目索引頁面上。