I'm building a school systems where instructors can manage classrooms in scope of their respective schools.
I have the following ability setup to match:
class Ability
include CanCan::Ability
#define the user ability
def initialize(user)
user ||= User.new # guest user (not logged in)
if user.has_role? :instructor
can :manage, Classroom do |classroom|
classroom.new_record? && classroom.school_id == user.school_id || classroom.instructor == user
end
end
end
end
In theory this should enable instructors to manage new records which won't have their relationship with the instructor setup so long as both the instructor and the new classroom belong to the same school.
In my classroom new action I build the classroom from the parent School to accommodate this @classroom = @school.classrooms.build
. This initializes the new Classroom record with a school_id enabling the instructor to to thereby manage the record. However in my classrooms controller I call load_and_authorize_resource
which authorizes the instructor before the school to classroom relationship gets established and a CanCan authorization exception is thrown.
Is there any way around this?
CanCan is probably checking abilities before the association with the school is built. You could break out the create and manage permissions explicitly:
can :create, Classroom
can :manage, Classroom, instructor_id: user.id
and then check that the classroom belongs to the instructor's school in a validation.