Search code examples
reactjscasl

How to pass a plain object to the permissions of CASL (React)


How to pass a condition to the <Can /> component which is matched with condition in the ability object.

The AbilityBuilder which exposes permissions to my app:

AbilityBuilder.define((can, cannot) => {
  cannot('delete', 'user', { role: 2 }) // <- 2
});

The component which should render a paragraph.

<Can I="delete" a="user" of={{ role: 1 }}>
    <p>Should be visible</p> 
</Can>

How I can pass an object instead of instance of a class? I have not found any information about that :(


Solution

  • This is the common misunderstanding of how to use CASL. Neither ability.can nor React's <Can> does not support such behavior.

    What you need to do instead is to understand what the subject name is and how CASL detects subject name based on passed in ability.can object. This is explained in documentation: https://stalniy.github.io/casl/abilities/2017/07/21/check-abilities.html#instance-checks

    Also please read https://github.com/stalniy/casl/issues/59 if information in documentation is not enough.

    Also check the example app https://github.com/stalniy/casl-react-example (there is a link to codesanbox, so you can quickly play around with it). Todo app uses similar usecase which you need to implement in your app.

    Finally, I created a separate ehancement https://github.com/stalniy/casl/issues/192, so others will receive an error message with explanation about wrong usage and link to documentation.

    Basically you need to define own subjectName detection function, and pass user as this:

    <Can I="delete" this={{ role: 1, __typename: 'user' }}>
        <p>Should be visible</p> 
    </Can>
    

    Update: typename should be a part of object instance in order to prevent collisions (e.g., when objects look the same or similar but have different types). The easiest way to keep consistency between object types and their instances is to use classes. But there other approaches as well, for example GraphQL has __typename field which tells client the object type received from server

    Update 2: by default Ability forbids to do everything, so your AbilityBuilder can't contain only forbidden rules. You need at least one rule that allows something to do.