0

How would I provide pundit authorization for a dashboard controller which provides data from various models?

My DashboardsController looks like this:

class DashboardsController < ApplicationController
  before_action :authenticate_user!
  before_action :set_user
  before_action :set_business
  after_action :verify_authorized

  def index

  end


  private

  def set_user
    @user = current_user
  end
  def set_business
    @business = current_user.business
  end


end

How would I authorize for both @user and @business within my DashboardsPolicy?

Rich
  • 590
  • 7
  • 20

2 Answers2

0

Pundit expects a current user and a model object to be passed to it. In this case I think what you would want is a DashboardsPolicy class, and you would authorize it like:

  def index
    authorize(@business)
  end

From the README:

Pundit will call the current_user method to retrieve what to send into this argument

The authorize method automatically infers that Post will have a matching PostPolicy class, and instantiates this class, handing in the current user and the given record

There is also a specific section in the README regarding headless policies that uses the Dashboard as the example action: https://github.com/varvet/pundit#headless-policies

You can also create a plain ruby object that takes two entities and use that as your object to authorize:

class UserBusiness
  def initialize(user, business)
  end

  ...other methods here
end

@model = UserBusiness.new(user, business)
authorize(@model)
Jed Schneider
  • 14,085
  • 4
  • 35
  • 46
  • Hey Jed, If I created a plain ruby object, that would be a Model, no? If I created that model (not an AR model, just a plain ruby object), how would I get my Policy to reference that object? More plainly, how would I implement your instructions? Thanks for the help! – Rich Mar 16 '18 at 14:55
  • Hi @Rich, Pundit doesn't care if your model is backed by ActiveRecord or not. one of the reasons to choose it is that it isn't opinionated on that front. All your "model" object needs to be able to do is be able to be queried against the object to make a policy decision. It is up to you to decide what those business rules are regarding the permissibility of the action. I think you're over thinking it. – Jed Schneider Mar 16 '18 at 15:41
0

I would argue that trying to get access to a dashboard is not a policy based on a resource named dashboard, but simply a special method in the business policy.

Therefore, I would add this to the BusinessPolicy as a method dashboard.

# in your controller
authorize @business, :dashboard?

# and the business_policy
class BusinessPolicy < ApplicationPolicy
  def dashboard?
    # condition depending on a `user` (current_user) and a record (business)
    user.admin? || user.business == record
  end
end

Or it might be even simpler. If someone is allowed to see the dashboard when she is allowed to show the business, then just re-use BusinessPolicy#show? in your controller:

authorize @business, show?
spickermann
  • 100,941
  • 9
  • 101
  • 131
  • In my DashboardController, how would I get the Pundit to use the BusinessPolicy? I agree that simply trying to get access to the dashboard is not a policy based on a resource. – Rich Mar 16 '18 at 14:44
  • @Rich Pundit magic! This is just the default behavior of the `authorize` method. The `authorize` method automatically infers that `@busniess` (which is an instance of `Business`) will have a matching BusinessPolicy class, and instantiates this class, handing in the current user and the given `@business` record. – spickermann Mar 16 '18 at 16:44