Skip to main content

filter child record by the parent.

Rails • Asked by Francisco Quinones

Info: My models and association. I got a ServiceUser ( Manager ) model,User model, ServiceCompany model, Employee model and a Project model. A ServiceCompany can have many projects, employees and many ServiceUSer. A ServiceUser can be assign to a project and employees work at a project. Im using devise for authentication and cancan.
Models: https://gist.github.com/Frank004/c578864985b77fe284d4
Second info: My routes

    resources :service_companies, shallow: true do
    resources :service_users
    end
    resources :projects, shallow: true do
    resources :employees
    end

My problem: I got different companies and each one has his projects with different employees on each project. I can filter the project of the current user as a (client or as a manager). my problem start in the url anybody can change the ids of companies, projects or employees and view info from the other company. employee controller: https://gist.github.com/Frank004/b013218c4d4103a7ee55

Im looking for a way to only allow the information of the current project that is view and if he change the ids it wont show the other projects or parts of the projects like the employees list.

Im trying to find a way to get the project
@project and then filter the employees by the project



The best way to handle that is authorization with Pundit. You can load up the project and verify if the current user has access to the project based upon the associations set. They will be able to change the ID in the url, but Pundit will throw an error if they try to access one they aren't a part of. Here's an episode on Authorization With Pundit that I did a while back.


can I do the same with cancan as I got all working and setup. Thanx


Absolutely can. I'm a fan of Pundit over CanCan, but choose whichever one you are more comfortable with.


How can I do this achive this with cancan at the moment. I like to move to pundit but have to get this setup as fast as I can.

This my ability file

      class Ability
      include CanCan::Ability


      def initialize(user)
        #-----------------------------------------------------------------
        if user.role == "super_admin"
          can :manage, [ServiceCompany,User] #,:dashboard]
          cannot :manage,[ClientCompany,Company,Project,Employee,Inspection,InspectionSection,
            InspectionComponent,Section,Reply,ServiceUser,ClientUser,TaskArea,TaskSection,TaskItem,Accident,
            Incident,Training,Workorder,Turnover,:help,:project_report,:report,Complaint,Payroll]
          #-----------------------------------------------------------------
        elsif user.role == "admin"
          can :manage, [ClientCompany,Company,Employee,Inspection,InspectionSection,InspectionComponent,Section,Reply,ServiceUser,ClientUser,TaskArea,TaskSection,TaskItem,:help]
          can :manage,[Project]
          can [:read,:index,:destroy,:edit,:update,:create], [Accident,Incident,Training,Workorder,Turnover,Payroll]
          # can [:read,:index], Payroll
          can [:read,:edit,:update,:remove_photo], ServiceCompany
          can [:read,:edit,:update,:index,:destroy],Complaint
          can [:index,:trainings,:inspections_total,:workorders,:incidents,:accidents,:turnovers],:project_report
          can [:index,:trainings,:inspections],:report
          can :read, ServiceCompany
          #---------Cannot----------
          cannot :index, ServiceCompany
          #-----------------------------------------------------------------
        elsif user.role == "auditor"
          can [:read, :index], [Project,Complaint,:project_report,:report,:help]
           #---------Cannot----------
          cannot :index, ServiceCompany
          #-----------------------------------------------------------------
        elsif user.role == "cliente"
          can [:create, :read, :index], [Complaint,Reply]
          can [:show], [ClientCompany]
          cannot :index, ClientCompany
          cannot :index, InspectionSection
          can [:index,:inspections],:report
          can [:index,:read,:detail], Inspection
          can [:report_table], InspectionSection
          can [:index,:trainings,:inspections_total,:workorders,:incidents,:accidents,:turnovers],:project_report
          can [:read, :index], [Project,:help]
          #---------Cannot----------
          cannot :index, ClientCompany
          #-----------------------------------------------------------------
        elsif user.role == "gerente"
          can [:create,:read,:update,:destroy,:edit,:signature,:detail], [Accident,Incident,Training,Workorder,Turnover,Inspection,InspectionComponent,Reply,Payroll,Employee]
          can [:create,:read,:update,:destroy,:edit,:report_table],InspectionSection
          can [:index,:show],[Project,TaskArea,TaskSection,ClientCompany,:help]
          can [:index,:trainings,:inspections_total,:workorders,:incidents,:accidents,:turnovers],:project_report
          can [:index,:trainings,:inspections],:report
          can [:read,:index,:edit,:update], [TaskItem,Complaint]  
          can :read, ServiceCompany
          #---------Cannot----------
          cannot :index, ServiceCompany
          #-----------------------------------------------------------------
        else user.role == "administración"
            can [:index,:show,:read,:signature,:detail],[ClientCompany,Company,Project,Employee,Inspection,
            InspectionComponent,Section,Reply,ServiceUser,ClientUser,TaskArea,TaskSection,TaskItem,Accident,Incident,Training,
            Workorder,Turnover,:help,Payroll]
            can [:index,:show,:read,:report_table], InspectionSection
            can [:index,:trainings,:inspections],:report
            can [:index,:trainings,:inspections_total,:workorders,:incidents,:accidents,:turnovers],:project_report
            can [:create, :read, :index], Reply
            can [:edit,:update,:read, :index],Complaint
            can :read, ServiceCompany
            #---------Cannot----------
            cannot :index, ServiceCompany
        end
      end
    end

You'll need to use a block and filter by the ID in the user's list.

This isn't exactly what you'll need, but this is one way of checking if a project is in the user's associated list. You can modify this for your authorization.

can :manage, Project do |project|
  user.projects.map(&:id).include? project.id
end

And here's more information on this: https://github.com/ryanb/cancan/wiki/Defining-Abilities-with-Blocks


thank you ill look at it :)


Thank I found a way to do it but its going to make the file to big can I create some tipe of partical like??
So I can clean the class ability
example:

class Ability
  include CanCan::Ability
  include super_admin_ability
  def initialize(user)
    if user.role == "super_admin"
      super_admin_ability
    end
  end 
end

Class SuperAdminAbility
    def super_admin_ability
      can :manage, [ServiceCompany,User]
    end
end

That's exactly what I do. Mine is a little different, but just make sure you return a class that inherits from CanCan::Ability and you'll be fine.

module Abilities
  def self.ability_for(user)
    if user
      if user.admin?
        AdminAbility.new(user)
      elsif user.editor?
        EditorAbility.new(user)
      elsif user.member?
        MemberAbility.new(user)
      end
    else
      GuestAbility.new
    end
  end
end

wow super this a big step for me. thank you for your time. next Multitenancy.


Awesome! I'm glad I could be of help! :)


Login or Create An Account to join the conversation.

Subscribe to the newsletter

Join 24,647+ developers who get early access to new screencasts, articles, guides, updates, and more.

    By clicking this button, you agree to the GoRails Terms of Service and Privacy Policy.

    More of a social being? We're also on Twitter and YouTube.