Rolify:验证用户模型中具有复杂功能的角色

Rolify: Validate roles with complex functionality inside the User model

我已经花了四天时间尝试实现此角色验证但没有成功,而且我不知道目前是否有任何方法可以使用 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

第三:如果记录通过所有验证,创建用户,然后在注册中分配角色#new action

我认为这种方法可行,但我现在对虚拟属性有一些问题,它似乎与从表单接收的角色参数没有关联。我想我还是不明白虚拟属性是如何工作的,所以我希望有人能在这方面解决我的问题。

我明白了!我在更新中添加的过程是正确的,所以我将简要介绍如何正确实现这一点。

Objective: 在用户模型中验证 rolify 的复杂功能。这必须在用户模型中完成,因为必须检查所有添加的角色,而不是每个角色

第一步: 如果您的应用程序要使用的角色是静态的,那么您必须首先使用特定角色填充您的角色 table。为此,我将在 Stack Overflow 中的另一个问题中留下一个 post 来深入解释这个过程:

第二步:修改您的注册表。为了获得用户选择的角色,我们必须首先添加一些与第一步定义的角色相对应的复选框。这是一个简单的代码。

<%= 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 => [] }}

重要提示!如果用户没有select任何角色,那么变量input_roles将不会被定义!您必须在验证中检查这一点。 此外,请勿将变量的名称更改为 roles,我犯了这个错误,并且竭尽全力修复我遇到的所有错误。如果有兴趣查看我经历的一切,这里是 link 我创建的问题:

https://github.com/RolifyCommunity/rolify/issues/446

第三步: 由于要向表单添加新参数,因此还必须将其包含在强参数中。由于这个变量是一个数组,你必须在你的强参数中明确定义它:

如果您使用的是 Devise:

devise_parameter_sanitizer.permit(:sign_up, keys: [:email, :password, :password_confirmation, input_roles: [])

如果您没有使用设计:

params.require(:user).permit( :email, :password, :password_confirmation, input_roles: [])

第四步: 好的,现在 input_roles 参数被传递到我们的 User 模型中。但是,现在我们需要找到一种方法来验证内部的值。由于此参数不是我们用户模型的一部分,因此我们必须创建一个虚拟属性才能使用此参数。所以我们只是将其命名为与传递给模型的参数相同的名称,如下所示:

Class User < ApplicationRecord
rolify
attr_accessor :input_roles

现在,当您想要访问用户已 select 作为角色设置的值时,您只需在用户模型中执行此操作:

self.input_roles.to_a # => ["admin", "developer", "guest"] If the user selected all roles

现在您可以使用这些信息进行各种验证!希望这可以帮助! 如果有人知道更清洁的方法,请告诉我。我查看了我可能偶然发现的所有内容,但没有给出任何答案。至少,验证是在模型内部完成的,而不是控制器。