ruby Rails 7 - pundit的作用域有很多

3j86kqsm  于 2023-04-20  发布在  Ruby
关注(0)|答案(1)|浏览(91)

我最近开始在我的Rails应用程序中使用Pundit gem进行授权。在我的应用程序中,我有Company的模型,每个Company可以有多个Employees,这是通过一个has many through关系完成的:

# company.rb
has_many :employees, dependent: :destroy
has_many :users, through: :employees

# employee.rb
belongs_to :company

# user ...

Employees既可以发布,也可以不发布。在我列出公司员工的视图中,我只想为普通用户显示published员工,但给定公司的其他员工应该看到该公司的所有员工。
在我的employees_controller#index中,我有一个解决方案,目前看起来像这样:

def index
  @employees = if current_user.is_employee?(@company)
                 @company.employees.all
               else
                 @company.employees.select { |employee|   employee.published == true }
               end
end

这是可行的,但我试图了解如何利用Pundit的作用域来实现同样的目标。
Pundit Scope的伪代码(这显然不起作用,但给出了我想要实现的示例):

# EmployeePolicy
class Scope
  def initialize(user, scope)
    @user = user
    @scope = scope
  end

  def resolve
    if user.is_employee?(...) # can't get company from scope
      scope.all
    else
      scope.where(published: true)
    end
  end
end

我已经看到了一些使用连接来实现这一点的例子,但这似乎有点麻烦,有没有其他推荐的方法来实现这一点使用Pundit?

nzkunb0c

nzkunb0c1#

# app/models/user.rb
class User < ApplicationRecord
  has_many :employees, dependent: :destroy
  has_many :companies, through: :employees
end

# app/models/employee.rb
class Employee < ApplicationRecord
  belongs_to :company
  belongs_to :user
end

# app/models/company.rb
class Company < ApplicationRecord
  has_many :employees, dependent: :destroy
  has_many :users, through: :employees
end
Company.create!(name: "one", users: [User.new, User.new])
Company.create!(name: "two", users: [User.new, User.new])
Employee.find(3).update(published: true)

>> Employee.all.as_json
=> [{"id"=>1, "published"=>nil,  "company_id"=>1, "user_id"=>1},
    {"id"=>2, "published"=>nil,  "company_id"=>1, "user_id"=>2},
    {"id"=>3, "published"=>true, "company_id"=>2, "user_id"=>3},
    {"id"=>4, "published"=>nil,  "company_id"=>2, "user_id"=>4}]
# app/policies/employee_policy.rb

class EmployeePolicy < ApplicationPolicy
  class Scope < Scope
    def resolve
      scope.where(company: user.company_ids).or(
        scope.where(published: true)
      )
    end
  end
end

用户#1可以看到公司#1的每个员工,只能看到公司#2的published

>> Pundit.policy_scope(User.first, Employee).as_json
=> [{"id"=>1, "published"=>nil,  "company_id"=>1, "user_id"=>1},
    {"id"=>2, "published"=>nil,  "company_id"=>1, "user_id"=>2},
    {"id"=>3, "published"=>true, "company_id"=>2, "user_id"=>3}]

来自公司#2的用户看不到其他公司员工:

>> Pundit.policy_scope(User.third, Employee).as_json
=> [{"id"=>3, "published"=>true, "company_id"=>2, "user_id"=>3},
    {"id"=>4, "published"=>nil,  "company_id"=>2, "user_id"=>4}]

与授权无关的作用域应在控制器中应用:

>> employee_scope = Pundit.policy_scope(User.first, Employee)

>> employee_scope.where(company: Company.first).as_json
=> [{"id"=>1, "published"=>nil, "company_id"=>1, "user_id"=>1},
    {"id"=>2, "published"=>nil, "company_id"=>1, "user_id"=>2}]

# user #1 authorization to see their own company employees didn't change
# just currently looking at the other company
>> employee_scope.where(company: Company.second).as_json
=> [{"id"=>3, "published"=>true, "company_id"=>2, "user_id"=>3}]

相关问题