Chapters
00:00 - Creating Our Files
00:50 - Defining Our Route, Controller, and Action
03:02 - Testing Our User Logout
03:32 - Adding Toast Messages
Join Adocasts Plus for $8/mo, or sign into an existing Adocasts Plus account, to get access to all of our lessons.
We'll hook up our logout user menu button to a POST route to logout an authenticated user.
00:00 - Creating Our Files
00:50 - Defining Our Route, Controller, and Action
03:02 - Testing Our User Logout
03:32 - Adding Toast Messages
What's the benefit of using actions instead of keeping that logic in the controllers? I personally would prefer to keep it in the controllers like I've seen in the docs as those additional directories seem a bit burdensome to me. What would I lose/gain from keeping that content which honestly seems fairly short inside my controllers?
I also understand the benefits of separating concerns, I'm just curious as to the reasoning to go down this extra level.
As a whole, by using actions you're:
Giving the operation a name & scope, which improves the ability to scan your controllers.
Gives us the ability to easily reuse the code if needed. It is considered bad practice to call one controller method from another, as controllers are meant to handle routes.
On top of reusability, if we need to update an operation later on, we only have to perform that update in one spot rather than each spot it is performed in the controllers.
As you said, it gives us a separation of concerns. If we're performing an action, we know we can find it within our actions folder, under the resource/section it is for.
Note that actions are very similar to services. To compare, you can think of each subfolder within actions
as a service class and each file within the subfolder as a service class method. The main difference here though is actions allow us to easily define steps within the actions whereas that'd need to be additional methods inside a service, which can make things a little messy.
A good example, though the code for this is from a future lesson releasing soon, is the account deletion controller & action. The controller is easy to scan. The operations have a designated location & scope and can make use of subactions. We're reusing our webLogout
method, meaning we can easily update just the webLogout
method if we ever need to adjust how we handle logouts. For example, if you're tracking user sessions, you might need to mark that session record in the database as logged out in addition to actually logging out the user.
@inject() async destroy({ request, response, session, auth }: HttpContext, webLogout: WebLogout) { const user = auth.use('web').user! const validator = vine.compile( vine.object({ email: vine.string().in([user.email]), }) ) await request.validateUsing(validator) await DestroyUserAccount.handle({ user }) await webLogout.handle() session.flash('success', 'Your account has been deleted') return response.redirect().toRoute('register.show') }
Copied!
I've worked with code, and written my fair share, where the controller method gets unwieldy large because all the operations are done directly in the controller. It might seem small at first, but requirements change, time gets crunched, and things slowly grow over time.
Hope this helps!
Thanks for that explanation. I got an idea in 5.3 of how large a controller could get with the StoreOrganization action lol