Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Pundit policies with two input parameters

I'm pretty new with Rails and I have a problem with the following policies (using Pundit): I'd like to compare two objects: @record and @foo, as you can see here:

class BarPolicy < ApplicationPolicy
  def show?
    @record.foo_id == @foo
  end
end

I don't reach to find a good way to pass a second parameter to pundit methods (@foo).

I'd like to do something like:

class BarsController < ApplicationController
  def test
    authorize bar, @foo, :show? # Throws ArgumentError
    ...
  end
end

But the Pundit authorize method allows only two parameters. Is there a way to solve this issue?

Thanks!

like image 348
Rowandish Avatar asked Jan 29 '15 14:01

Rowandish


2 Answers

Relying on more than the current user and a domain model is a code smell, but in case it really is required, then you can use a custom query method with any number of parameters and raise an exception if the requirements don't met:

class BarPolicy < ApplicationPolicy
  def authorize_test?(foo)
    raise Pundit::NotAuthorizedError, "not authorized to test" unless record.foo_id == foo
  end
end

class BarsController < ApplicationController
  def test
    skip_authorization && BarPolicy.new(current_user, @record).authorize_test?(@foo)
    ...
  end
end

The skip_authorization && part is not required if after_action :verify_authorized is not used, I just wanted to show a one-liner that can be used in this case to get rid of the not-authorized exception while still having the requirement to authorize the action.

like image 114
István Ujj-Mészáros Avatar answered Sep 19 '22 01:09

István Ujj-Mészáros


I found the answer at here.

Here is my way:

Add a pundit_user function in ApplicationController:

class ApplicationController < ActionController::Base
include Pundit
def pundit_user
    CurrentContext.new(current_user, foo)
end

Create the CurrentContext class:

/lib/pundit/current_context.rb
class CurrentContext
  attr_reader :user, :foo

  def initialize(user, foo)
    @user = user
    @foo = foo
  end
end

Update the initialize Pundit method.

class ApplicationPolicy
  attr_reader :user, :record, :foo

  def initialize(context, record)
    @user = context.user
    @foo = context.foo
    @record = record
  end
end
like image 32
Rowandish Avatar answered Sep 19 '22 01:09

Rowandish