【问题标题】:CanCanCan show only instance of model that user belongs toCanCanCan 仅显示用户所属的模型实例
【发布时间】:2023-03-20 09:40:01
【问题描述】:

我目前正在使用 Devise、CanCan 和 Rolify 来处理我的 rails 应用程序的身份验证和授权,但我很难理解如何做到这一点,以便 user只能:show:update 用户 所属的模型的特定实例(也就是我的user 有一个client_id 列,而不是相反)。

我为具有:client 角色的user 定义的Abilities.rb 的更新部分工作正常,即如果current_user.client_id = 3 那么他只能更新Client.id = 3 的客户端,但是,同一用户可以查看Client 模型的任何实例,我似乎无法掌握如何限制这一点。

Ability.rb

...
if user.has_role? :client
  can [:read, :update], [Property, Order], client_id: user.client_id
  can [:read, :update], Owner
  can :create, [Property, Order, Owner]
  can :manage, User, id: user.id
  can [:show, :update], Client, id: user.client_id
end
...

每个用户都没有index,而不是所有Clients,所以在研究后我将can [:read, :update], Client, ..更改为:show,但用户仍然可以看到另一个clients,但:update部分是否有效好吧,所以我在这里真的很茫然。在过去的几个小时里一直在谷歌上搜索并通读所有 CanCan 文档,我承认这些文档可能已解决,但我无法弄清楚。

我已经尝试从控制器端限制它,如下所示,但这也不起作用:

external/clients_controller.rb

class External::ClientsController < ApplicationController
  load_and_authorize_resource
  before_filter :client_only

  def index
    @clients = Client.paginate(page: params[:page], per_page: 15)
  end

  def show
    @clients = Client.find(params[:id])
    @client_users = User.where(client_id: params[:id])
    @client_orders = Order.where(client_id: params[:id]).includes(:property, :owners)
    can? :show, @clients
  end

  def edit
    @clients = Client.find(params[:id])
    respond_to do |format|
      format.html { @clients.save }
      format.js
    end
  end

  def update
    @clients = Client.find(params[:id])
    @clients.update_attributes(client_params)
    respond_to do |format|
      format.html { if @clients.save
                      flash[:success] = "Client Updated Successfully"
                      redirect_to client_path(@clients)
                    else
                      render 'edit'
                    end
      }
      format.js
    end
  end

  private

  def client_params
    params.require(:client).permit(:uuid, :company, :first_name, :last_name, :phone, :email, :address1, :address2, :city, :state, :zip, :notes)
  end

  def client_only
    redirect_to root_path unless current_user.is_client?
  end

end

因此,如果有人可以帮助我完全理解 CanCan 如何为模型实例处理基于角色的授权,那么我将不胜感激。提前致谢!

更新代码

删除了external/clients_controller.rb 中的所有@client 实例加载

class External::ClientsController < ApplicationController
  load_and_authorize_resource
  before_filter :client_only

  def show
    @client_users = User.where(client_id: params[:id])
    @client_orders = Order.where(client_id: params[:id]).includes(:property, :owners).paginate(page: params[:page], per_page: 15).order("order_number DESC")
  end

  def edit
    respond_to do |format|
      format.html
      format.js
    end
  end

  def update
    if params[:client][:state].blank?
      params[:client][:state] = @client.try(:state)
    end
    @client.update_attributes(client_params)
    respond_to do |format|
      format.html { if @client.save
                      flash[:success] = "Client Updated Successfully"
                      redirect_to external_client_path(@client)
                    else
                      render 'edit'
                    end
      }
      format.js
    end
  end

  private

  def client_params
    params.require(:client).permit(:uuid, :company, :first_name, :last_name, :phone, :email, :address1, :address2, :city, :state, :zip, :notes)
  end

  def client_only
    redirect_to root_path unless current_user.is_client?
  end

end

完整的ability.rb

class Ability
  include CanCan::Ability

  def initialize(user)  
    alias_action :show, :to => :view
    alias_action :open_external_orders, :completed_external_orders, :to => :client_order_views

    user ||= User.new
    if user.has_role? :admin
      can :manage, :all
      can :assign_roles, User
    else
      can :read, :all
    end

    if user.has_role? :executive
      can :manage, [Property, Deed, Mortgage, Order, Owner, Client, AttachedAsset, User]
      cannot :assign_roles, User
    end

    if user.has_role? :management
      can :manage, [Property, Deed, Mortgage, Order, Owner, Client, AttachedAsset]
      can :read, User
      can :manage, User, id: user.id
      cannot :destroy, [Property, Order, Client, User]
    end

    if user.has_role? :analyst
      can :manage, [Property, Deed, Mortgage, Order, Owner, Client, AttachedAsset]
      can :manage, User, id: user.id
      cannot :destroy, [Property, Order, Client, User]
    end

    if user.has_role? :it
      can :manage, [Property, Deed, Mortgage, Order, Owner, Client, AttachedAsset]
      can :manage, User, id: user.id
      can :read, User
      cannot :destroy, [Property, Order, Client, User]
    end

    if user.has_role? :client
      can [:read, :update], Client, id: user.client_id
      can [:read, :update, :client_order_views], [Property, Order], client_id: user.client_id
      can [:read, :update], Owner
      can :create, [Property, Order, Owner]
      can :manage, User, id: user.id
    end
  end
end

【问题讨论】:

  • 首先有几件事:方法中的变量@clients 实际上是@client,对吧? (单数,不是复数,请改),第二:这个已经通过load_and_authorize_resource加载了,为什么还要加载呢?您还可以发布其余的能力.rb吗?谢谢
  • 我实际上注意到昨晚浏览文档时,我在实现 CanCan 之前已经构建了大部分控制器等,我想我从未更改过它,但现在已经这样做了。我浏览了我所有的观点并将@clients 更改为@client,并发布了我更新的external/clients_controller.rb 以及我的完整ability.rb。谢谢你帮助我。
  • 您有一条规则,规定用户 can :read, :all 如果不是管理员。这将允许所有非管理员用户阅读所有模型。
  • 哎呀,我想我真的不明白 CanCan,因为我认为对 user.has_role? :client 的调用会覆盖它。感谢您抽出时间成为另一双眼睛。现在一切都按预期工作。如果您想将您的评论变成答案,那么我会为您接受。

标签: ruby-on-rails ruby-on-rails-5 cancan cancancan rolify


【解决方案1】:

CanCanCan 与“增加权限”一起使用。 每条规则都可以增加前一条。

如果你写:

can :show, User
can :edit, User

这两个权限将合并,您将能够显示和编辑用户。

在您的能力.rb 中,您定义了can :read, :all,您授予对所有对象的读取(显示和索引)权限。

我建议你按照“增加权限”的概念来编写你的能力文件。这意味着您无需开始为管理员定义能力,而是在最后这样做,将管理员需要的能力添加到您已经提供给每个人的能力中。

【讨论】:

  • 啊,我喜欢这个主意,我之前半掌握了这个概念,但后来把 can... 然后 cannot.. 但我认为它包含在每个 user.has_role? 块中,所以谢谢你清理它和建议。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-08-07
  • 1970-01-01
  • 1970-01-01
  • 2021-12-28
相关资源
最近更新 更多