Build a Twitter Clone With Adonis and Vue

Update User Profile

From time to time users might want to update their profile due to a reason or the other. As it stands now, the Tweetr app doesn't have that functionality. Let's add it in. Updating user's profile is going to be of two parts. First, we need to get the details of the currently authenticated user (user that wants to update his/her profile) from the database. These details will be used to pre-populate the profile edit form on the client-side. The second part is where the actual updating of user's profile is handled.

Add the code below to start/routes.js:

// start/routes.js

Route.group(() => {
    Route.get('/me', 'UserController.me')
    Route.put('/update_profile', 'UserController.updateProfile')
})
    .prefix('account')
    .middleware(['auth:jwt'])

Here we define a group route with a account prefix. This means the routes will be accessible as /account/me and /account/update_profile respectively. This will save us some key strokes when defining user account related routes. As you can see, we also add the auth middleware.

Next, let's add the me method to UserController:

// app/Controllers/Http/UserController.js

async me ({ auth, response }) {
    const user = await User.query()
        .where('id', auth.current.user.id)
        .with('tweets', builder => {
            builder.with('user')
            builder.with('favorites')
            builder.with('replies')
        })
        .with('following')
        .with('followers')
        .with('favorites')
        .with('favorites.tweet', builder => {
            builder.with('user')
            builder.with('favorites')
            builder.with('replies')
        })
        .firstOrFail()

    return response.json({
        status: 'success',
        data: user
    })
}

The currently authenticated user is available with the auth as auth.current.user, so it's the result of a query on the users table for where the ID matches that of the currently authenticated user. Calling the firstOrFail method will return the first user that matches the where clause and return an error if the ID supplied was not found in the database. In addition to getting the user's details, we also get the user's tweets, followers, users following and favorites the user has made by chaining the with method. The with method uses the relations (tweets, followers, following and favorites) we defined in the previous section.

The with method accepts a callback as it second argument. This is used to add runtime constraints to the relationship.

.with('tweets', builder => {
    builder.with('user')
    builder.with('favorites')
    builder.with('replies')
})

With this, we eager load the tweet's relations also.

Adonis's Lucid also support eager loading nested relations with help of *dot notation(.) *. That why we can do with('favorites.tweet). This simply means to load all the favorites with their related tweet.

.with('favorites.tweet', builder => {
    builder.with('user')
    builder.with('favorites')
    builder.with('replies')
})

We also pass a callback to load the tweet's relations. It is important to note that passing a callback to with for a nested relationship is applied to the last relation (in this case, tweet).

Next, let's add the method that will do the actual updating of user details. Add the code below to UserController:

// app/Controllers/Http/UserController.js

async updateProfile ({ request, auth, response }) {
    try {
        // get currently authenticated user
        const user = auth.current.user

        // update with new data entered
        user.name = request.input('name')
        user.username = request.input('username')
        user.email = request.input('email')
        user.location = request.input('location')
        user.bio = request.input('bio')
        user.website_url = request.input('website_url')

        await user.save()

        return response.json({
            status: 'success',
            message: 'Profile updated!',
            data: user
        })
    } catch (error) {
        return response.status(400).json({
            status: 'error',
            message: 'There was a problem updating profile, please try again later.'
        })
    }
}

Again, we get the details of the currently authenticated user, then update them with the data from the form. Then we persist the changes to the database. Finally, we return a JSON object with a success message and the user details. If there was a problem updating the user's profile, we return a message telling them to try again later.