В приложении My Rails есть много моделей, которые образуют иерархию. Например: Розничный торговец > Отдел > Категория продуктa > Продукт > Обзор.
Бизнес-требование состоит в том, что высокопоставленные пользователи могут "делиться" с каким-либо отдельным элементом в иерархии с новым или существующим "обычным" пользователем. Не имея общего с ними объекта, обычные пользователи не имеют права видеть (или делать что-либо еще) с любым объектом на любом уровне иерархии.
Процесс совместного доступа включает в себя выбор того, разрешает ли данный ресурс разрешение только на чтение, чтение-обновление или полный CRUD на целевой объект.
Обмен любыми объектами предоставляет R/O, R/W или CRUD-разрешения этому объекту и всем объектам нижнего уровня в иерархии и R/O-разрешение всем прямым предкам объекта. Коллекция объектов вырастает органично, поэтому система разрешений работает только путем регистрации пользователя user_id, объекта_объекта и характера ресурса (R/O, CRUD и т.д.). Поскольку совокупность объектов в этой иерархии растет все время, нецелесообразно создавать запись явного разрешения в БД для каждой комбинации пользователя/объекта.
Вместо этого, в начале цикла пользовательского запроса ApplicationController
собирает все записи разрешений (пользователь X имеет разрешение CRUD для Департамента № 5) и удерживает их в хеше в памяти. Модель разрешений знает, как оценить хэш, когда какой-либо объект передан ему - Permission.allow? (: Show, Department # 5) вернет true или false в зависимости от содержимого хеша разрешения пользователя.
Возьмем, например, модель отдела:
# app/models/department.rb
class Department < ActiveRecord::Base
after_initialize :check_permission
private
def check_permission
# some code that returns true or false
end
end
Когда метод check_permission
возвращает true, я хочу, чтобы Department.first
возвращал первую запись в базу данных как обычно, НО, если check_permission
возвращает false, я хочу вернуть nil
.
В настоящее время у меня есть решение, при котором области по умолчанию запускают проверку разрешений, но это вызывает 2X количество запросов, а для классов с большим количеством объектов проблемы с памятью и проблемы времени/производительности обязательно будут на горизонт.
Моя цель - использовать обратные вызовы after_initialize
для предварительного разрешения объектов.
Однако, похоже, что after_initialize
не может заблокировать возврат исходного объекта. Это позволяет мне reset значения атрибутов объекта, но не обойтись без него.
Кто-нибудь знает, как добиться этого?
EDIT:
Большое спасибо за все предоставленные ответы и комментарии; надеюсь, эта расширенная версия вопроса прояснит ситуацию.