Allow only certain possible values โ€‹โ€‹in Rails Strong Parameters

I have a rails application with a custom model that can have multiple roles. I implemented this with a bitmask:

class User < ActiveRecord::Base DEFAULT_ROLES = %w[developer entrepreneur] ROLES = ['admin', 'entrepreneur', 'developer'] def has_role?(role) roles.include?(role.to_s) end def is?(role) has_role?(role) end def roles=(roles) self.roles_mask = (roles & ROLES).map { |r| 2**ROLES.index(r) }.inject(0, :+) end def roles ROLES.reject do |r| ((roles_mask.to_i || 0) & 2**ROLES.index(r)).zero? end end end 

On the application registration page, I want users to choose whether they are an "entrepreneur" or a "developer." However, I want to make sure that they cannot assign themselves (or anyone else) any other role if they are no longer an administrator.

My first thought was to do this in the roles= method, changing it to look like

  def roles=(roles) unless current_user.is?(:admin) validates_inclusion_of roles, :in => DEFAULT_ROLES end self.roles_mask = (roles & ROLES).map { |r| 2**ROLES.index(r) }.inject(0, :+) end 

However, as I found out, you cannot access current_user from within the model (which, I think, makes sense if you think about it ...)

My next attempt was to see if I could do this using Strong options .

I expected it to look something like this (I use devise, overriding RegistrationsController)

 class RegistrationsController < Devise::RegistrationsController private def sign_up_params if (user_signed_in?) && (current_user.is?(:admin)) params.require(:user).permit(:name, :school, :email, :password, :password_confirmation, {roles: User::ROLES}) else params.require(:user).permit(:name, :school, :email, :password, :password_confirmation, {roles: User::DEFAULT_ROLES}) end end def account_update_params if (user_signed_in?) && (current_user.is?(:admin)) params.require(:user).permit(:name, :school, :email, :password, :password_confirmation, :current_password, :about_me, {roles: User::ROLES}) else params.require(:user).permit(:name, :school, :email, :password, :password_confirmation, :current_password) end end end 

However, when I tried this, I got the following: enter image description here which makes me think that I donโ€™t understand how strong parameters work.

Is it possible to limit what values โ€‹โ€‹a user can enter for any given field based on this user role using strong parameters? If not, is there any other way to do this?

+6
source share
1 answer

I realized this is how I did it. (This method overrides the Devise RegistrationController if you are not using devise, and then simply replace any method that determines which parameters are entered for the new user.)

 class RegistrationsController < Devise::RegistrationsController private def sign_up_params parameters = params.require(:user).permit(:name, :school, :email, :password, :password_confirmation, :about_me, roles: []) unless (user_signed_in?) && (current_user.is?(:admin)) parameters[:roles] = parameters[:roles].reject { |h| !User::DEFAULT_ROLES.include? h } parameters end end def account_update_params if can? :assign_roles, :all params.require(:user).permit(:name, :school, :email, :password, :password_confirmation, :current_password, :about_me, roles: []) else params.require(:user).permit(:name, :school, :email, :password, :password_confirmation, :current_password) end end end 

I simply filtered the parameter in the [: role] parameters to include only the values โ€‹โ€‹contained in User::DEFAULT_ROLES (shown above in the question), and then returned the parameters object.

+6
source

Source: https://habr.com/ru/post/982013/


All Articles