6

Ho un'app per rotaie con un modello utente, che è in grado di avere diversi ruoli. Ho implementato questo utilizzando una maschera di bit come questo:Permette solo determinati valori possibili nei parametri Rails Strong

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 

Nella pagina di registrazione per l'applicazione, voglio agli utenti di scegliere se si tratta di un 'imprenditore' o un 'sviluppatore'. Tuttavia, voglio assicurarmi che non siano in grado di assegnare a se stessi (o a nessun altro) nessun altro ruolo, a meno che non siano già amministratori.

Il mio primo pensiero è stato quello di fare questo nel metodo roles= da changin per assomigliare

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 

Tuttavia, come ho scoperto, non è possibile accedere current_user dall'interno di un modello (che immagino marche senso se ci pensate ...)

Il mio prossimo tentativo era di vedere se potevo farlo usando Strong Parameters.

mi aspettavo che sarebbe simile a questa (sto usando ideare, ignorando l'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 

Tuttavia, quando ho provato, ho ottenuto questo: enter image description here che mi fa pensare che' Mi fraintendimento di come Strong Parameters funzioni davvero.

È possibile limitare i valori che un utente può immettere per un determinato campo in base al ruolo degli utenti con i parametri forti? Se no, c'è un modo diverso per farlo?

+0

Dovrebbe essere definito come convalida del modello. Un parametro forte è per filtrare le chiavi param, non i valori. – kengo

+0

@kengo - Come posso convalidarlo nel modello se non riesco ad accedere al ruolo utente corrente? (poiché gli amministratori potrebbero modificare altri utenti, non solo loro stessi) – Ephraim

+0

Non è possibile definire un parametro forte come before_action. Utilizzare in questo modo nel metodo di creazione o aggiornamento. Account.new (account_update_params) – kengo

risposta

6

L'ho capito, ecco come l'ho fatto. (Questo è il metodo override del Devise RegistrationController, se non si sta usando ideare, quindi è sufficiente sostituire qualsiasi metodo controlla quali parametri siano immessi in un nuovo utente.)

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 

Ho appena filtrati il ​​parametro nei parametri [: ruoli] per includere solo i valori contenuti in User::DEFAULT_ROLES (mostrato sopra nella domanda), quindi restituito l'oggetto parameters.

+0

Sì, i parametri sono modificabili (l'hai ordinato prima che potessi tornare a te) . – railsdog