如何使用Pundit限制对用户资源索引操作的授权?我认为答案不是范围

时间:2016-12-08 18:44:22

标签: ruby-on-rails nested authorization ruby-on-rails-5 pundit

在使用Pundit时,我正在努力获得嵌套资源的索引操作的授权。 Pundit是如此光滑,可能很容易,我不想把它抛到一边,因为我无法解决这个问题。我想,一旦我理解了这一部分,其他一切都会内联。我已经阅读了很多人的帖子,询问与我提出的问题非常相似的问题,似乎最接近我问的问题的帖子永远不会得到解决。所以,我还在寻找答案。

class User < ApplicationRecord
  enum role: [:user, :admin]
  after_initialization :set_default_role, :if => :new_record?
  def set_default_role
  self.role ||= :user
  has_many :galleries, dependent: :destroy
end

class Gallery < ApplicationRecord
  belongs_to :user
  validates :user_id, presence: true
  validates :title,, presence: true
end

我让用户通过UserPolicy设置我想要的方式。它不会从ApplicationPolicy继承,因为我看到的教程说我不需要它。

我的路线看起来像这样:

devise_for :users, path: 'accounts
resources :users, shallow: true do
  resources :galleries
end

基本上我不希望一个用户看到另一个用户的东西,即索引,显示......动作。我相信这被称为封闭系统。我查看用户图库(我的嵌套资源)索引的路径如下所示:

localhost:/users/20/galleries

我不希望用户19看到用户20在其图库索引中有什么。我该怎么做?

这就是我的GalleryController的样子:

before_action :authenticate_user! #I'm using devise
def index
  @galleries = current_user.galleries.all
  #authorize ????? <<part of what I don't understand
end

private
def gallery_params
  params.require(:gallery).permit(:title)
end

我真的不知道我应该在GalleryPolicy中为索引做什么。我已经完成了show动作,因为它只是根据用户id的实例检查库的实例。这是GalleryPolicy

attr_reader :user, :model

def initialize(user, model)
  @user = user
  @gallery = gallery
end

def show?
  @gallery.user_id == user.id
end

def index?
  # I can't figure it out
end

def new?
  #actually this is confusing too
end

1 个答案:

答案 0 :(得分:1)

首先,我总是编写继承自ApplicationPolicy的Pundit策略,所以让我们从那里开始。 ApplicationPolicy使用用户和记录进行初始化。该记录将是您希望用户有权查看的模型。在这种情况下,一个画廊。

其次,每项政策都应包括范围。这也是在ApplicationPolicy中初始化的,但是你的工作是根据需要限制范围。

class GalleryPolicy < ApplicationPolicy
  class Scope < Scope
    def resolve
      scope.where(:user_id => user.id)
    end
  end

  # no need for an index? method here. we will see this in the controller

  # essentially here we are checking that the user associated to the record
  # is the same as the current user
  def show?
    record.user == user
  end

  # this is actually already the case in ApplicationPolicy but I added 
  # it here for clarity
  def new?
    create? 
  end

  # who do we want to be able to create a gallery? anyone!
  # so this simple returns true
  def create?
    true
  end
end

然后在GalleryController中,您每次都会授权模型。正如我们现在所看到的那样,只有索引动作有点不同:

# controllers/gallery_controller.rb
def index 
 @galleries = policy_scope(Gallery)
 # as we specified the scope in GalleryPolicy to only include galleries which belong 
 # to the current user this is all we need here!
end

# your other actions will look something like this:
def show
  @gallery = Gallery.find(params[:gallery_id]
  authorize @gallery
end

def new
  @gallery = Gallery.new # or @gallery = current_user.galleries.build
  authorize @gallery
end

[...]

我希望这有帮助!一旦你掌握它,Pundit就是一个非常好的工具。