Я пытаюсь научиться использовать 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
Я не уверен, что я понимаю способ решения или контроллер, выбрасывающий идею сейчас. Я не вижу, что случилось с линией области видимости, чтобы увидеть, что попробовать.
Один за один раз, пожалуйста! Первая - это простая ошибка: в вашем профиле нет единого проекта, но много проектов. вот почему ошибка. Давайте избавимся от этого и сосредоточимся на том, с которым вы пытаетесь работать с '.projects' – Leito
Вы изменили свою' application_policy.rb' или то же самое, что и pundit, когда вы его устанавливаете? – lcguida
Я добавил политику приложения в конец своего сообщения – Mel