首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用Pundit的多租户作用域

使用Pundit的多租户作用域
EN

Stack Overflow用户
提问于 2015-06-23 06:11:04
回答 1查看 459关注 0票数 2

我使用Pundit进行授权,并希望利用它的作用域机制实现多租户(由主机名驱动)。

到目前为止,我一直在手动执行此操作,其原因如下:

代码语言:javascript
复制
class ApplicationController < ActionController::Base
  # Returns a single Client record
  def current_client
    @current_client ||= Client.by_host(request.host)
  end
end

然后在我的控制器中做像这样的事情:

代码语言:javascript
复制
class PostsController < ApplicationController
  def index
    @posts = current_client.posts
  end
end

相当标准的票价,真的。

我喜欢Pundit的verify_policy_scoped过滤器的简单性,它可以确保每个操作的作用域都正确的Client。对我来说,如果作用域还没有正式执行,那么它真的值得500错误。

给定权威人士的策略范围:

代码语言:javascript
复制
class PostPolicy < ApplicationPolicy
  class Scope < Scope
    def resolve
      # have access to #scope => Post class
      # have access to #user => User object or nil
    end
  end
end

现在,Pundit似乎想让我按用户过滤Post,例如:

代码语言:javascript
复制
def resolve
  scope.where(user_id: user.id)
end

然而,在这个场景中,我实际上希望将current_client.posts作为默认情况进行过滤。我不确定在这种情况下如何使用专家作用域,但我的感觉是它需要看起来像这样:

代码语言:javascript
复制
def resolve
  current_client.posts
end

current_client自然不会出现在权威人士的范围内。

一种解决方案是将current_client.posts传递给policy_scope

代码语言:javascript
复制
def index
  @posts = policy_scope(current_client.posts)
end

但我觉得这分散了我的租约范围,破坏了使用专家完成这项任务的目的。

有什么想法吗?或者,我是不是超出了它的设计目标?

EN

回答 1

Stack Overflow用户

发布于 2015-08-06 09:45:47

处理这个问题最“权威”的方法是在你的Post模型中创建一个作用域:

代码语言:javascript
复制
Class Post < ActiveRecord::Base
  scope :from_user, -> (user) do
    user.posts
  end
end

然后,您将能够在您的策略中使用它,其中user由来自您的控制器的current_user填充:

代码语言:javascript
复制
class PostPolicy < ApplicationPolicy
  class Scope
    attr_reader :user, :scope

    def initialize(user, scope)
      @user = user
      @scope = scope
    end

    def resolve
      scope.from_user(user)
    end
  end
end

如果要从作用域返回ActiveRecord::Relation,则可以从此处停止读取。

如果您的作用域返回一个数组

默认ApplicationPolicy使用wheresource实现方法show

因此,如果您的作用域不返回AR::Relation而是数组,一种解决方法可能是覆盖此show方法:

代码语言:javascript
复制
class PostPolicy < ApplicationPolicy
  class Scope
    # same content than above
  end

  def show?
    post = scope.find do |post_in_scope|
      post_in_scope.id == post.id
    end
    post.present?
  end
end

无论您的实现是什么,您只需要以“专家方式”从您的控制器使用PostPolicy

代码语言:javascript
复制
class PostsController < ApplicationController
  def index
    @posts = policy_scope(Post)
  end

  def show
    @post = Post.find(params[:id])
    authorize @post
  end
end
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/30990700

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档