2017-09-06 21 views
2

J'utilise actuellement Devise, CanCan et Rolify pour gérer l'authentification et l'autorisation de mon application rails et j'ai du mal à comprendre comment le faire qu'un user peut uniquement :show et :update une instance spécifique d'un modèle auquel appartient l'utilisateur (alias mon user a une colonne client_id, et non l'inverse).CanCanCan afficher uniquement l'instance du modèle auquel l'utilisateur appartient

La partie mise à jour de mon défini Abilities.rb pour le user avec le rôle :client, fonctionne très bien, à savoir si current_user.client_id = 3 alors il ne peut mettre à jour un client où Client.id = 3, cependant, ce même utilisateur peut voir une instance du modèle Client et je ne peut pas sembler saisir comment limiter cela.

Ability.rb

... 
if user.has_role? :client 
    can [:read, :update], [Property, Order], client_id: user.client_id 
    can [:read, :update], Owner 
    can :create, [Property, Order, Owner] 
    can :manage, User, id: user.id 
    can [:show, :update], Client, id: user.client_id 
end 
... 

Chaque utilisateur ne dispose pas d'un index de tous Clients, donc après la recherche que j'ai changé can [:read, :update], Client, ..-:show mais les utilisateurs peuvent toujours voir l'autre clients mais la partie :update si elle fonctionne bien , donc je suis vraiment perdue ici. Je fais des recherches sur Google depuis quelques heures et je lis toute la documentation de CanCan dont je reconnais qu'elle a peut-être été traitée, mais je n'arrive pas à comprendre.

J'ai essayé limiter du côté du contrôleur comme indiqué ci-dessous, mais cela ne fonctionne pas non plus:

external/clients_controller.rb

class External::ClientsController < ApplicationController 
    load_and_authorize_resource 
    before_filter :client_only 

    def index 
    @clients = Client.paginate(page: params[:page], per_page: 15) 
    end 

    def show 
    @clients = Client.find(params[:id]) 
    @client_users = User.where(client_id: params[:id]) 
    @client_orders = Order.where(client_id: params[:id]).includes(:property, :owners) 
    can? :show, @clients 
    end 

    def edit 
    @clients = Client.find(params[:id]) 
    respond_to do |format| 
     format.html { @clients.save } 
     format.js 
    end 
    end 

    def update 
    @clients = Client.find(params[:id]) 
    @clients.update_attributes(client_params) 
    respond_to do |format| 
     format.html { if @clients.save 
         flash[:success] = "Client Updated Successfully" 
         redirect_to client_path(@clients) 
        else 
         render 'edit' 
        end 
     } 
     format.js 
    end 
    end 

    private 

    def client_params 
    params.require(:client).permit(:uuid, :company, :first_name, :last_name, :phone, :email, :address1, :address2, :city, :state, :zip, :notes) 
    end 

    def client_only 
    redirect_to root_path unless current_user.is_client? 
    end 

end 

Donc, si quelqu'un pouvait me aider à bien comprendre comment les poignées Cancan autorisation basée sur le rôle pour une instance d'un modèle alors je l'apprécierais grandement. Merci d'avance!

code mis à jour

Removed toutes les charges d'instance @client dans external/clients_controller.rb

class External::ClientsController < ApplicationController 
    load_and_authorize_resource 
    before_filter :client_only 

    def show 
    @client_users = User.where(client_id: params[:id]) 
    @client_orders = Order.where(client_id: params[:id]).includes(:property, :owners).paginate(page: params[:page], per_page: 15).order("order_number DESC") 
    end 

    def edit 
    respond_to do |format| 
     format.html 
     format.js 
    end 
    end 

    def update 
    if params[:client][:state].blank? 
     params[:client][:state] = @client.try(:state) 
    end 
    @client.update_attributes(client_params) 
    respond_to do |format| 
     format.html { if @client.save 
         flash[:success] = "Client Updated Successfully" 
         redirect_to external_client_path(@client) 
        else 
         render 'edit' 
        end 
     } 
     format.js 
    end 
    end 

    private 

    def client_params 
    params.require(:client).permit(:uuid, :company, :first_name, :last_name, :phone, :email, :address1, :address2, :city, :state, :zip, :notes) 
    end 

    def client_only 
    redirect_to root_path unless current_user.is_client? 
    end 

end 

plein ability.rb

class Ability 
    include CanCan::Ability 

    def initialize(user) 
    alias_action :show, :to => :view 
    alias_action :open_external_orders, :completed_external_orders, :to => :client_order_views 

    user ||= User.new 
    if user.has_role? :admin 
     can :manage, :all 
     can :assign_roles, User 
    else 
     can :read, :all 
    end 

    if user.has_role? :executive 
     can :manage, [Property, Deed, Mortgage, Order, Owner, Client, AttachedAsset, User] 
     cannot :assign_roles, User 
    end 

    if user.has_role? :management 
     can :manage, [Property, Deed, Mortgage, Order, Owner, Client, AttachedAsset] 
     can :read, User 
     can :manage, User, id: user.id 
     cannot :destroy, [Property, Order, Client, User] 
    end 

    if user.has_role? :analyst 
     can :manage, [Property, Deed, Mortgage, Order, Owner, Client, AttachedAsset] 
     can :manage, User, id: user.id 
     cannot :destroy, [Property, Order, Client, User] 
    end 

    if user.has_role? :it 
     can :manage, [Property, Deed, Mortgage, Order, Owner, Client, AttachedAsset] 
     can :manage, User, id: user.id 
     can :read, User 
     cannot :destroy, [Property, Order, Client, User] 
    end 

    if user.has_role? :client 
     can [:read, :update], Client, id: user.client_id 
     can [:read, :update, :client_order_views], [Property, Order], client_id: user.client_id 
     can [:read, :update], Owner 
     can :create, [Property, Order, Owner] 
     can :manage, User, id: user.id 
    end 
    end 
end 
+0

Quelques choses d'abord: la variable '@ clients' dans les méthodes est en fait un' @ client', n'est-ce pas? (singulier, pas pluriel, s'il vous plaît changer cela), deuxième: ceci est déjà chargé via 'load_and_authorize_resource', alors pourquoi le recharger? Pouvez-vous également poster le reste de votre capacité.rb? merci – coorasse

+0

J'ai effectivement remarqué qu'en passant par les docs la nuit dernière, j'avais déjà construit la plupart des contrôleurs et tel avant que j'implémente CanCan et je suppose que je n'ai jamais changé, mais l'ai fait maintenant. J'ai parcouru toutes mes vues et changé '@ clients' en' @ client' et j'ai posté ma mise à jour 'external/clients_controller.rb' ainsi que mon full' ability.rb'. Merci de m'avoir aidé. –

+0

Vous avez une règle qui stipule qu'un utilisateur 'peut: read,: all' si ce n'est pas un admin. Cela permettra à tous les utilisateurs non administrateurs de lire tous les modèles. – coorasse

Répondre

1

CanCanCan fonctionne avec des "autorisations" de plus en plus. Chaque règle peut augmenter la précédente.

Si vous écrivez:

can :show, User 
can :edit, User 

les deux autorisations seront jointes et vous serez en mesure de montrer et de modifier un utilisateur.

Dans votre capacité.rb vous définissez can :read, :all vous accordez des autorisations pour lire (afficher et indexer) sur tous les objets.

Je vous suggère d'écrire votre fichier de capacités selon le concept de "permisssions croissante".Cela signifie que vous ne commencez pas à définir la capacité pour l'administrateur, mais que vous le faites à la fin, en ajoutant les capacités dont un administrateur a besoin à celles que vous avez déjà données à tout le monde.

+0

Ahhh J'aime cette idée, j'ai semi-saisi le concept avant mais en mettant 'peut ...' puis 'ne peux pas ..' après, mais je pensais qu'il était contenu dans chaque bloc 'user.has_role?' Alors merci pour effacer cela et pour les suggestions. –