ruby-on-rails - перевод - ruby on rails cancancan
Rails 4-политика Pundit для индексов (2)
Я пытаюсь узнать, как использовать Pundit с моим Rails 4.
У меня есть следующие модели:
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
с 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| %>
Я не могу заставить это работать. Сообщение об ошибке выделяет эту строку моего метода scope в политике:
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.
Если бы у меня была такая работа, то, возможно, я мог бы получить метод scope для работы с индексом на контроллере:
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)
Пожалуйста помоги!
СЛЕДУЮЩАЯ ПОПЫТКА
Моя следующая попытка состоит в том, чтобы попытаться принять предложения из этой проблемы Pundit и реализовать эту идею о том, как получить правильную область для конкретного пользователя.
В моей политике Eoi я изменил метод разрешения на:
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
Затем в моем действии индекса контроллера eoi я попробовал это:
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 и не показан в документах Gem Pundit. Если это необходимо включить, что он делает? 1
REWRITE
Теперь я просмотрел более 200 репозиториев на github для понимания того, как я должен писать политику для достижения моих целей. У меня нет идей о том, как использовать Pundit по назначению.
Я полностью изменил настройку, чтобы попытаться обойти бит, который я не могу понять. У меня теперь есть:
Контроллер Eois
class EoisController < ApplicationController
def index
@eois = Eoi.by_user_id(current_user.id)
end
end
Проекты :: Контроллер Eois
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
Eoi Policy (чтобы решить, когда показывать все eois, сделанные пользователем)
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 приведена ниже. Я не уверен, что правильно понимаю, потому что eois всегда будет иметь идентификатор проекта и идентификатор пользователя, но, возможно, я не понимаю, что делает метод load_parent.
В моем контроллере Eois у меня есть:
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
В моей политике Eoi у меня есть:
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
На моих маршрутах.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 %>
В моем eois / show у меня есть:
"test"
Когда я пытаюсь все это, загружается страница eois / index. Когда я пытаюсь показать конкретную страницу eoi, я получаю сообщение об ошибке:
wrong number of arguments (given 2, expected 0)
сообщение об ошибке указывает на авторизацию строки @eoi контроллера:
def load_eoi
@eoi = Eoi.find(params[:id])
authorize @eoi
end
Такая же ошибка возникает, если я устанавливаю authorize @eoi в действии show вместо метода load 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
СЛЕДУЮЩАЯ ПОПЫТКА
Принимая предложение PaReeOhNos (скопированное выше), я попытался немного его адаптировать, чтобы лучше соответствовать моим случаям использования.
Теперь у меня есть:
Контроллер Eoi
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
Политика Eoi
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'
Это не работает, потому что, когда я перехожу к проекту, а затем пытаюсь отобразить индекс eois, у которого есть соответствующий идентификатор проекта, я получаю пустую индексную страницу, когда у меня есть 4 записи в моей базе данных, которые должны отображаться.
ПРЕДЛОЖЕНИЕ ЛЕЙТО
Принимая предложение Лейто, я также пробовал это:
Контроллер Eoi
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
Политика Eoi
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
Маршруты и представления такие же, как и попытка выше
Проблема здесь в том, что метод get project в моем контроллере. Мне нужно это для сценария, где Im пытается показать все eois по конкретному проекту. Мне это не нужно, когда я пытаюсь показать всех пользователей eois.
Когда я сохраню все это и попробую, эйз по проекту покажет правильно. Однако eois (не вложенный внутри проекта), который должен показать мне все мои (как пользователь) eois, показывает ошибку, которая гласит:
Couldn't find Project with 'id'=
В сообщении об ошибке выделяется метод get_project.
ОБНОВЛЕННОЕ ПРЕДЛОЖЕНИЕ LEITO
Принимая последнее предложение Лейто, я изложил текущую попытку.
Прежде чем это сделать, я хочу уточнить, что у всех Eois будет как идентификатор пользователя, так и идентификатор проекта. Я использую эту таблицу для того, чтобы пользователи проявляли интерес к проектам. Моя цель состоит в том, чтобы пользователь, чей профиль владеет проектом, видит все eois, представленные в этом проекте. Затем я также хочу, чтобы пользователи видели все свои собственные eois (во всех проектах).
Политика Eoi
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
Контроллер Eoi
def index
@eois = policy_scope(Eoi)
@eois = @eois.where(project_id: params[:project_id]) if params[:project_id]
end
В настоящее время это прекрасно подходит для поиска eois, которые вложены в проект (проект / 26 / eois). Однако, когда я пытаюсь сделать eois / index (не вложенный в проект), который я хочу вернуть всем eois пользователя, я получаю сообщение об ошибке:
Couldn't find Project with 'id'=
Он выделяет эту строку контроллера eoi:
def get_project
@project = Project.find(params[:project_id])
end
Я не уверен, что сейчас понимаю метод решения или контроллер, который выбрал идею. Я не вижу, что случилось с линией области видимости, чтобы увидеть, что попробовать.
В вашем первом примере есть несколько проблем. Во-первых, @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
пределах этой области.
Доступ к этому уже не префикс с @
поскольку это соответствует тому, как работает pundit.
Во всей остальной части политики @eoi
снова не может работать, но это было изменено на record
(предполагая, что это то, что есть в ApplicationPolicy). Пожалуйста, имейте в виду область действия, а остальная часть политики - это два разных класса.
С помощью этой настройки вы должны теперь просто вызвать policy_scope(@eoi)
из своего контроллера. Обратите внимание на использование переменной @eoi
здесь и НЕ класс @eoi
как и раньше. Это важно, так как без этого у вас не будет доступа к таким вещам, как user_id
или project_id
поскольку эти методы не существуют в классе Eoi, а только запись.
Я также удалил ?
символы с конца ваших условий if. Они обычно используются для обозначения того, что вызываемый метод возвращает логическое значение, тогда как вы имели их в конце чего-то, что просто возвращает целое число. Я бы предположил, что на самом деле вы получите сообщение о том, что метод не существует, но если вы переименовали вещи, то можете захотеть их вернуть, но, как я уже сказал, это противоречит стилям рубинового кодирования.
И на стороне примечание, используя or
или and
в операторах вместо ||
или &&
могут в нечетном случае вести себя по-другому, как вы ожидаете. В большинстве сценариев это нормально, но технически это не означает то же самое.
Надеюсь, что все это поможет, сообщите мне, есть ли у вас какие-либо дальнейшие проблемы.
Я - предыдущий комментатор по этому вопросу.
Для вашего 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