I'm using Quasar ^2.0.0 and Vue 3.2.22. I'm using "@casl/vue" and "@casl/ability" for permissions. I'm having trouble updating an existing ability. The idea is to be able to update the app's ability based on a user role received after authentication. When I try to use the update method to update my rules, I get this error:
Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'm')
Here's where I'm attempting to make the update (post-authentication).
import { AbilityBuilder, Ability } from "@casl/ability";
import { useAbility } from "@casl/vue";
const { update } = useAbility();
function updateAbility() {
const { rules, can, cannot } = new AbilityBuilder(Ability);
can(["read", "update", "create", "delete"], "Notes");
cannot("read", ["Photos", "Videos", "Users", "Files"]);
update(rules);
}
// Eventually updateAbility will receive a `user` that contains one of several possible roles
onMounted(async () => {
await onAuthStateChanged(auth, async (user) => {
...
updateAbility();
...
});
});
If I comment out the above updateAbility, I'm able to successfully use can elsewhere in the application based on the configuration in my boot file.
import { useAbility } from "@casl/vue";
const { can } = useAbility();
console.log(can("create", "Videos")); // returns false as expected
casl.js (boot file)
import { boot } from "quasar/wrappers";
import ability from "src/services/ability";
import { abilitiesPlugin } from "@casl/vue";
export default boot(({ app }) => {
app.use(abilitiesPlugin, ability);
app.config.globalProperties.$ability = ability;
});
ability.js
import { defineAbility } from "@casl/ability";
export default defineAbility((can, cannot) => {
cannot(["read", "update", "create", "delete"], "Notes");
can(
["read", "update", "create", "delete"],
["Photos", "Videos", "Users", "Files"]
);
});
I don't know what's causing this error. Any help would be appreciated!
The solution was actually to use
createMongoAbilityalongsideAbilityBuilder. Unfortunately, the documentation for CASL/Vue is a bit out of date. The key concepts I needed to learn were:useAbilitycomposition hook actually returns the full global PureAbility instance, which includes thecanandupdatemethods.AbilityBuilderinstance provides arulesarray that contains all the rule information needed to update the ability.canorcannotmethods provided byAbilityBuilderautomatically updates itsrulesarray. You can define any rules you want and simply pass therulesarray to your global PureAbility instance using itsupdatemethod.Note: The
canandcannotmethods on theAbilityBuilderare not the same as thecanmethod on the PureAbility instance. This confused me. The former define the rules, and the latter checks them.