1

I am really struggling in my efforts over the past 2+ years to try to learn how to use pundit.

I am trying to write scoped policies, so that different users can receive objects based on the scope class that they fit into.

I have asked several questions on the same topic previously, but I'm not getting any closer to a solution. My recent questions are: here, here, here, here, here and here.

There are several others but these give the general picture, that I am struggling with the fundamentals of how to get started.

I have a million problems with getting started and realise that after 4 years of trying (every day - 10+ hours), I'm not really getting far in my attempts to learn to code, BUT the current problem Im facing is with this error:

wrong number of arguments (given 2, expected 0)

It points to wherever I put the authorize @eoi line in my controller. I previously asked about this error here

I was originally putting in the set_eoi method as follows:

 def set_eoi
      @eoi = Eoi.find(params[:id])
      authorize @eoi
    end

I was using that method in a before action in the controller:

before_action :set_eoi, only: [:show, :edit, :update, :destroy]

I stopped doing that when I found the answer to this post, which says not to use authorize in a before action (even though the Go Rails video tutorial on pundit shows to do this).

Then, I moved the authorize call to the show action itself:

  def show
    authorize @eoi
  end

That gives the same error as using it in the before action.

Please, can someone help with getting started. My current setup is as follows:

Objective

User's have profiles. Those profiles own projects they create. Other user's can express interest in joining a project owned by another user. The user who creates the project should be able to see all of the eois submitted on their own project. A user who submits an eoi on a project, should see their own eoi only, when viewing a project page. Also, every user can see an index of their own eois (doesnt matter which project they submitted the eoi on).

The approach I currently took is to make two policies for the same controller (although I think maybe this issue resolves that this is not a good approach to take).

I have models for User, Profile. Project and Eoi. The associations are:

class User < ActiveRecord::Base
  has_one :profile
  has_many :eois
end

class Profile < ActiveRecord::Base
  belongs_to :user
  has_many :projects, dependent: :destroy
end

class Project < ActiveRecord::Base
  belongs_to :profile
  has_many :eois
end

class Eoi < ActiveRecord::Base
  belongs_to :project
  belongs_to :user
end

My routes file has:

resources :eois#, only: [:index]
  concern :eoiable do
    resources :eois
  end

resources :projects do
    member do
  concerns :eoiable
end

I have an Eoi Policy and a Project Eoi Policy, as follows:

class EoiPolicy < ApplicationPolicy

  class Scope

    # def initialize(user, scope)
    #   @user  = user
    #   @scope = scope
    # end

    def resolve
      # selects all the EOI's for a given user
      @scope.where(user_id: @user.id)
    end

  end

  def index?
    true
  end

  def new?
    true
  end

  def show?
#     record.user_id == user.id || user.profile.project_id == record.project_id
    true
  end

  def edit?
    user.id == eoi.user.id?
  end

  def create?
    true
  end

  def update?
    user.id == eoi.user.id?
  end

  def destroy?
    user.id == eoi.user.id?
  end


end


class ProjectEoiPolicy < ApplicationPolicy
  class Scope < Scope
    def resolve(project_id)
      project = Project.find(project_id)
      if project.owner?(@user)
        # if the user is the owner of the project, then get
        # all the eois
        project.eois
      else
        # select all the eois for the project
        # created by this user
        Eoi.for_user(@user.id).for_project(project_id)
      end
    end
  end

end

My eois controller has:

class EoisController < ApplicationController
  before_action :get_project, except: [:index, :show]
  before_action :set_eoi, only: [:show, :edit, :update, :destroy]
  # before_action :load_parent
  # before_action :load_eoi, only: [:show, :edit, :update, :destroy]


  def index
    if params[:project_id]
      @eois = ProjectEoiPolicy::Scope.new(current_user, Eoi).resolve(params[:project_id])
    else
      @eois = policy_scope(Eoi)
    end
  end


  # GET /eois/1
  # GET /eois/1.json
  def show
    authorize @eoi
  end

My application policy has:

class ApplicationPolicy
  attr_reader :user,  :scope

  class Scope
    def initialize(user, scope)
      #byebug        
      @user = user
      # record = record
      @scope = scope
    end

    def resolve
      scope
    end
  end

  def index?
    false
  end

  def show?
    scope.where(:id => record.id).exists?
  end

  def create?
    false
  end

  def new?
    create?
  end

  def update?
    false
  end

  def edit?
    update?
  end

  def destroy?
    false
  end

  def scope
    Pundit.policy_scope!(user, record.class)
  end

When I save all of this and try it, I can render all of the indexes correctly (although I can't when I add authorize @eois to the index action in the eois controller.

I can't get the show page to render. Instead I get an error that says:

ArgumentError at /projects/26/eois/24
wrong number of arguments (given 2, expected 0)

I don't know what this error message means. I am only giving one argument to the authorize method in the show action of the eoi controller - so its strange to me that this error thinks I have given 2.

I already saw this post, where a user seems to have the same error message as me, although the answer in that post highlights some errors in that user's setup that I don't have myself.

Can anyone see where I'm going wrong? To my mind, the index only works because I haven't tried to add authorize @eois to it. The scopes are right for the index purposes. The show action doesnt work at all when I try to authorize it.

Community
  • 1
  • 1
Mel
  • 2,481
  • 26
  • 113
  • 273

1 Answers1

0

ok, on the Pundit docs: https://github.com/elabs/pundit

the example seems to suggest that the Policy Scope need to inherit from applicationPolicy's scope:

class PostPolicy < ApplicationPolicy
  class Scope < Scope

so my guess is that you should try this:

class EoiPolicy < ApplicationPolicy
  class Scope < Scope # this is the changed line of code

Likewise, the application policy you have has the attr_readers outside of the Scope where the pundit examples have them inside eg:

class ApplicationPolicy
  # should not be here
  # attr_reader :user,  :scope

  class Scope
    # should be here instead
    attr_reader :user,  :scope

which might get you past the issue where you're deep-diving into the @-var here when you should just need the reader:

def resolve
  # selects all the EOI's for a given user
  # should not use `@scope`
  # @scope.where(user_id: @user.id)
  # instead use `scope` which is the reader
  scope.where(user_id: @user.id)
end

Regardless of whether this fixes your bug... you probably need to do these things :)

Taryn East
  • 27,486
  • 9
  • 86
  • 108
  • I tried adding < Scope to the eoi policy, but it still gives the same error. I actually tried removing those words to match the example in this part of the pundit docs: github.com/elabs/pundit#scopes - whether I have that inheritance or not, I still get the same error. – Mel Sep 08 '16 at 05:50
  • darn... worth a try, but I'm sad it didn't help. My guess was that it wasn't using the `initialize` that it should be. – Taryn East Sep 08 '16 at 05:52
  • Thanks anyway. I'll try to learn more about the initialize function next. Thanks for the help. – Mel Sep 08 '16 at 05:54
  • Ok, just doing a compare-and-contrast against the examples on the pundit page... you should move the attr_reader line inside the `class Scope` definition. You should use `scope` not `@scope` (except in the `initialize` method). I'll update the example above to match that – Taryn East Sep 08 '16 at 05:59
  • Thanks. I tried all of these things. I've been toggling between scope and @scope in trying to get these working. They both seem to work, although I understand why its a good correction to use scope instead of 'a' scope. I've also been toggling the attr_reader line. I moved it inside the application scope method. I still get the error but I'll keep looking for clues. Thanks again – Mel Sep 08 '16 at 06:42
  • Ok, so this probably sounds daft but... have you tried uninstalling and reinstalling the gem? If you aren't the only person with a problem, it could have been a bug with the gem that could plausibly now be solved (it's a long shot, but given how much effort you've gone to, worth a shot?) – Taryn East Sep 08 '16 at 23:55