Rails 4 - Pundit - 索引范围策略 [英] Rails 4 - Pundit - scoped policy for index

查看:46
本文介绍了Rails 4 - Pundit - 索引范围策略的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试学习如何在我的 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,但默认*范围只知道 scopeuser.* 默认情况下,我的意思是当它从 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆