Rolify: Validate roles with complex functionality inside the User model

∥☆過路亽.° 提交于 2019-12-12 04:45:32

问题


I've spent four days trying to achieve this role validation with no success, and I don't know if there is currently any way to do this behaviour with rolify. Here's a simple example of the situation I am having:

Suppose I have 3 types of roles:

  • admin
  • developer
  • guest

A user can be both an admin and a developer, but cannot be also a guest.

A guest cannot be either an admin nor a developer.

I want the user to be able to set their roles on user registration, so I need to validate this behaviour before the user is created, and if it is not valid, the registration should fail and no user should be created.

I've read a lot of guides trying to achieve similar results, at least for the form submission, but there is no explanation about this type of validation.

Thanks in advance!

UPDATE: I've been searching for some ways to implement this, and this is the line of thought I've had during this time of struggles.

First: receive the roles selected as input and create a virtual attribute at the user model corresponding to this roles so that the params would look like this (simplified)

:params => { :user => {:email, :password, :roles => ["admin", "developer", "guest"]}}

if all roles are selected, and

:params => { :user => {:email, :password}}

if no role is selected.

Second: Do any type of validations with this virtual attribute(simplified)

Class User < ApplicationRecord
  attr_accessor :roles
  validate :roles_valid

  def roles_valid
    # Define custom validation
  end
end

Third: if the record passes all the validations, create user and then assign the roles inside the registrations#new action

I think this method would work, but I am now having some problems with the virtual attribute, and it is that it doesn't seem to be connected to the roles params being received from the form. I guess I still don't understand how virtual attributes work, so I wish someone would clear me out on this one.


回答1:


I got it now! The process I added in the update is correct, so I will make a brief guide on how to achieve this correctly.

Objective: validate complex functionality for rolify inside the User model. This must be done inside the User model because one must check all the roles being added, and not each individually

Step One: If the roles your app is going to use are static, then you must first populate your roles table with the specific roles. For this, I will leave a post from another question here in Stack Overflow that explains this process in depth:

Defining Roles with Rolify

Step two: modify your registration form. In order to get the roles the user has chosen, we must first add some checkboxes corresponding to the roles defined on step one. Here is a simple code for this.

<%= 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 %>

Doing this will generate all the checkboxes necessary, and store the result inside the variable

params => {:user => { :input_roles => [] }}

Important notes! if the user does not select any role, then the varialbe input_roles won't be defined! you must check for this in your validations. ALSO, DO NOT CHANGE THE NAME OF THE VARIABLE TO roles, I made this mistake and went through hell trying to fix all the errors I was getting. If interested on seeing everything I went through, here is a link to the issue I created:

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

Step three: Since you are adding a new parameter to the form, you must also include it inside your strong parameters. Since this variable is an array, you must explicitly define this inside your strong parameters:

In case you are using Devise:

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

In case you aren't using devise:

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

Step four: Ok, so now the input_roles param is being passed into our User model. But, now we need to find a way to validate the values inside. Since this parameter is not part of our User model, we must create a virtual attribute to be able to work with this parameters. So we just name it the same as the param being passed to the model, like this:

Class User < ApplicationRecord
rolify
attr_accessor :input_roles

Now when you want to access the values the user has selected as roles, you just have to do this in you User model:

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

Now you can do all sorts of validation with this information! Hope this helps! If anyone know of a cleaner way to do this, please let me know. I looked through everything I could stumble upon and no answer was given. At leaast with this the validations are done inside the model, instead of the controller.



来源:https://stackoverflow.com/questions/42963609/rolify-validate-roles-with-complex-functionality-inside-the-user-model

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!