问题
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.
回答1:
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 :)
来源:https://stackoverflow.com/questions/39382294/rails-4-pundit-scopes-getting-started