Rails 4 - Pundit - как написать сферу
Я пытаюсь узнать, как использовать Pundit с Rails 4. Я пытался изучить это в течение последних 2 лет и постепенно делаю небольшие успехи.
Я также пытаюсь научиться писать области. Я все еще пытаюсь понять, как перевести совет на простой английский, чтобы я мог начать понимать.
Я застреваю на пересечении использования политик мудрости областей и общего класса области действия, который я могу написать в модели.
У меня есть модели для Uer, Profile и Project.
Ассоциации являются:
пользователь
has_one :profile
Профиль
belongs_to :user
has_many :projects
проект
belongs_to :profile
Я пытаюсь написать политику для экспертов, которая позволяет разным пользователям видеть разные проекты. Я пишу ограниченную политику, в мудрости, чтобы справиться с этим.
В моей модели проекта я пытаюсь написать область действия, которая находит все проекты пользователя. Говоря простым языком, я хочу найти во всех проектах те, которые имеют идентификатор профиля, который принадлежит идентификатору пользователя, который равен текущему пользователю.
В моей политике pundit я пытаюсь написать этот метод разрешения:
class Scope
attr_reader :user, :scope
def initialize(user, scope)
@user = user
@scope = scope
end
def resolve
if user.has_role?(:admin)
scope.all
elsif user.id == @project.profile.user_id
scope.projects_for_user
elsif user.present?
scope.in_state(:publish)
else
Project.none
end
end
end
Я испробовал около 100 различных способов написания области действия для моей модели проекта, которая находит проекты, принадлежащие текущему пользователю. Я знаю, что не могу использовать в модели devisus current_user, поэтому я не могу использовать его в области видимости. Эти две мои лучшие попытки - обе ошибочны.
scope :projects_for_user, -> { joins(:user_id).where('project.profile.user_id = ?', user.id) }
scope :projects_for_user, -> { where(project.profile.user_id: User.id) }
Моя главная проблема с изучением этого - я не вижу, как разбить эту линию на разные части.
Из того, что я могу понять, немного до того, как ":" это то, что вы ищете. Бит после ":" - это экземпляр, который вы используете, когда запускаете область. Если это так, то я не понимаю, почему моя 2-я попытка не сработала (а также очень смущен оператором объединения в 1-й попытке).
Если бы кто-то мог помочь с простым английским объяснением того, как писать области, я уверен, что я знаю, что я хочу искать, просто отчаянно растерялся, как написать запрос, чтобы найти его.
В настоящее время, когда я пытаюсь использовать мою политику проекта (я попытался включить предложение Тарин ниже - хотя я не понимаю каждого компонента области, поэтому я не уверен, что происходит с ним).
class ProjectPolicy < ApplicationPolicy
attr_reader :user, :record
class Scope
attr_reader :user, :scope
def initialize(user, scope)
@user = user
@scope = scope
end
def resolve
if user.has_role?(:admin)
scope.all
elsif user.id == @project.profile.user_id
scope.projects_for_user(user)
elsif user.present?
scope.in_state(:publish)
else
Project.none
end
end
end
def index?
true
end
def show?
true
end
private
def project
record
end
Модель проекта:
scope :projects_for_user, -> (user){ joins(:user_id).where('project.profile.user_id = ?', user.id) }
В моем контроллере проекта у меня есть:
class ProjectsController < ApplicationController
before_action :set_project, only: [:show, :edit, :update, :destroy ]
before_action :authenticate_user!
def index
@projects = Project.all
authorize @projects
end
def show
@project = Project.find(params[:id])
# authorize @project
end
private
def set_project
@project = Project.find(params[:id])
authorize @project
end
Когда я сохраняю это и пробую это, это дает ошибку, которая говорит:
wrong number of arguments (given 2, expected 0)
Эта ошибка возвращается, когда я пытаюсь увидеть индекс проектов или конкретного проекта (поэтому я не думаю, что это связано с областью действия). Я не понимаю, какие два аргумента приводятся, чтобы знать, как поступить, пытаясь решить эту проблему.
ДОБАВИТЬ STACK TRACE
ArgumentError - wrong number of arguments (given 2, expected 0):
pundit (1.1.0) lib/pundit.rb:112:in `policy!'
pundit (1.1.0) lib/pundit.rb:235:in `policy'
pundit (1.1.0) lib/pundit.rb:194:in `authorize'
app/controllers/eois_controller.rb:20:in `show'
actionpack (4.2.4) lib/action_controller/metal/implicit_render.rb:4:in `send_action'
actionpack (4.2.4) lib/abstract_controller/base.rb:198:in `process_action'
actionpack (4.2.4) lib/action_controller/metal/rendering.rb:10:in `process_action'
actionpack (4.2.4) lib/abstract_controller/callbacks.rb:20:in `block in process_action'
activesupport (4.2.4) lib/active_support/callbacks.rb:117:in `call'
activesupport (4.2.4) lib/active_support/callbacks.rb:555:in `block (2 levels) in compile'
activesupport (4.2.4) lib/active_support/callbacks.rb:505:in `call'
activesupport (4.2.4) lib/active_support/callbacks.rb:92:in `__run_callbacks__'
activesupport (4.2.4) lib/active_support/callbacks.rb:778:in `_run_process_action_callbacks'
activesupport (4.2.4) lib/active_support/callbacks.rb:81:in `run_callbacks'
actionpack (4.2.4) lib/abstract_controller/callbacks.rb:19:in `process_action'
actionpack (4.2.4) lib/action_controller/metal/rescue.rb:29:in `process_action'
actionpack (4.2.4) lib/action_controller/metal/instrumentation.rb:32:in `block in process_action'
activesupport (4.2.4) lib/active_support/notifications.rb:164:in `block in instrument'
activesupport (4.2.4) lib/active_support/notifications/instrumenter.rb:20:in `instrument'
activesupport (4.2.4) lib/active_support/notifications.rb:164:in `instrument'
actionpack (4.2.4) lib/action_controller/metal/instrumentation.rb:30:in `process_action'
actionpack (4.2.4) lib/action_controller/metal/params_wrapper.rb:250:in `process_action'
searchkick (1.3.0) lib/searchkick/logging.rb:153:in `process_action'
activerecord (4.2.4) lib/active_record/railties/controller_runtime.rb:18:in `process_action'
actionpack (4.2.4) lib/abstract_controller/base.rb:137:in `process'
actionview (4.2.4) lib/action_view/rendering.rb:30:in `process'
actionpack (4.2.4) lib/action_controller/metal.rb:196:in `dispatch'
actionpack (4.2.4) lib/action_controller/metal/rack_delegation.rb:13:in `dispatch'
actionpack (4.2.4) lib/action_controller/metal.rb:237:in `block in action'
actionpack (4.2.4) lib/action_dispatch/routing/route_set.rb:76:in `dispatch'
actionpack (4.2.4) lib/action_dispatch/routing/route_set.rb:45:in `serve'
actionpack (4.2.4) lib/action_dispatch/journey/router.rb:43:in `block in serve'
actionpack (4.2.4) lib/action_dispatch/journey/router.rb:30:in `serve'
actionpack (4.2.4) lib/action_dispatch/routing/route_set.rb:821:in `call'
omniauth (1.3.1) lib/omniauth/strategy.rb:186:in `call!'
omniauth (1.3.1) lib/omniauth/strategy.rb:164:in `call'
omniauth (1.3.1) lib/omniauth/strategy.rb:186:in `call!'
omniauth (1.3.1) lib/omniauth/strategy.rb:164:in `call'
omniauth (1.3.1) lib/omniauth/strategy.rb:186:in `call!'
omniauth (1.3.1) lib/omniauth/strategy.rb:164:in `call'
omniauth (1.3.1) lib/omniauth/strategy.rb:186:in `call!'
omniauth (1.3.1) lib/omniauth/strategy.rb:164:in `call'
meta_request (0.4.0) lib/meta_request/middlewares/app_request_handler.rb:13:in `call'
meta_request (0.4.0) lib/meta_request/middlewares/meta_request_handler.rb:13:in `call'
warden (1.2.6) lib/warden/manager.rb:35:in `block in call'
warden (1.2.6) lib/warden/manager.rb:34:in `call'
rack (1.6.4) lib/rack/etag.rb:24:in `call'
rack (1.6.4) lib/rack/conditionalget.rb:25:in `call'
rack (1.6.4) lib/rack/head.rb:13:in `call'
actionpack (4.2.4) lib/action_dispatch/middleware/params_parser.rb:27:in `call'
actionpack (4.2.4) lib/action_dispatch/middleware/flash.rb:260:in `call'
rack (1.6.4) lib/rack/session/abstract/id.rb:225:in `context'
rack (1.6.4) lib/rack/session/abstract/id.rb:220:in `call'
actionpack (4.2.4) lib/action_dispatch/middleware/cookies.rb:560:in `call'
activerecord (4.2.4) lib/active_record/query_cache.rb:36:in `call'
activerecord (4.2.4) lib/active_record/connection_adapters/abstract/connection_pool.rb:653:in `call'
activerecord (4.2.4) lib/active_record/migration.rb:377:in `call'
actionpack (4.2.4) lib/action_dispatch/middleware/callbacks.rb:29:in `block in call'
activesupport (4.2.4) lib/active_support/callbacks.rb:88:in `__run_callbacks__'
activesupport (4.2.4) lib/active_support/callbacks.rb:778:in `_run_call_callbacks'
activesupport (4.2.4) lib/active_support/callbacks.rb:81:in `run_callbacks'
actionpack (4.2.4) lib/action_dispatch/middleware/callbacks.rb:27:in `call'
actionpack (4.2.4) lib/action_dispatch/middleware/reloader.rb:73:in `call'
actionpack (4.2.4) lib/action_dispatch/middleware/remote_ip.rb:78:in `call'
better_errors (2.1.1) lib/better_errors/middleware.rb:84:in `protected_app_call'
better_errors (2.1.1) lib/better_errors/middleware.rb:79:in `better_errors_call'
better_errors (2.1.1) lib/better_errors/middleware.rb:57:in `call'
actionpack (4.2.4) lib/action_dispatch/middleware/debug_exceptions.rb:17:in `call'
rack-contrib (1.4.0) lib/rack/contrib/response_headers.rb:17:in `call'
meta_request (0.4.0) lib/meta_request/middlewares/headers.rb:16:in `call'
web-console (2.3.0) lib/web_console/middleware.rb:28:in `block in call'
web-console (2.3.0) lib/web_console/middleware.rb:18:in `call'
actionpack (4.2.4) lib/action_dispatch/middleware/show_exceptions.rb:30:in `call'
railties (4.2.4) lib/rails/rack/logger.rb:38:in `call_app'
railties (4.2.4) lib/rails/rack/logger.rb:20:in `block in call'
activesupport (4.2.4) lib/active_support/tagged_logging.rb:68:in `block in tagged'
activesupport (4.2.4) lib/active_support/tagged_logging.rb:26:in `tagged'
activesupport (4.2.4) lib/active_support/tagged_logging.rb:68:in `tagged'
railties (4.2.4) lib/rails/rack/logger.rb:20:in `call'
request_store (1.3.1) lib/request_store/middleware.rb:9:in `call'
actionpack (4.2.4) lib/action_dispatch/middleware/request_id.rb:21:in `call'
rack (1.6.4) lib/rack/methodoverride.rb:22:in `call'
rack (1.6.4) lib/rack/runtime.rb:18:in `call'
activesupport (4.2.4) lib/active_support/cache/strategy/local_cache_middleware.rb:28:in `call'
rack (1.6.4) lib/rack/lock.rb:17:in `call'
actionpack (4.2.4) lib/action_dispatch/middleware/static.rb:116:in `call'
rack (1.6.4) lib/rack/sendfile.rb:113:in `call'
skylight (0.10.6) lib/skylight/middleware.rb:61:in `call'
railties (4.2.4) lib/rails/engine.rb:518:in `call'
railties (4.2.4) lib/rails/application.rb:165:in `call'
rack (1.6.4) lib/rack/content_length.rb:15:in `call'
puma (3.4.0) lib/puma/configuration.rb:224:in `call'
puma (3.4.0) lib/puma/server.rb:569:in `handle_request'
puma (3.4.0) lib/puma/server.rb:406:in `process_client'
puma (3.4.0) lib/puma/server.rb:271:in `block in run'
puma (3.4.0) lib/puma/thread_pool.rb:114:in `block in spawn_thread'
Началось POST "/__better_errors/123578515c1e4e10/variable" для::1 в 2016-09-08 13:23:01 +1000
АНАЛИЗ STACK TRACE
Единственная строка, которую я написал сам, - это строка authorize @eoi в контроллере eois (внутри действия show). Это ключевая часть использования Pundit. Остальная часть трассировки стека взята из вещей, которые я не написал и не знаю, как изменить.
app/controllers/eois_controller.rb:20:in `show'
ОТВЕТ НА ВОЗМОЖНЫЙ ДУБЛИКАТ ТЕГ
Другой вопрос также один, который я отправил. Они идут в разные точки. В этом посте я подумал, что, возможно, я неправильно писал прицелы (возможно, я и был). В другом посте я попытался изложить весь процесс, чтобы посмотреть, смог ли кто-то помочь мне понять, где я ошибался.
1 ответ
Проблема в том, что вы на самом деле не указываете идентификатор пользователя. В этом: User.id
это никогда не сработает... User
класс представляет всех пользователей... нет смысла спрашивать его идентификатор (вы просто получите идентификатор объекта ruby, в котором хранятся методы класса).
в другой... вы используете user.id
но на самом деле не устанавливайте значение user
переменная (так что она всегда будет терпеть неудачу).
Возможно, попробуйте передать соответствующий идентификатор пользователя в метод в качестве параметра, например:
# define the `user` parameter as an argument to this scope-method
scope :projects_for_user, -> (user){ joins(:user_id).where('project.profile.user_id = ?', user.id) }
def resolve
if user.has_role?(:admin)
scope.all
elsif user.id == @project.profile.user_id
scope.projects_for_user(user) # pass the user into the method
elsif user.present?
scope.in_state(:publish)
else
Project.none
end
end
Примечание: я не проверял (и не буду) проверять этот код, он может содержать опечатки или ошибки... попробуйте и исправьте ошибки.