2

我正在尝试使用 cancan 修改 spree 的管理/订单站点。在我的商店,产品从不同的供应商处出售。注册用户有一个vendor_id,产品也有一个vendor_id。下订单时,LineItem订单中的 a 有 a Product,因此它有 a vendor_id

我想要实现的是,当用户登录并访问管理面板中的订单页面时,他只能看到从他那里订购产品的订单。用户不应看到来自其他供应商/用户的其他订单。

我尝试通过设置一些功能来使用 CanCan 来做到这一点:

  def initialize(user)
    if user.has_spree_role?("shop_manager") && !user.vendor.nil?
      can :admin, Spree::Order
      can :index, Spree::Order, :line_items => { :product => { :vendor_id => user.vendor_id } }
      can :show, Spree::Order, :line_items => { :product => { :vendor_id => user.vendor_id } }
      can :manage, Spree::LineItem, :product => { :vendor_id => user.vendor_id }
      can :read, Spree::Order
    end
  end

如您所见,用户应该只在索引页面查看订单 where:line_items => { :product => { :vendor_id => user.vendor_id } }并且应该只查看LineItemswhere :product => { :vendor_id => user.vendor_id }

但是我得到的行为是,我无权查看订单的索引页面,并且每个LineItem都显示在订单的显示操作中。

对于第二个任务,我认为修改视图是个好主意。我试图从 spree 核心更改并更改所有显示_order_details.html.erb的循环:LineItems

<% @order.line_items.accessible_by(@current_ability).each do |item| %>

但这给了我一个Uninitialized constant Product(我认为应该是Spree::Product)。所以,我不知道该怎么做,无论是索引还是带有LineItems. 希望有人有想法。

4

2 回答 2

1

Why you set restriction for :read, :show and :index at the same time?

:read assumes :index and :show and any aliased methods.

Then, if you pass associated conditions, you have to :join or :include it.

def initialize(user)
  if user.has_spree_role?("shop_manager") && !user.vendor.nil?
    can :admin, Spree::Order
    can :read, Spree::Order, Spree::Order.includes(:line_items).where(:line_items => { :product => { :vendor_id => user.vendor_id } })
    can :manage, Spree::LineItem, Spree::LineItem.includes(:product).where(:product => { :vendor_id => user.vendor_id })
  end
end

For the second issue, try it again, but it will be much better if you collect records anywhere BEFORE ActionView runtime, in controller. It will be much much faster anyway.

Update:

def initialize(user)
  if user.has_spree_role?("shop_manager") && !user.vendor.nil?
    can :admin, Spree::Order
    can :read, Spree::Order, Spree::Order.includes(:line_items).where(:line_items => { :product => { :vendor_id => user.vendor_id } }) do |order|
      order.line_items.includes(:product).exists?(:vendor_id => user.vendor_id)
    end
    can :manage, Spree::LineItem, Spree::LineItem.includes(:product).where(:product => { :vendor_id => user.vendor_id })
  end
end

What pass the block. When you define :read, the first AR::Relation statement filters the :index (listing), and the block clause filters the :show and give you ability to user can? and cannot?.

于 2012-12-12T19:40:21.593 回答
1

要解决Uninitialized constant Product issue,您需要在过滤器中或之前添加:class选项:load_resourceload_and_authorized_resource

https://github.com/ryanb/cancan/wiki/authorizing-controller-actions

于 2014-02-04T19:30:17.887 回答