2016-08-28 2 views
4

Я пытаюсь научиться использовать Pundit с моим Rails 4.Rails 4 - Pundit - политика для индекса

У меня есть следующие модели:

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 

У меня есть область действия EoiPolicy с:

class EoiPolicy < ApplicationPolicy 

    class Scope 
    attr_reader :user, :scope 

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

    def resolve 
     if user.profile.project.id == @eoi.project_id? 
     scope.where(project_id: @user.profile.project.id) 
     elsif user.id == eoi.user_id? 
     scope.where(user_id: user.id) 
     else 
     nil 
     end 
    end 
    end 

    def index? 
    user.profile.project.id == @eoi.project_id? or user.id == eoi.user_id? 
    end 

    def new? 
    true 
    end 

    def show? 
    user.profile.project.id == @eoi.project_id? or user.id == eoi.user_id? 
    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 

В моих EoisController, я пытался использовать сферу с:

def index 
    # @eois = @project.eois 
    @eois = policy_scope(Eoi) 
    # @eois = Eois.find_by_project_id(params[:project_id]) 
end 

Затем в моем view/eois/index я попытался отобразить индекс с помощью:

<% policy_scope(@user.eois).each do |group| %> 

Я не могу заставить это работать. Сообщение об ошибке выделяет эту линию моего метода области действия в политике:

if user.profile.project.id == @eoi.project_id? 

Для меня это выглядит правильно, хотя я все еще пытаюсь понять это. Может ли кто-нибудь увидеть, что должно произойти, чтобы сделать эту работу, так что, если пользователь является пользователем, которому принадлежит профиль, соответствующий проект, все евреи, относящиеся к этому проекту, видны.

В противном случае, если пользователь является пользователем, создавшим eoi, то все созданные ими eois видны?

сообщение об ошибке говорит:

undefined method `project' for #<Profile:0x007fa03f3faf48> 
Did you mean? projects 
       projects= 

мне интересно, если это потому, что индекс будет иметь много записей, он должен показать что-то другое в политике распознавать множество?

Я также попытался заменить эту строку с:

if @eoi.project_id == @user.profile.project.id? 

хотя это тоже неправильно и дает

undefined method `project_id' for nil:NilClass 
Did you mean? object_id 

Я также попытался сделать сферу:

def resolve 
     # cant figure what is wrong with this 
     if eoi.project_id == user.profile.project.id? 
     scope.where(project_id: @user.profile.project.id) 
     else 
     nil 
     end 
    end 

но это также неверно и дает эту ошибку:

undefined local variable or method `eoi' for #<EoiPolicy::Scope:0x007ffb505784f8> 

Я также попытался:

def resolve 
     # cant figure what is wrong with this 

     if @eoi.project_id == user.profile.project.id? or Eoi.project_id == user.profile.project.id? 
     scope.where(project_id: @user.profile.project.id) 
     elsif user.id == eoi.user_id? 
     scope.where(user_id: user.id) 
     else 
     nil 
     end 
    end 
    end 



def index? 
    user.profile.project.id == Eoi.project_id? or user.id == Eoi.user_id? 
    end 

, но эта попытка дает это сообщение об ошибке:

undefined method `project_id' for nil:NilClass 
Did you mean? object_id 

ТОК ПОРАЗМЫСЛИ

Я думаю, что мне нужно передать больше, чем пользователей и объема к методу области. Если я могу также передать проект, я могу сделать область применимой к проекту, к которому относится EoI.

Если бы я мог иметь эту работу, то, возможно, я мог бы получить метод области, чтобы работать на индексном на контроллере:

class Scope 
    attr_reader :user, :scope 

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

затем в контроллере:

def index 
    # @eois = @project.eois 

    @eois = policy_scope(Eoi, @project) 
    # authorize @eois 
    # @eois = Eois.find_by_project_id(params[:project_id]) 
end 

Это оленья кожа работа, когда я пытаюсь получить ошибку, заявив, что политика

wrong number of arguments (given 2, expected 1) 

Пожалуйста, помогите!

СЛЕДУЮЩЕЙ ПОПЫТКА

Моей следующая попытка попробовать принимать предложения от [этого] пандита проблемы и реализовать эту идею, как получить правильный масштаб для конкретного пользователя.

В моей ВЗ политике, я изменил метод постановляет:

class Scope 
    attr_reader :user, :scope 

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

    end 

    def resolve 
     # if Eoi.project_id == user.profile.project.id? or Eoi.project_id == user.profile.project.id? 
     if user.id == eoi.projects.profile.user.map(&:id) 
     scope.joins(eois: :projects).where(project_id: user.profile.projects.map(&:id)).empty? 
     # if scope.eoi.project_id == user.profile.projects.map(&:id) 
     # scope.where(project_id: user.profile.projects.map(&:id)).empty? 
     # scope.where(project_id: user.profile.project.id) 
     # elsif user.id == eoi.user_id? 
     # scope.where(user_id: user.id) 
     else 
     # nil 
     end 
    end 
    end 

Тогда в моем ВЗЕ указательного контроллера действия, я попытался это:

def index 
    # @eois = @project.eois 

    # @eois = policy_scope(Eoi, @project) 
    policy_scope(Eoi).where(project_id: params[:project_id]) 
    # authorize @eois 
    # @eois = Eois.find_by_project_id(params[:project_id]) 
    end 

Это не работает либо. Сообщение об ошибке для этой попытки говорит:

undefined local variable or method `eoi' for #<EoiPolicy::Scope:0x007f98677c9cf8> 

Im из идей для вещей, чтобы попробовать. Может ли кто-нибудь увидеть способ дать правилу правильные входные данные, чтобы настроить это?

НАБЛЮДЕНИЕ Я заметил, что много репозиториев на GitHub, которые используют Pundit с областями, также включают в себя метод, как это:

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

Этот метод в дополнении к классу Scope и ISN» t показано в документах драгоценных камней Pundit. Если это необходимо включить, что он делает? 1

REWRITE

Я теперь просмотрел более 200 сделок РЕПО на GitHub для понимания того, как я должен написать политику для удовлетворения своих целей. У меня нет идей о том, как использовать Pundit по назначению.

Я полностью изменил настройки, чтобы попытаться обойти биты, которые я не могу понять.Теперь у меня есть:

ВЗ Controller

class EoisController < ApplicationController 

    def index 
    @eois = Eoi.by_user_id(current_user.id) 
    end 
end 

Проекты :: ВЗ контроллер

module Projects 
    class EoisController < ApplicationController 
    before_action :get_project 
    before_action :set_eoi, only: [:edit, :update, :destroy] 
    # after_action :verify_authorized 

    def index 
     @eois = Project.by_user_id(current_user.id).find_by(id: params[:project_id]).try(:eois) || [] 
    end 

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

def set_eoi 
     @eoi = EoiPolicy::Scope.new(current_user, params[:project_id]).resolve.find(params[:id]) 
     end 

     def get_project 
     @project = Project.find(params[:project_id]) 
     end 

ВЗ политики (чтобы решить, когда, чтобы показать все ВЗ сделанные пользователем)

class EoiPolicy < ApplicationPolicy 

    class Scope 
    attr_reader :user, :scope 

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

    def resolve 
     if scope.present? 
      Eoi.by_user_id(user.id) 
     # end 
     else 
     [] 
     end 
    end 

    end 

    def index? 
    user.profile.project.id == Eoi.project_id? or user.id == Eoi.user_id? 
    end 

    def new? 
    true 
    end 

    def show? 
    record.user_id == user.id || user.profile.project_id == record.project_id 
    # user.profile.project.id == @eoi.project_id? or user.id == eoi.user_id? 
    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 

Маршруты

resources :eois 

resources :projects do 
    member do 
    resources :eois, controller: 'projects/eois 
    end 

Когда я хочу показать EoI, которые представлены в отношении проекта, я использую политику проектов Eoi, и когда я хочу показать Eois, что пользователь создал, я использую Eoi Policy - no scopes.

Мне очень хотелось бы разобраться в этом, поэтому я могу использовать этот камень так, как он предназначен. Совет будет очень благодарен. Я уверен, что эта попытка не в том, что означает Pundit, но я не могу понять, как использовать этот камень, как показано в документах.

Я не могу использовать policy_scope, потому что мне нужно передать параметр project_id в действие индекса для действия индекса контроллера eoi.

PaReeOhNos SUGGESTION

Моя попытка пытается реализовать PareeOhNos предложение изложено ниже. Я не уверен, что правильно понимаю, потому что eois всегда будет иметь идентификатор проекта и идентификатор пользователя, но, возможно, я не понимаю, что делает метод load_parent.

В моем ВЗЕ контроллере, у меня есть:

class EoisController < ApplicationController 
    before_action :load_parent 
    before_action :load_eoi, only: [:show, :edit, :update, :destroy] 



    def index 
    authorize @parent 
    @eois = EoiPolicy::Scope.new(current_user, @parent).resolve 
    end 



    def show 

    end 

    # GET /eois/new 
    def new 
    @project = Project.find(params[:project_id]) 
    @eoi = @project.eois.build 
    @contribute = params[:contribute] || false 
    @participate = params[:participate] || false 
    @partner = params[:partner] || false 
    @grant = params[:grant] || false 
    @invest = params[:invest] || false 
    end 

    # GET /eois/1/edit 
    def edit 
    end 

    # POST /eois 
    # POST /eois.json 
    def create 
    @eoi = Project.find(params[:project_id]).eois.build(eoi_params) 
    @eoi.user_id = @current_user.id 

    respond_to do |format| 
     if @eoi.save 
     format.html { redirect_to Project.find(params[:project_id]), notice: 'Eoi was successfully created.' } 
     format.json { render :show, status: :created, location: @project } 
     else 
     format.html { render :new } 
     format.json { render json: @eoi.errors, status: :unprocessable_entity } 
     end 
    end 
    end 

    # PATCH/PUT /eois/1 
    # PATCH/PUT /eois/1.json 
    def update 
    respond_to do |format| 
     if @eoi.update(eoi_params) 
     format.html { redirect_to @project, notice: 'Eoi was successfully updated.' } 
     format.json { render :show, status: :ok, location: @eoi } 
     else 
     format.html { render :edit } 
     format.json { render json: @eoi.errors, status: :unprocessable_entity } 
     end 
    end 
    end 

    # DELETE /eois/1 
    # DELETE /eois/1.json 
    def destroy 
    @eoi.destroy 
    respond_to do |format| 
     format.html { redirect_to @project, notice: 'Eoi was successfully destroyed.' } 
     format.json { head :no_content } 
    end 
    end 

    private 

    def load_parent 
     # @parent = (params[:project_id] ? Project.find(params[:project_id] : current_user) 
     @parent = params[:project_id] ? Project.find(params[:project_id]) : current_user 
    end 

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

В моей ВЗ политике, у меня есть:

class EoiPolicy < ApplicationPolicy 
class Scope 
    attr_reader :user, :scope 

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

    def resolve 
     if scope.is_a?(User) 
     Eoi.where(user_id: scope.id) 
     elsif scope.is_a?(Project) 
     Eoi.where(project_id: scope.id) 
     else 
     [] 
     end 
    end 

    end 

    def index? 
    record.is_a?(User) || user.profile.project.id == record.project_id 
    end 

    def new? 
    true 
    end 

    def show? 
    record.user_id == user.id || user.profile.project_id == record.project_id 
    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 

В моем routes.rb, у меня есть:

resources :projects do 
    member do 
    resources :eois, shallow: true 

resources :eois, only: [:index] 

В моем eois/index у меня есть:

<% @eois.sort_by(&:created_at).in_groups_of(2) do |group| %> 
     <% group.compact.each do |eoi| %> 
      <h4><%= link_to eoi.user.full_name %></h4> 
      <%= link_to 'VIEW DETAILS', eoi_path(eoi), :class=>"portfolio-item-view" %> 
<% end %> 
<% end %> 

В моей ВЗ/шоу, у меня есть:

"test" 

Когда я пытаюсь все это, ВЗ/индекс загрузки страницы. Когда я пытаюсь показать конкретную страницу ВЗ, я получаю сообщение об ошибке, которая говорит:

wrong number of arguments (given 2, expected 0) 

точек сообщений об ошибках, чтобы разрешить @eoi линию контроллера:

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

Та же ошибка возникает, если я поместите авторизацию @eoi в действие show вместо метода загрузки eoi.

ПРИМЕНЕНИЕ ПОЛИТИКА ИМЕЕТ

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 

Следующая попытка

Taking PaReeOhNos предложение (скопированный выше), я пытался адаптировать его немного, чтобы лучше соответствовать мои варианты использования.

Теперь у меня есть:

ВЗ контроллер

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


    # GET /eois 
    # GET /eois.json 
    # def index 
    # @eois = @project.eois 
    # # @eois = Eois.find_by_project_id(params[:project_id]) 
    # end 

    def index 
    # authorize @parent 
    @eois = policy_scope(Eoi.where(project_id: params[:project_id])) 
    # @eois = EoiPolicy::Scope.new(current_user, @parent).resolve 
    end 


    # GET /eois/1 
    # GET /eois/1.json 
    def show 

    end 

    # GET /eois/new 
    def new 
    @project = Project.find(params[:project_id]) 
    @eoi = @project.eois.build 
    @contribute = params[:contribute] || false 
    @participate = params[:participate] || false 
    @partner = params[:partner] || false 
    @grant = params[:grant] || false 
    @invest = params[:invest] || false 
    end 

    # GET /eois/1/edit 
    def edit 
    end 

    # POST /eois 
    # POST /eois.json 
    def create 
    @eoi = Project.find(params[:project_id]).eois.build(eoi_params) 
    @eoi.user_id = @current_user.id 

    respond_to do |format| 
     if @eoi.save 
     format.html { redirect_to Project.find(params[:project_id]), notice: 'Eoi was successfully created.' } 
     format.json { render :show, status: :created, location: @project } 
     else 
     format.html { render :new } 
     format.json { render json: @eoi.errors, status: :unprocessable_entity } 
     end 
    end 
    end 

    # PATCH/PUT /eois/1 
    # PATCH/PUT /eois/1.json 
    def update 
    respond_to do |format| 
     if @eoi.update(eoi_params) 
     format.html { redirect_to @project, notice: 'Eoi was successfully updated.' } 
     format.json { render :show, status: :ok, location: @eoi } 
     else 
     format.html { render :edit } 
     format.json { render json: @eoi.errors, status: :unprocessable_entity } 
     end 
    end 
    end 

    # DELETE /eois/1 
    # DELETE /eois/1.json 
    def destroy 
    @eoi.destroy 
    respond_to do |format| 
     format.html { redirect_to @project, notice: 'Eoi was successfully destroyed.' } 
     format.json { head :no_content } 
    end 
    end 

    private 

    def load_parent 
     # @parent = (params[:project_id] ? Project.find(params[:project_id] : current_user) 
     @parent = params[:project_id] ? Project.find(params[:project_id]) : current_user 
    end 

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

ВЗ политика

class EoiPolicy < ApplicationPolicy 

    class Scope 
    attr_reader :user, :scope 

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

    def resolve 
     # since we send the scoped eois from controller, we can pick 
     # any eoi and get its project id 

     # check if the current user is the owner of the project 
    # if (user.profile.projects.map(&:id).include?(project_id)) 
    #  # user is the owner of the project, get all the eois 
    #  scope.all 
    # end 
    # #not the owner , then get only the eois created by the user 
    # scope.where(user_id: user.id) 
    # end 
     if scope.is_a?(User) 
     Eoi.where(user_id: scope.id) 
     elsif scope.is_a?(Project) && (user.profile.projects.map(&:id).include?(project_id)) 
     project_id = scope.first.project_id 
     Eoi.where(project_id: scope.id) 
     else 
     Eoi.none 
     end 
    end 

    end 

    def index? 
    record.is_a?(User) || user.profile.project.id == record.project_id 
    end 

    def new? 
    true 
    end 

    def show? 
    record.user_id == user.id || user.profile.project_id == record.project_id 
    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 

Маршруты

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

resources :projects do 
    concerns :eoiable 
    end 

Индекс

<% @eois.sort_by(&:created_at).in_groups_of(2) do |group| %> 
    <% group.compact.each do |eoi| %> 
    <h4><%= link_to eoi.user.full_name %></h4> 
    <%= link_to 'VIEW DETAILS', project_eoi_path(eoi.project, eoi), :class=>"portfolio-item-view" %> 
          <% end %> 
         <% end %> 

Посмотреть

'test' 

Это не работает, потому что, когда я перейти к проекту, а затем попытаться оказать индекс ВЗ, которые имеют идентификатор соответствия проекта, я получаю пустую страницу индекса, когда У меня есть 4 записи в моей базе данных, которые нужно визуализировать.

SUGGESTION Leito'S

Принимая предложение Leito, я также пробовал это:

ВЗ контроллер

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


    # GET /eois 
    # GET /eois.json 
    # def index 
    # @eois = @project.eois 
    # # @eois = Eois.find_by_project_id(params[:project_id]) 
    # end 

    def index 
    # authorize @eois 
    # authorize @parent 
    # policy_scope(@project.eois) 
    @eois = policy_scope(Eoi.where(project_id: params[:project_id])) 
    # @eois = EoiPolicy::Scope.new(current_user, @parent).resolve 
    end 


    # GET /eois/1 
    # GET /eois/1.json 
    def show 

    end 

    # GET /eois/new 
    def new 
    @project = Project.find(params[:project_id]) 
    @eoi = @project.eois.build 
    @contribute = params[:contribute] || false 
    @participate = params[:participate] || false 
    @partner = params[:partner] || false 
    @grant = params[:grant] || false 
    @invest = params[:invest] || false 
    end 

    # GET /eois/1/edit 
    def edit 
    end 

    # POST /eois 
    # POST /eois.json 
    def create 
    @eoi = Project.find(params[:project_id]).eois.build(eoi_params) 
    @eoi.user_id = @current_user.id 

    respond_to do |format| 
     if @eoi.save 
     format.html { redirect_to Project.find(params[:project_id]), notice: 'Eoi was successfully created.' } 
     format.json { render :show, status: :created, location: @project } 
     else 
     format.html { render :new } 
     format.json { render json: @eoi.errors, status: :unprocessable_entity } 
     end 
    end 
    end 

    # PATCH/PUT /eois/1 
    # PATCH/PUT /eois/1.json 
    def update 
    respond_to do |format| 
     if @eoi.update(eoi_params) 
     format.html { redirect_to @project, notice: 'Eoi was successfully updated.' } 
     format.json { render :show, status: :ok, location: @eoi } 
     else 
     format.html { render :edit } 
     format.json { render json: @eoi.errors, status: :unprocessable_entity } 
     end 
    end 
    end 

    # DELETE /eois/1 
    # DELETE /eois/1.json 
    def destroy 
    @eoi.destroy 
    respond_to do |format| 
     format.html { redirect_to @project, notice: 'Eoi was successfully destroyed.' } 
     format.json { head :no_content } 
    end 
    end 

    private 

    # def load_parent 
    # # @parent = (params[:project_id] ? Project.find(params[:project_id] : current_user) 
    # @parent = params[:project_id] ? Project.find(params[:project_id]) : current_user 
    # end 

    # def load_eoi 
    # @eoi = Eoi.find(params[:id]) 
    # # authorize @eoi 
    # end 
    # # Use callbacks to share common setup or constraints between actions. 
    def set_eoi 
     @eoi = Eoi.find(params[:id]) 
    end 

    def get_project 
     @project = Project.find(params[:project_id]) 
    end 

ВЗ политики

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

    def resolve 

     if scope.joins(project: :profile).where profiles: { user_id: user } 
     Eoi.where(project_id: scope.ids) 
     elsif scope.joins(eoi: :user).where eois: { user_id: user } 
     Eoi.where(user_id: scope.ids) 
     else 
     Eoi.none 
     end 
     # since we send the scoped eois from controller, we can pick 
     # any eoi and get its project id 

     # check if the current user is the owner of the project 
    # if (user.profile.projects.map(&:id).include?(project_id)) 
    #  # user is the owner of the project, get all the eois 
    #  scope.all 
    # end 
    # #not the owner , then get only the eois created by the user 
    # scope.where(user_id: user.id) 
    # end 
     # if scope.is_a?(User) 
     # Eoi.where(user_id: scope.id) 
     # elsif scope.is_a?(Project) && (user.profile.projects.map(&:id).include?(project_id)) 
     # project_id = scope.first.project_id 

     # Eoi.where(project_id: scope.id) 
     # else 
     # Eoi.none 
     # end 
    end 

    end 

    def index? 
    true 
    # record.is_a?(User) || user.profile.project.id == record.project_id 
    end 

    def new? 
    true 
    end 

    def show? 
    true 
    # record.user_id == user.id || user.profile.project_id == record.project_id 
    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 

Маршруты и мнения так же, как попытка abov e

Проблема здесь в том, что метод get в моем контроллере. Мне нужно это для сценария, где Im пытается показать все eois по конкретному проекту. Мне это не нужно, когда я пытаюсь показать всех пользователей eois.

Когда я сохраню все это и попробую, eois на проекте покажет правильно. Однако ВЗ (не вложены в проект), которые должны показать мне все мои (как пользователь) ВЗ, показывает ошибку, которая говорит:

Couldn't find Project with 'id'= 

сообщение об ошибке указывает на «get_project метод».

Leito Обновлено SUGGESTION

Принимая обновленное предложение Leito, я изложил текущую попытку.

Прежде чем это сделать, я хочу уточнить, что все Eois будут иметь идентификатор пользователя и идентификатор проекта. Я использую эту таблицу для того, чтобы пользователи проявляли интерес к проектам.Моя цель состоит в том, чтобы пользователь, чей профиль владеет проектом, видит все eois, представленные в этом проекте. Затем я также хочу, чтобы пользователи видели все свои собственные eois (во всех проектах).

ВЗ Политика

контроллер
def resolve 
    if scope.joins(project: :profile).where 'profiles.user_id = ? OR eois.user_id = ?', user.id, user.id 
    Eoi.all 
    else 
    Eoi.none 
    end 

ВЗ

def index 
    @eois = policy_scope(Eoi) 
    @eois = @eois.where(project_id: params[:project_id]) if params[:project_id] 
    end 

В настоящее время это работает отлично в поиске ВЗ, которые вложены в рамках проекта (проект/26/ВЗ). Однако, когда я пытаюсь сделать ВЗ/индекс (не вложены в проект), который я хочу, чтобы вернуть все ВЗ пользователя, я получаю сообщение об ошибке, которая говорит:

Couldn't find Project with 'id'= 

Он выделяет эту линию контроллера ВЗ:

def get_project 
    @project = Project.find(params[:project_id]) 
end 

Я не уверен, что я понимаю способ решения или контроллер, выбрасывающий идею сейчас. Я не вижу, что случилось с линией области видимости, чтобы увидеть, что попробовать.

+0

Один за один раз, пожалуйста! Первая - это простая ошибка: в вашем профиле нет единого проекта, но много проектов. вот почему ошибка. Давайте избавимся от этого и сосредоточимся на том, с которым вы пытаетесь работать с '.projects' – Leito

+0

Вы изменили свою' application_policy.rb' или то же самое, что и pundit, когда вы его устанавливаете? – lcguida

+0

Я добавил политику приложения в конец своего сообщения – Mel

ответ

2

В вашем первом примере есть несколько вопросов. Во-первых, @eoi не существует и не может существовать. Переменная @eoi задается в контроллере, и это другой объект. Он не работает так же, как ваши взгляды, где это доступно, поэтому это никогда не будет установлено.

Равным образом, переменная eoi не будет установлен, так как ваш метод initialize только назначая user и resource переменных, поэтому они только два у вас есть доступ (если вы не переименовывать)

Сферы действия в политика работает немного по-другому, как вы думаете, что это работает. Сама политика обычно включает пользователя, входящего в систему, и класс или запись, которую вы разрешаете. Однако область действия обычно не принимает запись в качестве второго аргумента. Это область действия, поэтому либо активный подкласс класса, либо отношение. Однако вы не ограничены этим, и вы можете обойти это, поставив запись, но обратите внимание, что это не нормальное поведение для Pundit.

Для того, чтобы достичь того, что вы после этого, вы должны только сделать несколько изменений:

class EoiPolicy < ApplicationPolicy 

    class Scope 
    attr_reader :user, :eoi 

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

    def resolve 
     if user.profile.project.id == eoi.project_id 
     Eoi.where(project_id: user.profile.project.id) 
     elsif user.id == eoi.user_id 
     Eoi.where(user_id: user.id) 
     else 
     nil 
     end 
    end 
    end 

    def index? 
    user.profile.project.id == record.project_id or user.id == record.user_id 
    end 

    def new? 
    true 
    end 

    def show? 
    user.profile.project.id == record.project_id? or user.id == record.user_id 
    end 

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

    def create? 
    true 
    end 

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

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


end 

Основные изменения здесь в том, что attr_reader :user, :scope теперь attr_reader :user, :eoi, который даст вам доступ к eoi в это scope.

Доступ к этому уже не префикс @, так как это соответствует тому, как работает пандит.

Всюду по остальной части политики @eoi снова не может работать, но это было изменено на record (предполагается, что это то, что есть в ApplicationPolicy). Пожалуйста, имейте в виду область действия, а остальная часть политики - это два разных класса.

С помощью этой настройки вы должны теперь просто позвонить policy_scope(@eoi) с вашего контроллера. Обратите внимание на использование переменной @eoi здесь и НЕ Eoi, как и раньше. Это важно, так как без этого у вас не будет доступа к таким вещам, как user_id или project_id, поскольку эти методы не существуют в классе Eoi, а только запись.

Я также удалил символы ? с конца ваших условий if. Они обычно используются для обозначения того, что вызываемый метод возвращает логическое значение, тогда как вы имели их в конце чего-то, что просто возвращает целое число. Я бы предположил, что на самом деле вы получите сообщение о том, что метод не существует, но если вы переименовали вещи, то можете захотеть их вернуть, но, как я уже сказал, это противоречит стилям рубинового кодирования.

А на боковой ноте, используя or или and в отчетности вместо || или && может по нечетной случаю ведут себя по-разному, как вы ожидаете. В большинстве сценариев это нормально, но технически это не означает то же самое.

Надеюсь, что все это помогает, сообщите мне, есть ли у вас какие-либо дополнительные проблемы.

+0

Привет, большое спасибо за это объяснение. Я очень хочу попробовать это. На данный момент, когда я пытаюсь это сделать, появляется сообщение об ошибке: невозможно найти область политики nil и указывает на эту строку в моем действии индекса в контроллере eois: policy_scope (@eoi) – Mel

+0

Это предполагает, что ' @ eoi' - ноль. Это определенно было настроено на что-то? – PaReeOhNos

+0

Существует определенно eoi, и его внешний ключ определенно находится на правильном проекте. – Mel

3

Я бывший комментатор по этому вопросу.

Для вашего EoiScope вы просто хотите, чтобы у Eois у пользователя был доступ (поскольку они принадлежат проектам под этим профилем), независимо от проекта (это требование предназначено только для контроллера, поскольку оно вложенное), поэтому ваш контроллер должен выглядеть примерно так:

Редактировать: Исходя из вашей последней попытки, я обновил область для учета Eois, принадлежащую непосредственно пользователю (а не через проект), и вы должны просто охватить его проектом или не зависит от наличия параметров [: project_id], см. обновленный ответ.

@eois = policy_scope(Eoi) 
@eois = @eios.where(project_id: params[:project_id]) if params[:project_id] 

И ваша область действия должна соединяться до тех пор, пока она не достигнет пользователя или просто не найдет свойство user_id на Eoi.

class EoiPolicy < ApplicationPolicy 
    class Scope < Scope 
     def resolve 
     scope.joins(project: : profile).where 'profiles.user_id = ? OR eois.user_id = ?', user.id, user.id 
     end 
    end 

    # Other methods that differ from ApplicationPolicy's methods 
    end 

Пожалуйста, обратите внимание, что Scope не называет eoi, но по умолчанию * сфера только знает о scope и user. * По умолчанию я имею в виду, когда он наследует от ApplicationPolicy::Scope

+0

Большое спасибо за попытку помочь Лейто. Я попробовал ваше предложение, но получаю эту ошибку: неопределенная локальная переменная или метод 'eoi 'для # . Сообщение об ошибке указывает на эту строку: if user.id == eoi.projects.profile.user.map (&: id) – Mel

+0

Это метод 'show?'? По умолчанию ApplicationPolicy, который вы можете наследовать, имеет метод 'record', который, вероятно, содержит eoi, но не метод' eoi', следовательно, ошибку. – Leito

+0

Это на индексе? метод. Я не понимаю ошибку, которую вы описываете. У вас есть предложение, как я могу понять, что означает эта ошибка или как ее решить? – Mel

0

Для других я не уверен, что это решение, которое использует Pundit так, как оно предназначалось, однако оно генерирует потоки, которые я хочу, в пределах моих возможностей.

Благодарим всех, кто помог в этом. Я уверен, что у меня еще есть много, чтобы узнать, как улучшить это, но на данный момент это решение, которое работает.

Итого: теперь у меня есть две политики для 1 контроллера.

ВЗ Политика

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 

Проект ВЗ Политика

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 

индекс действия ВЗ Контроллер

class EoisController < ApplicationController 
    before_action :get_project, except: [:index, :show] 
    before_action :set_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 
+0

POST SCRIPT: Поцарапайте это. Это не работает. Когда я добавляю authorize @eoi в действие моего контроллера (просто тестирование на действие show), я получаю сообщение об ошибке: неправильное количество аргументов (учитывая 2, ожидается 0). Вернуться к доске для рисования. Я все еще застрял. – Mel