Skip to content

Commit 11bf5f4

Browse files
committed
docs: update usage
fix #29
1 parent 83279ac commit 11bf5f4

File tree

1 file changed

+53
-9
lines changed

1 file changed

+53
-9
lines changed

README.md

Lines changed: 53 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -126,16 +126,12 @@ Easy!
126126
### Define Abilities
127127

128128
> [!NOTE]
129-
> With the upcoming Nuxt4, you can store your abilities in the `app/utils/abilities.ts` file. Then, you can import them in your server folder using `~/utils/abilities`.
130-
> See an example with [the project Orion](https://github.com/Barbapapazes/orion/blob/main/app/utils/users/abilities.ts).
131-
132-
> [!NOTE]
133-
> With Nuxt4, a new `shared` directory will be introduced to easily share code between the client and the server.
134-
> See [the issue](https://github.com/nuxt/nuxt/issues/28675).
129+
> With Nuxt 4, a new `shared` directory will be introduced to easily share code between the client and the server.
130+
> See [the video from Alexander Lichter](https://youtu.be/_m5ct5e8nVo?si=2iNcPVMttlIq5fLR).
135131
136132
Now the resolvers are set up, you can define your first ability. An ability is a function that takes at least the user, and returns a boolean to indicate if the user can perform the action. It can also take additional arguments.
137133

138-
I recommend to create a new file `utils/abilities.ts` to create your abilities:
134+
I recommend to create a new file `shared/utils/abilities.ts` to create your abilities:
139135

140136
```ts
141137
export const listPosts = defineAbility(() => true) // Only authenticated users can list posts
@@ -145,7 +141,7 @@ export const editPost = defineAbility((user: User, post: Post) => {
145141
})
146142
```
147143

148-
If you have many abilities, you could prefer to create a directory `utils/abilities/` and create a file for each ability. Having the abilities in the `utils` directory allows auto-import to work in the client while having a simple import in the server `~/utils/abilities`.
144+
If you have many abilities, you could prefer to create a directory `shared/utils/abilities/` and create a file for each ability. Having the abilities in the `shared/utils` directory allows auto-import to work in the client while having a simple import in the server `~~/shared/utils/abilities`. **Remember that the shared folder only exports the first level of the directory.** So you have to export the abilities in the `shared/utils/abilities/index.ts` file.
149145

150146
By default, guests are not allowed to perform any action and the ability is not called. This behavior can be changed per ability:
151147

@@ -157,7 +153,7 @@ Now, unauthenticated users can list posts.
157153

158154
### Use Abilities
159155

160-
To use ability, you have access to 3 bouncer functions: `allows`, `denies`, and `authorize`. Both of them are available in the client and the server. _The implementation is different but the API is the same and it's entirely transparent the developer._
156+
To use ability, you have access to 3 bouncer functions: `allows`, `denies`, and `authorize`. Both of them are available in the client and the server. _The implementation is different but the API is (nearly) the same and it's entirely transparent the developer. On the server, the first parameter is the `event` from the handler._
161157

162158
The `allows` function returns a boolean if the user can perform the action:
163159

@@ -167,6 +163,14 @@ if (await allows(listPosts)) {
167163
}
168164
```
169165

166+
_For the server:_
167+
168+
```ts
169+
if (await allows(event, listPosts)) {
170+
// User can list posts
171+
}
172+
```
173+
170174
The `denies` function returns a boolean if the user cannot perform the action:
171175

172176
```ts
@@ -175,6 +179,14 @@ if (await denies(editPost, post)) {
175179
}
176180
```
177181

182+
_For the server:_
183+
184+
```ts
185+
if (await denies(event, editPost, post)) {
186+
// User cannot edit the post
187+
}
188+
```
189+
178190
The `authorize` function throws an error if the user cannot perform the action:
179191

180192
```ts
@@ -183,6 +195,12 @@ await authorize(editPost, post)
183195
// User can edit the post
184196
```
185197

198+
_For the server:_
199+
200+
```ts
201+
await authorize(event, editPost, post)
202+
```
203+
186204
You can customize the error message and the status code per return value of the ability. This can be useful to return a 404 instead of a 403 to keep the user unaware of the existence of the resource.
187205

188206
```ts
@@ -248,6 +266,32 @@ The `Bouncer` component offers a more flexible and centralized way to handle bot
248266
</Bouncer>
249267
```
250268

269+
All of these components accept a prop named `as` to define the HTML tag to render. By default, it's a renderless component.
270+
271+
```vue
272+
<Can
273+
:ability="editPost"
274+
:args="[post]"
275+
as="div"
276+
>
277+
<button>Edit</button>
278+
</Can>
279+
```
280+
281+
This will render:
282+
283+
```html
284+
<div>
285+
<button>Edit</button>
286+
</div>
287+
```
288+
289+
Instead of:
290+
291+
```html
292+
<button>Edit</button>
293+
```
294+
251295
## Contribution
252296

253297
<details>

0 commit comments

Comments
 (0)