ade*_*rey 0 ruby ruby-on-rails pundit
我使用 pundit 来处理我的 API 策略,我有一个项目显示,在某些情况下可以禁止用户,而在其他情况下只是受到限制。我所说的受限是指现在被禁止,但如果他付费,他就可以访问它。因此,我需要我的 API 使用特定代码 ( 402 Payment Required) 进行响应,以便客户端可以邀请用户付款以解锁节目。
403这是我当前的代码,它仅在 pundit 返回 false 时做出响应。
为了保持干燥和干净,最好在哪里实现返回403OR 的条件?402
class Api::V1::ItemController < Api::V1::BaseController
def show
@item = Item.find(params[:id])
authorize @item
end
end
class ItemPolicy < ApplicationPolicy
def show?
return true if record.public?
# 403 will be generated, that's ok.
return false if !record.band.members.include?(user)
# If that condition is false I want to generate a 402 error at the end, not a 403.
user.premium?
end
end
class Api::V1::BaseController < ActionController::API
include Pundit
rescue_from Pundit::NotAuthorizedError, with: :user_not_authorized
def user_not_authorized(_exception)
# Here I've got the exception with :policy, :record and :query,
# also I can access :current_user so I could go for a condition,
# but that would include duplicated code from ItemPolicy#show?.
render json: { error: { message: "Access denied" } }, status: :forbidden
end
end
Run Code Online (Sandbox Code Playgroud)
不幸的是,Pundit无法立即处理不同的错误类型。它的构建总是期望策略的方法返回true或 false false。因此,引发另一个自定义错误并从控制器中拯救该错误将不起作用,因为它也会破坏视图方法。
我建议一种解决方法来引入不同的错误类型。像这样的事情可能会起作用:
# in the policy
class ItemPolicy < ApplicationPolicy
def show?
return true if record.public?
return false unless record.band.members.include?(user)
if user.premium?
true
else
Current.specific_response_error_code = :payment_required
false
end
end
end
# in the controller
class Api::V1::BaseController < ActionController::API
include Pundit
rescue_from Pundit::NotAuthorizedError, with: :user_not_authorized
def user_not_authorized(_exception)
case Current.specific_response_error_code
when :payment_required
render json: { error: { message: "Premium required" } }, status: :payment_required
else
render json: { error: { message: "Access denied" } }, status: :forbidden
end
end
end
Run Code Online (Sandbox Code Playgroud)
我不认为使用全局是CurrentAttributes一个好的实践,但它们是 Rails 的一部分,在这种情况下,使用这个全局数据存储可以避免覆盖专家内部结构。
您可能想阅读有关CurrentAttributes.