Ready to get started?

Join Adocasts Plus for $8.00/mo, or sign into your account to get access to all of our lessons.

robot mascot smiling

Onboarding Newly Registered Users

In this lesson, we'll create our onboarding flow for newly registered users. Before users can enter the application, they'll need to have at least one organization set up so everything works smoothly.

Published
Oct 11, 24
Duration
22m 31s

Developer, dog lover, and burrito eater. Currently teaching AdonisJS, a fully featured NodeJS framework, and running Adocasts where I post new lessons weekly. Professionally, I work with JavaScript, .Net C#, and SQL Server.

Adocasts

Burlington, KY

Get the Code

Download or explore the source code for this lesson on GitHub

Repository

Chapters

00:00 - Our End Goal
00:45 - Setting Up Our Organization Create Route & Controller
03:15 - Defining The Organization Create Page
06:18 - Storing A New Organization
10:02 - Making the User An Organization Admin
12:18 - Stubbing the Organization with Default Difficulties, Statuses, & Access Levels
16:38 - Managed Transactions & Improving our Promise Flow
18:40 - Calling Our Store Organization Action
19:38 - Redirecting New Users to our Onboarding Page
20:00 - Testing It Out

Ready to get started?

Join Adocasts Plus for $8.00/mo, or sign into your account to get access to all of our lessons.

Join The Discussion! (4 Comments)

Please sign in or sign up for free to join in on the dicussion.

  1. Commented 25 days ago

    Hello,
    In this video, you are using a transaction with db.transaction.
    You apply the transaction to the await Organization.create().
    However, for this.#assignAdmin and this.#createDefaults, you are not directly using it. Yet, these two calls are included in the callback function.
    If an issue occurs in assignAdmin or createDefaults, will the transaction still perform a rollback? Or will these two functions not trigger a rollback?

    1

    Please sign in or sign up for free to reply

    1. Commented 25 days ago

      Hi Tigerwolf!

      Lucid cascades the transaction to relationship operations for us! So, when we attach the transaction to the operation that creates the organization, the transaction reference will be kept in the organization instance.

      return db.transaction(async (trx) => {
        const organization = await Organization.create(data, { client: trx })
        
        organization.$trx // 👈 holds the transaction
      
        // ...
      })
      Copied!

      This transaction reference is then automatically used when we perform subsequent operations with this organization, which includes related operations.

      return db.transaction(async (trx) => {
        const organization = await Organization.create(data, { client: trx })
        
        // 👇 passes $trx on the organization along with the attach db operation
        return organization.related('users').attach({
          [user.id]: {
            role_id: Roles.ADMIN,
          },
        })
      
        // ...
      })
      Copied!

      The managed transaction, then, wraps the callback within a try/catch block. The transaction is committed if the callback completes and no errors are thrown. Otherwise, if an error is caught, the transaction is rolled back. Essentially doing the below for us in a nicer syntax.

      const trx = await db.transaction()
      
      try {
        const organization = await Organization.create(data, { client: trx })
        
        // 👇 passes $trx on the organization along with the attach db operation
        return organization.related('users').attach({
          [user.id]: {
            role_id: Roles.ADMIN,
          },
        })
      
        // ...
      
        await trx.commit()
      } catch (error) {
        await trx.rollback()
      }
      Copied!

      So, as long as we don't eat the errors thrown by the operations we're performing, the managed transaction will catch it and roll back our transaction. This is regardless of how we structure our code within the managed transaction, including splitting it into additional methods.

      So, to answer your question, If an issue occurs in assignAdmin or createDefaults the managed transaction will catch this and roll back our transaction for us! You can see this for yourself by trying to assign the user a role_id that doesn't exist. Since we're using a foreign key constraint here, attempting to do so will throw an error.

      static async #assignAdmin(organization: Organization, user: User) {
        return organization.related('users').attach({
          [user.id]: {
            role_id: 45, //Roles.ADMIN, // 👈 replace admin with some non-existant id
          },
        })
      }
      Copied!
      1

      Please sign in or sign up for free to reply

      1. Commented 21 days ago

        Thank you, I had missed that information in the documentation. My English level is not very high, so there is some information that I sometimes overlook.
        Thank you very much for this detailed and illustrated response.

        1

        Please sign in or sign up for free to reply

        1. Commented 21 days ago

          Anytime and no worries at all! That's completely understandable!! 😊

          0

          Please sign in or sign up for free to reply