Rolify: проверка ролей со сложной функциональностью внутри модели User
Я потратил четыре дня, пытаясь добиться этой роли, но безуспешно, и я не знаю, есть ли в настоящее время какой-либо способ сделать это с помощью rolify. Вот простой пример ситуации, которую я имею:
Предположим, у меня есть 3 типа ролей:
- админ
- разработчик
- гость
Пользователь может быть как администратором, так и разработчиком, но не может быть и гостем.
Гость не может быть ни администратором, ни разработчиком.
Я хочу, чтобы пользователь мог устанавливать свои роли при регистрации пользователя, поэтому мне нужно проверить это поведение до того, как пользователь будет создан, и, если оно недопустимо, регистрация должна завершиться сбоем, и ни один пользователь не должен быть создан.
Я прочитал много руководств, пытающихся достичь аналогичных результатов, по крайней мере, при отправке формы, но нет объяснения этому типу проверки.
Заранее спасибо!
ОБНОВЛЕНИЕ: Я искал несколько способов реализовать это, и это направление мысли, которое у меня было в это время борьбы.
Во-первых: получите роли, выбранные в качестве входных данных, и создайте виртуальный атрибут в пользовательской модели, соответствующей этим ролям, чтобы параметры выглядели так (упрощенно)
:params => { :user => {:email, :password, :roles => ["admin", "developer", "guest"]}}
если все роли выбраны, и
:params => { :user => {:email, :password}}
если роль не выбрана.
Второе. Выполните любой тип проверок с этим виртуальным атрибутом (упрощенно).
Class User < ApplicationRecord
attr_accessor :roles
validate :roles_valid
def roles_valid
# Define custom validation
end
end
Третье: если запись проходит все проверки, создайте пользователя, а затем назначьте роли внутри регистраций # новое действие
Я думаю, что этот метод будет работать, но у меня сейчас есть некоторые проблемы с виртуальным атрибутом, и он заключается в том, что он не связан с параметрами ролей, получаемых из формы. Полагаю, я до сих пор не понимаю, как работают виртуальные атрибуты, поэтому я бы хотел, чтобы кто-нибудь объяснил мне этот вопрос.
1 ответ
Я понял! Процесс, который я добавил в обновлении, является правильным, поэтому я сделаю краткое руководство о том, как этого добиться правильно.
Цель: проверить сложную функциональность для rolify внутри пользовательской модели. Это должно быть сделано внутри модели User, потому что нужно проверять все добавляемые роли, а не каждую в отдельности.
Шаг первый: если роли, которые будет использовать ваше приложение, являются статическими, то сначала необходимо заполнить таблицу ролей конкретными ролями. Для этого я оставлю пост с другим вопросом здесь, в Переполнении стека, который подробно объясняет этот процесс:
Определение ролей с помощью Rolify
Шаг второй: измените вашу регистрационную форму. Чтобы получить роли, выбранные пользователем, мы должны сначала добавить несколько флажков, соответствующих ролям, определенным на первом шаге. Вот простой код для этого.
<%= form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| %>
<!-- ADD HERE ALL YOUR REGISTRATION INPUTS -->
<% Role.all.each do |role| %>
<%= f.checkbox :input_roles, {multiple: true}, role.name, nil %>
<%= role.name %>
<% end %>
<% end %>
Выполнение этого сгенерирует все необходимые флажки и сохранит результат внутри переменной
params => {:user => { :input_roles => [] }}
Важные заметки! если пользователь не выбирает какую-либо роль, тогда переменная input_roles
не будет определен! Вы должны проверить это в ваших валидациях. ТАКЖЕ, НЕ ИЗМЕНЯЙТЕ ИМЯ ПЕРЕМЕННОГО К roles
Я сделал эту ошибку и прошел через ад, пытаясь исправить все ошибки, которые я получал. Если вам интересно посмотреть, через что я прошел, вот ссылка на созданную мной проблему:
https://github.com/RolifyCommunity/rolify/issues/446
Шаг третий: Поскольку вы добавляете новый параметр в форму, вы также должны включить его в свои сильные параметры. Поскольку эта переменная является массивом, вы должны явно определить это внутри ваших сильных параметров:
Если вы используете Devise:
devise_parameter_sanitizer.permit(:sign_up, keys: [:email, :password, :password_confirmation, input_roles: [])
Если вы не используете devise:
params.require(:user).permit( :email, :password, :password_confirmation, input_roles: [])
Шаг четвертый: Хорошо, теперь input_roles
Param передается в наш User
модель. Но теперь нам нужно найти способ проверки значений внутри. Поскольку этот параметр не является частью нашей модели User, мы должны создать виртуальный атрибут, чтобы иметь возможность работать с этими параметрами. Таким образом, мы просто называем его так же, как параметр, передаваемый модели:
Class User < ApplicationRecord
rolify
attr_accessor :input_roles
Теперь, когда вы хотите получить доступ к значениям, которые пользователь выбрал в качестве ролей, вам просто нужно сделать это в вашей пользовательской модели:
self.input_roles.to_a # => ["admin", "developer", "guest"] If the user selected all roles
Теперь вы можете сделать все виды проверки с этой информацией! Надеюсь это поможет! Если кто-нибудь знает более чистый способ сделать это, пожалуйста, дайте мне знать. Я просмотрел все, на что мог наткнуться, и ответа не было. По крайней мере с этим проверки выполняются внутри модели, а не контроллера.