Rails 4 - Pundit - 索引范围策略 [英] Rails 4 - Pundit - scoped policy for index
问题描述
我正在尝试学习如何在我的 Rails 4 应用中使用 Pundit.
I am trying to learn how to use Pundit with my Rails 4 app.
我有以下型号:
class User < ActiveRecord::Base
has_one :profile
has_many :eois
end
class Profile < ActiveRecord::Base
belongs_to :user
has_many :projects, dependent: :destroy
end
class Project < ActiveRecord::Base
belongs_to :profile
has_many :eois
end
class Eoi < ActiveRecord::Base
belongs_to :project
belongs_to :user
end
我有一个范围EoiPolicy
:
class EoiPolicy < ApplicationPolicy
class Scope
attr_reader :user, :scope
def initialize(user, scope)
@user = user
@scope = scope
end
def resolve
if user.profile.project.id == @eoi.project_id?
scope.where(project_id: @user.profile.project.id)
elsif user.id == eoi.user_id?
scope.where(user_id: user.id)
else
nil
end
end
end
def index?
user.profile.project.id == @eoi.project_id? or user.id == eoi.user_id?
end
def new?
true
end
def show?
user.profile.project.id == @eoi.project_id? or user.id == eoi.user_id?
end
def edit?
user.id == eoi.user.id?
end
def create?
true
end
def update?
user.id == eoi.user.id?
end
def destroy?
user.id == eoi.user.id?
end
end
在我的 EoisController
中,我尝试将范围用于:
In my EoisController
, I have tried to use the scope with:
def index
# @eois = @project.eois
@eois = policy_scope(Eoi)
# @eois = Eois.find_by_project_id(params[:project_id])
end
然后在我的 view/eois/index
中,我尝试显示索引:
Then in my view/eois/index
, I have tried to display the index with:
<% policy_scope(@user.eois).each do |group| %>
我无法让它工作.错误消息在策略中突出显示了我的范围方法的这一行:
I can't get this to work. The error message highlights this line of my scope method in the policy:
if user.profile.project.id == @eoi.project_id?
对我来说,这看起来是正确的,尽管我仍在努力解决这个问题.任何人都可以看到使这项工作需要发生什么,以便如果用户是用户,谁的个人资料拥有相关项目,与该项目相关的所有 eois 都是可见的.
To me, this looks correct, although I'm still trying to figure this out. Can anyone see what needs to happen to make this work, so that if the user is the user, who's profile owns the relevant project, all eois relating to that project are visible.
否则,如果用户是创建eoi的用户,那么他们创建的所有eois都是可见的?
Otherwise, if the user is the user who created the eoi, then all eois they have created are visible?
错误信息说:
undefined method `project' for #<Profile:0x007fa03f3faf48>
Did you mean? projects
projects=
我想知道这是不是因为一个索引会有很多记录,它需要在策略中显示一些不同的东西来识别复数?
I'm wondering if that's because an index will have many records, it needs to show something different in the policy to recognise the plurality?
我也尝试用以下内容替换该行:
I have also tried replacing that line with:
if @eoi.project_id == @user.profile.project.id?
虽然这也是错误的,并且给出了
although that is also wrong and gives
undefined method `project_id' for nil:NilClass
Did you mean? object_id
我也尝试制作范围:
def resolve
# cant figure what is wrong with this
if eoi.project_id == user.profile.project.id?
scope.where(project_id: @user.profile.project.id)
else
nil
end
end
但这也是错误的,并给出了这个错误:
but that's also wrong and gives this error:
undefined local variable or method `eoi' for #<EoiPolicy::Scope:0x007ffb505784f8>
我也试过:
def resolve
# cant figure what is wrong with this
if @eoi.project_id == user.profile.project.id? or Eoi.project_id == user.profile.project.id?
scope.where(project_id: @user.profile.project.id)
elsif user.id == eoi.user_id?
scope.where(user_id: user.id)
else
nil
end
end
end
def index?
user.profile.project.id == Eoi.project_id? or user.id == Eoi.user_id?
end
但该尝试给出了以下错误消息:
but that attempt gives this error message:
undefined method `project_id' for nil:NilClass
Did you mean? object_id
当前想法
我认为我需要向 scope 方法传递的不仅仅是 user 和 scope.如果我也可以通过项目,那么我可以使范围可参考与 EoI 相关的项目.
I think I need to pass more than user and scope to the scope method. If I can also pass project, then I can make the scope referable to the project to which the EoI relates.
如果我可以让这个工作,那么也许我可以让范围方法为控制器上的索引视图工作:
If I could have this working, then maybe I could get the scope method to work for the index view on the controller:
class Scope
attr_reader :user, :scope
def initialize(user, scope, project)
@user = user
@scope = scope
@project = project
end
end
然后在控制器中:
def index
# @eois = @project.eois
@eois = policy_scope(Eoi, @project)
# authorize @eois
# @eois = Eois.find_by_project_id(params[:project_id])
end
这不起作用,当我尝试时,我收到一条错误消息,指出该政策
This doesnt work, when I try I get an error saying that the policy
wrong number of arguments (given 2, expected 1)
请帮忙!
下一次尝试
我的下一个尝试是尝试从 [this]Pundit 问题中获取建议,并实施该想法,以便为特定用户获取正确的范围.
My next attempt is to try taking the suggestions from [this]Pundit issue and implement that idea for how to get the right scope for a particular user.
在我的 Eoi 政策中,我将解析方法更改为:
In my Eoi Policy, I changed the resolve method to:
class Scope
attr_reader :user, :scope
def initialize(user, scope) #project
@user = user
@scope = scope
# @project = project
end
def resolve
# if Eoi.project_id == user.profile.project.id? or Eoi.project_id == user.profile.project.id?
if user.id == eoi.projects.profile.user.map(&:id)
scope.joins(eois: :projects).where(project_id: user.profile.projects.map(&:id)).empty?
# if scope.eoi.project_id == user.profile.projects.map(&:id)
# scope.where(project_id: user.profile.projects.map(&:id)).empty?
# scope.where(project_id: user.profile.project.id)
# elsif user.id == eoi.user_id?
# scope.where(user_id: user.id)
else
# nil
end
end
end
然后在我的 eoi 控制器索引操作中,我尝试了这个:
Then in my eoi controller index action, I tried this:
def index
# @eois = @project.eois
# @eois = policy_scope(Eoi, @project)
policy_scope(Eoi).where(project_id: params[:project_id])
# authorize @eois
# @eois = Eois.find_by_project_id(params[:project_id])
end
那也行不通.此尝试的错误消息说:
That doesnt work either. The error message for this attempt says:
undefined local variable or method `eoi' for #<EoiPolicy::Scope:0x007f98677c9cf8>
我没有想法可以尝试.任何人都可以找到一种方法来为示波器提供正确的输入以进行设置吗?
Im out of ideas for things to try. Can anyone see a way to give the scope the right inputs to set this up?
观察我注意到 github 上很多使用 Pundit 和 scope 的存储库也包含这样的方法:
OBSERVATION I have noticed that a lot of the repos on github that use Pundit with scopes also include a method like this:
def scope
Pundit.policy_scope!(user, record.class)
end
该方法是 Scope 类的补充,未显示在 Pundit gem 文档中.如果有必要包括,它有什么作用?1
That method is in addition to the Scope class and isn't shown in the Pundit gem docs. If that is necessary to include, what does it do? 1
重写
我现在已经浏览了 github 上的 200 多个存储库,以深入了解我应该如何编写策略来实现我的目标.我不知道如何按预期使用 Pundit.
I've now looked through more than 200 repos on github for insight into how I'm supposed to write a policy to meet my objectives. I'm out of ideas for how to use Pundit as intended.
我已经完全改变了我的设置,试图解决我无法理解的问题.我现在有:
I've changed my setup completely to try and work around the bits I can't understand. I now have:
Eois 控制器
class EoisController < ApplicationController
def index
@eois = Eoi.by_user_id(current_user.id)
end
end
项目:: Eois 控制器
Projects:: Eois controller
module Projects
class EoisController < ApplicationController
before_action :get_project
before_action :set_eoi, only: [:edit, :update, :destroy]
# after_action :verify_authorized
def index
@eois = Project.by_user_id(current_user.id).find_by(id: params[:project_id]).try(:eois) || []
end
def show
@eoi = Eoi.find(params[:id])
authorize @eoi
end
def set_eoi
@eoi = EoiPolicy::Scope.new(current_user, params[:project_id]).resolve.find(params[:id])
end
def get_project
@project = Project.find(params[:project_id])
end
Eoi 政策(决定何时显示用户制作的所有 eois)
Eoi Policy (to decide when to show all eois made by a user)
class EoiPolicy < ApplicationPolicy
class Scope
attr_reader :user, :scope
def initialize(user, scope)
@user = user
@scope = scope
end
def resolve
if scope.present?
Eoi.by_user_id(user.id)
# end
else
[]
end
end
end
def index?
user.profile.project.id == Eoi.project_id? or user.id == Eoi.user_id?
end
def new?
true
end
def show?
record.user_id == user.id || user.profile.project_id == record.project_id
# user.profile.project.id == @eoi.project_id? or user.id == eoi.user_id?
end
def edit?
user.id == eoi.user.id?
end
def create?
true
end
def update?
user.id == eoi.user.id?
end
def destroy?
user.id == eoi.user.id?
end
end
路线
resources :eois
resources :projects do
member do
resources :eois, controller: 'projects/eois
end
当我想显示提交的与项目相关的 EoI 时,我使用项目 Eoi 政策;当我想显示用户创建的 Eoi 时,我使用 Eoi 政策——没有范围.
When I want to show EoIs that are submitted in relation to a project, I use the Projects Eoi Policy and when I want to show the Eois that a user has created, I use the Eoi Policy -- no scopes.
我很想弄清楚这一点,这样我就可以按照预期的方式使用这个 gem.建议将不胜感激.我确信这次尝试不是 Pundit 的目的 - 但我无法弄清楚如何使用文档中所示的这个 gem.
I would love to figure this out so I can use this gem the way it is intended. Advice would be greatly appreciated. I'm sure this attempt isn't what Pundit is meant for - but I can't figure out how to use this gem as shown in the docs.
我无法使用 policy_scope,因为我需要将 project_id 参数传递到项目 eoi 控制器索引操作的索引操作中.
I can't use policy_scope because I need to pass the project_id param into the index action for the projects eoi controller index action.
PaReeOhNos 建议
我尝试实施 PareeOhNos 建议的尝试如下.我不确定我是否理解正确,因为 eois 总是有一个项目 ID 和一个用户 ID,但也许我没有明白 load_parent 方法在做什么.
My attempt at trying to implement PareeOhNos suggestion is set out below. I'm not sure I understand it properly because eois will always have a project id and a user id, but maybe I'm not getting the point of what the load_parent method is doing.
在我的 Eois 控制器中,我有:
In my Eois Controller, I have:
class EoisController < ApplicationController
before_action :load_parent
before_action :load_eoi, only: [:show, :edit, :update, :destroy]
def index
authorize @parent
@eois = EoiPolicy::Scope.new(current_user, @parent).resolve
end
def show
end
# GET /eois/new
def new
@project = Project.find(params[:project_id])
@eoi = @project.eois.build
@contribute = params[:contribute] || false
@participate = params[:participate] || false
@partner = params[:partner] || false
@grant = params[:grant] || false
@invest = params[:invest] || false
end
# GET /eois/1/edit
def edit
end
# POST /eois
# POST /eois.json
def create
@eoi = Project.find(params[:project_id]).eois.build(eoi_params)
@eoi.user_id = @current_user.id
respond_to do |format|
if @eoi.save
format.html { redirect_to Project.find(params[:project_id]), notice: 'Eoi was successfully created.' }
format.json { render :show, status: :created, location: @project }
else
format.html { render :new }
format.json { render json: @eoi.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /eois/1
# PATCH/PUT /eois/1.json
def update
respond_to do |format|
if @eoi.update(eoi_params)
format.html { redirect_to @project, notice: 'Eoi was successfully updated.' }
format.json { render :show, status: :ok, location: @eoi }
else
format.html { render :edit }
format.json { render json: @eoi.errors, status: :unprocessable_entity }
end
end
end
# DELETE /eois/1
# DELETE /eois/1.json
def destroy
@eoi.destroy
respond_to do |format|
format.html { redirect_to @project, notice: 'Eoi was successfully destroyed.' }
format.json { head :no_content }
end
end
private
def load_parent
# @parent = (params[:project_id] ? Project.find(params[:project_id] : current_user)
@parent = params[:project_id] ? Project.find(params[:project_id]) : current_user
end
def load_eoi
@eoi = Eoi.find(params[:id])
authorize @eoi
end
在我的 Eoi 政策中,我有:
In my Eoi Policy, I have:
class EoiPolicy < ApplicationPolicy
class Scope
attr_reader :user, :scope
def initialize(user, scope)
@user = user
@scope = scope
end
def resolve
if scope.is_a?(User)
Eoi.where(user_id: scope.id)
elsif scope.is_a?(Project)
Eoi.where(project_id: scope.id)
else
[]
end
end
end
def index?
record.is_a?(User) || user.profile.project.id == record.project_id
end
def new?
true
end
def show?
record.user_id == user.id || user.profile.project_id == record.project_id
end
def edit?
user.id == eoi.user.id?
end
def create?
true
end
def update?
user.id == eoi.user.id?
end
def destroy?
user.id == eoi.user.id?
end
end
在我的 routes.rb 中,我有:
In my routes.rb, I have:
resources :projects do
member do
resources :eois, shallow: true
resources :eois, only: [:index]
在我的 eois/index 中,我有:
In my eois/index, I have:
<% @eois.sort_by(&:created_at).in_groups_of(2) do |group| %>
<% group.compact.each do |eoi| %>
<h4><%= link_to eoi.user.full_name %></h4>
<%= link_to 'VIEW DETAILS', eoi_path(eoi), :class=>"portfolio-item-view" %>
<% end %>
<% end %>
在我的 eois/节目中,我有:
In my eois/ show, I have:
"test"
当我尝试所有这些时,eois/index 页面加载.当我尝试显示特定的 eoi 页面时,我收到一条错误消息:
When I try all this, the eois/index page loads. When I try to show a specific eoi page, I get an error that says:
wrong number of arguments (given 2, expected 0)
错误信息指向授权控制器的@eoi行:
the error message points to authorise @eoi line of the controller:
def load_eoi
@eoi = Eoi.find(params[:id])
authorize @eoi
end
如果我将 authorize @eoi 放在 show 动作而不是 load eoi 方法中,也会出现同样的错误.
The same error arises if I put authorize @eoi in the show action instead of the load eoi method.
申请政策有
class ApplicationPolicy
attr_reader :user, :scope
class Scope
def initialize(user, scope)
#byebug
@user = user
# record = record
@scope = scope
end
def resolve
scope
end
end
def index?
false
end
def show?
scope.where(:id => record.id).exists?
end
def create?
false
end
def new?
create?
end
def update?
false
end
def edit?
update?
end
def destroy?
false
end
def scope
Pundit.policy_scope!(user, record.class)
end
下一次尝试
根据 PaReeOhNos 的建议(上面复制),我尝试对其进行一些调整以更好地适应我的用例.
Taking PaReeOhNos suggestion (copied above), I've tried to adapt it a bit to better fit my use cases.
现在,我有:
Eoi 控制器
class EoisController < ApplicationController
# before_action :get_project
# before_action :set_eoi, only: [:show, :edit, :update, :destroy]
before_action :load_parent
before_action :load_eoi, only: [:show, :edit, :update, :destroy]
# GET /eois
# GET /eois.json
# def index
# @eois = @project.eois
# # @eois = Eois.find_by_project_id(params[:project_id])
# end
def index
# authorize @parent
@eois = policy_scope(Eoi.where(project_id: params[:project_id]))
# @eois = EoiPolicy::Scope.new(current_user, @parent).resolve
end
# GET /eois/1
# GET /eois/1.json
def show
end
# GET /eois/new
def new
@project = Project.find(params[:project_id])
@eoi = @project.eois.build
@contribute = params[:contribute] || false
@participate = params[:participate] || false
@partner = params[:partner] || false
@grant = params[:grant] || false
@invest = params[:invest] || false
end
# GET /eois/1/edit
def edit
end
# POST /eois
# POST /eois.json
def create
@eoi = Project.find(params[:project_id]).eois.build(eoi_params)
@eoi.user_id = @current_user.id
respond_to do |format|
if @eoi.save
format.html { redirect_to Project.find(params[:project_id]), notice: 'Eoi was successfully created.' }
format.json { render :show, status: :created, location: @project }
else
format.html { render :new }
format.json { render json: @eoi.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /eois/1
# PATCH/PUT /eois/1.json
def update
respond_to do |format|
if @eoi.update(eoi_params)
format.html { redirect_to @project, notice: 'Eoi was successfully updated.' }
format.json { render :show, status: :ok, location: @eoi }
else
format.html { render :edit }
format.json { render json: @eoi.errors, status: :unprocessable_entity }
end
end
end
# DELETE /eois/1
# DELETE /eois/1.json
def destroy
@eoi.destroy
respond_to do |format|
format.html { redirect_to @project, notice: 'Eoi was successfully destroyed.' }
format.json { head :no_content }
end
end
private
def load_parent
# @parent = (params[:project_id] ? Project.find(params[:project_id] : current_user)
@parent = params[:project_id] ? Project.find(params[:project_id]) : current_user
end
def load_eoi
@eoi = Eoi.find(params[:id])
# authorize @eoi
end
Eoi 政策
class EoiPolicy < ApplicationPolicy
class Scope
attr_reader :user, :scope
def initialize(user, scope)
@user = user
@scope = scope
end
def resolve
# since we send the scoped eois from controller, we can pick
# any eoi and get its project id
# check if the current user is the owner of the project
# if (user.profile.projects.map(&:id).include?(project_id))
# # user is the owner of the project, get all the eois
# scope.all
# end
# #not the owner , then get only the eois created by the user
# scope.where(user_id: user.id)
# end
if scope.is_a?(User)
Eoi.where(user_id: scope.id)
elsif scope.is_a?(Project) && (user.profile.projects.map(&:id).include?(project_id))
project_id = scope.first.project_id
Eoi.where(project_id: scope.id)
else
Eoi.none
end
end
end
def index?
record.is_a?(User) || user.profile.project.id == record.project_id
end
def new?
true
end
def show?
record.user_id == user.id || user.profile.project_id == record.project_id
end
def edit?
user.id == eoi.user.id?
end
def create?
true
end
def update?
user.id == eoi.user.id?
end
def destroy?
user.id == eoi.user.id?
end
end
路线
resources :eois#, only: [:index]
concern :eoiable do
resources :eois
end
resources :projects do
concerns :eoiable
end
索引
<% @eois.sort_by(&:created_at).in_groups_of(2) do |group| %>
<% group.compact.each do |eoi| %>
<h4><%= link_to eoi.user.full_name %></h4>
<%= link_to 'VIEW DETAILS', project_eoi_path(eoi.project, eoi), :class=>"portfolio-item-view" %>
<% end %>
<% end %>
查看
'test'
这不起作用,因为当我导航到一个项目然后尝试呈现具有匹配项目 ID 的 eois 的索引时,当我的数据库中有 4 条记录时,我得到一个空的索引页呈现.
This isn't working, because when I navigate to a project and then try to render the index of eois that have a matching project id, I get an empty index page, when I have 4 records in my database that should be rendered.
莱托的建议
根据 Leito 的建议,我也试过这个:
Taking Leito's suggestion, I've also tried this:
Eoi 控制器
class EoisController < ApplicationController
before_action :get_project
before_action :set_eoi, only: [:show, :edit, :update, :destroy]
# before_action :load_parent
# before_action :load_eoi, only: [:show, :edit, :update, :destroy]
# GET /eois
# GET /eois.json
# def index
# @eois = @project.eois
# # @eois = Eois.find_by_project_id(params[:project_id])
# end
def index
# authorize @eois
# authorize @parent
# policy_scope(@project.eois)
@eois = policy_scope(Eoi.where(project_id: params[:project_id]))
# @eois = EoiPolicy::Scope.new(current_user, @parent).resolve
end
# GET /eois/1
# GET /eois/1.json
def show
end
# GET /eois/new
def new
@project = Project.find(params[:project_id])
@eoi = @project.eois.build
@contribute = params[:contribute] || false
@participate = params[:participate] || false
@partner = params[:partner] || false
@grant = params[:grant] || false
@invest = params[:invest] || false
end
# GET /eois/1/edit
def edit
end
# POST /eois
# POST /eois.json
def create
@eoi = Project.find(params[:project_id]).eois.build(eoi_params)
@eoi.user_id = @current_user.id
respond_to do |format|
if @eoi.save
format.html { redirect_to Project.find(params[:project_id]), notice: 'Eoi was successfully created.' }
format.json { render :show, status: :created, location: @project }
else
format.html { render :new }
format.json { render json: @eoi.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /eois/1
# PATCH/PUT /eois/1.json
def update
respond_to do |format|
if @eoi.update(eoi_params)
format.html { redirect_to @project, notice: 'Eoi was successfully updated.' }
format.json { render :show, status: :ok, location: @eoi }
else
format.html { render :edit }
format.json { render json: @eoi.errors, status: :unprocessable_entity }
end
end
end
# DELETE /eois/1
# DELETE /eois/1.json
def destroy
@eoi.destroy
respond_to do |format|
format.html { redirect_to @project, notice: 'Eoi was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# def load_parent
# # @parent = (params[:project_id] ? Project.find(params[:project_id] : current_user)
# @parent = params[:project_id] ? Project.find(params[:project_id]) : current_user
# end
# def load_eoi
# @eoi = Eoi.find(params[:id])
# # authorize @eoi
# end
# # Use callbacks to share common setup or constraints between actions.
def set_eoi
@eoi = Eoi.find(params[:id])
end
def get_project
@project = Project.find(params[:project_id])
end
Eoi 政策
def initialize(user, scope)
@user = user
@scope = scope
end
def resolve
if scope.joins(project: :profile).where profiles: { user_id: user }
Eoi.where(project_id: scope.ids)
elsif scope.joins(eoi: :user).where eois: { user_id: user }
Eoi.where(user_id: scope.ids)
else
Eoi.none
end
# since we send the scoped eois from controller, we can pick
# any eoi and get its project id
# check if the current user is the owner of the project
# if (user.profile.projects.map(&:id).include?(project_id))
# # user is the owner of the project, get all the eois
# scope.all
# end
# #not the owner , then get only the eois created by the user
# scope.where(user_id: user.id)
# end
# if scope.is_a?(User)
# Eoi.where(user_id: scope.id)
# elsif scope.is_a?(Project) && (user.profile.projects.map(&:id).include?(project_id))
# project_id = scope.first.project_id
# Eoi.where(project_id: scope.id)
# else
# Eoi.none
# end
end
end
def index?
true
# record.is_a?(User) || user.profile.project.id == record.project_id
end
def new?
true
end
def show?
true
# record.user_id == user.id || user.profile.project_id == record.project_id
end
def edit?
user.id == eoi.user.id?
end
def create?
true
end
def update?
user.id == eoi.user.id?
end
def destroy?
user.id == eoi.user.id?
end
end
路线和景色与上面的尝试相同
The routes and views are the same as the attempt above
这里的问题是我的控制器中的 get 项目方法.对于我试图在特定项目中显示所有 eois 的场景,我需要它.当我试图显示用户的所有 eois 时,我不需要它.
The problem here is with the get project method in my controller. I need that for the scenario where Im trying to show all the eois on a specific project. I don't need it when I'm trying to show all of a user's eois.
当我保存所有这些并尝试它时,项目上的 eois 显示正确.然而,应该向我展示我所有(作为用户)eois 的 eois(未嵌套在项目中)显示一个错误:
When I save all this and try it, the eois on a project show correctly. However the eois (not nested inside a project) that are supposed to show me all of my (as a user) eois, shows an error that says:
Couldn't find Project with 'id'=
错误消息突出显示了get_project 方法".
The error message highlights the 'get_project method'.
LEITO 的更新建议
根据 Leito 的更新建议,我已经列出了当前的尝试.
Taking Leito's updated suggestion, I have set out the current attempt.
在此之前,我想澄清一下,所有 Eois 都将同时拥有用户 ID 和项目 ID.我用这张表让用户表达对项目的兴趣.我的目标是让其个人资料拥有该项目的用户查看该项目上提交的所有 eois.然后,我还希望用户看到他们自己提交的所有 eois(跨所有项目).
Before doing so, I want to clarify that all Eois will have both a user id and a project id. I use this table for users to express interest in projects. My objective is to have the user whose profile owns the project to see all eois submitted on that project. Then, I also want users to see all of their own eois submitted (across all projects).
Eoi 政策
def resolve
if scope.joins(project: :profile).where 'profiles.user_id = ? OR eois.user_id = ?', user.id, user.id
Eoi.all
else
Eoi.none
end
Eoi 控制器
def index
@eois = policy_scope(Eoi)
@eois = @eois.where(project_id: params[:project_id]) if params[:project_id]
end
目前,这在查找嵌套在项目 (project/26/eois) 下的 eois 方面效果很好.但是,当我尝试执行 eois/index(未嵌套在项目下)时,我想返回所有用户的 eois,我收到一条错误消息:
Currently this works fine in finding the eois that are nested under a project (project/26/eois). However, when I try to do eois/index (not nested under project), which I want to return all the user's eois, I get an error that says:
Couldn't find Project with 'id'=
它突出显示了 eoi 控制器的这一行:
It highlights this line of the eoi controller:
def get_project
@project = Project.find(params[:project_id])
end
我不确定我现在是否理解解析方法或控制器剔除的想法.我看不到范围线有什么问题,无法尝试更改什么.
I'm not sure I understand the resolve method or the controller culling idea now. I can't see what's wrong with the scope line to see what to try changing.
推荐答案
我是该问题的前一位评论者.
I'm the previous commenter on that issue.
对于您的 EoiScope,您只需要用户有权访问的 Eois(因为它们属于此配置文件下的项目),独立于项目(此要求仅适用于控制器,因为是嵌套的),因此您的控制器应该看起来像这样:
For your EoiScope, you simply want what Eois the user has access to (because they belong to projects under this profile), independent from the project (this requirement is only for the controller, because is nested), so your controller should look something like this:
编辑:根据您最近的尝试,我更新了范围以说明 Eois 直接属于用户(而不是通过项目),您应该将其范围简单地限定为一个项目或不基于 params[:project_id] 的存在,请参阅更新的答案.
Edit: Based on your latest attempt, I've updated the scope to account for Eois belonging directly to the user (not through a project) and you should simply scope it to a project or not based on the presence of params[:project_id], see updated answer.
@eois = policy_scope(Eoi)
@eois = @eios.where(project_id: params[:project_id]) if params[:project_id]
并且您的范围应该进行连接,直到它到达用户或只是在 Eoi 上查找 user_id 属性.
And your scope should do joins until it reaches user or simply look for the user_id property on Eoi.
class EoiPolicy < ApplicationPolicy
class Scope < Scope
def resolve
scope.joins(project: : profile).where 'profiles.user_id = ? OR eois.user_id = ?', user.id, user.id
end
end
# Other methods that differ from ApplicationPolicy's methods
end
请注意,Scope 不会调用 eoi
,但默认*范围只知道 scope
和 user
.* 默认情况下,我的意思是当它从 ApplicationPolicy::Scope
Please note, Scope isn't calling eoi
, but default* scope only knows about scope
and user
. * By default, I mean when it inherits from ApplicationPolicy::Scope
这篇关于Rails 4 - Pundit - 索引范围策略的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!