00:00
(upbeat music)
00:02
So next we're gonna work on our user profiles.
00:06
We're gonna give them a page that lists out
00:08
all of the movies that they've watched
00:09
and it also will display their name
00:11
and biography information.
00:12
So first we need to give them the ability
00:14
to change their name and biography.
00:16
So we'll give them a little button right up here
00:17
that says something like edit profile.
00:19
So let's go ahead and hide our browser back away,
00:20
jump into our partials, nav,
00:22
and we'll put this behind our watch list.
00:23
We don't have a route for this made quite yet,
00:25
but we can go ahead and use the knowledge
00:27
that we have gained so far
00:28
to know that we're gonna call this route profiles.edit.
00:31
And a single authenticated user
00:33
is only ever gonna be able to edit their profile.
00:36
So we don't need to specify an ID in here.
00:38
Instead, we can just use the authenticated user
00:40
to pull which user is actually editing their profile.
00:43
And then we'll get our class text extra small,
00:46
add it on there.
00:47
And for the text, we'll do edit profile.
00:49
We'll give that a save
00:49
and that will temporarily result in an error in our browser
00:52
because this route currently does not exist.
00:53
So let's go ahead and create that
00:55
by jumping into our routes file.
00:56
And we'll put this at the end
00:58
of our application-based routes.
01:00
So right about here,
01:01
just above where we reach our authentication routes.
01:04
We'll do router.
01:05
And this will be a get
01:05
because we need a page to actually show the form.
01:07
A user only has one profile,
01:09
so we'll call the actual URL profile here, /edit,
01:12
as they're specifically going to be editing their profile.
01:15
For this, we'll use the profiles controller
01:17
that we created a while ago.
01:18
Hit tab to auto-import that.
01:19
And I don't think we stubbed any methods inside of it.
01:21
No, we didn't.
01:22
But we wanna use a method called edit for this.
01:24
And we'll give this a name of profiles.edit,
01:27
matching what we've added in our navigation.
01:29
Then we only want authenticated users to be able to use this.
01:32
So we'll do use middleware.andRequireAuthentication.
01:36
Give that a save.
01:37
And let's go add our edit method to our profiles controller.
01:40
So profiles controller.
01:42
Looks like it's empty at this moment.
01:43
So let's go ahead and uncomment our HTTP context import.
01:46
Async, edit.
01:47
We're gonna want our view and auth
01:49
out of our HTTP context.
01:51
And let's go ahead and grab our profile
01:53
as a separate entity.
01:54
So we'll do profile there equals auth user,
01:57
exclamation point to assert that we verify there is a user.
02:00
Related profile.query.firstOrFail.
02:03
And we also wanna await that call.
02:05
Now, during registration,
02:06
we should be creating a profile for our users.
02:09
However, at present, we are not doing that.
02:11
And this query assumes that we are doing that.
02:14
So in order to actually be able to make this assertion,
02:16
we're gonna need to verify that our user
02:17
is actually always going to have a profile
02:19
in our application.
02:20
So first, within our auth register controller,
02:23
we're gonna wanna create a profile for the user
02:25
in addition to creating the user.
02:27
So add an additional step here
02:29
as step three, create profile for user,
02:31
which makes our step three, step four,
02:33
and our step four, step five.
02:34
In a created profile,
02:35
all that we need to do is await user.relatedProfile.create.
02:40
And really the only thing that we have on our profile
02:42
that actually takes information is the description,
02:44
and that's nullable.
02:45
So we can just pass this an empty object
02:47
and it will be happy with that.
02:48
So that fixes our issue forward-looking.
02:50
But what about for users that already exist
02:51
inside of our application?
02:52
Well, why don't we jump into our terminal,
02:54
stop our application, clear that out,
02:56
node.ace.makeMigration,
02:58
and we'll call this addMissingUserProfiles.
03:01
We could, of course, just patch this in the database
03:03
ourselves relatively easily.
03:04
However, we wanna make sure that this change goes out
03:07
at the exact same time that our registration fix goes out
03:10
so that we don't have any people that sneak in between.
03:12
And we should always be running our pending migrations
03:14
as we're deploying out our application changes.
03:17
So by placing this change inside of a migration,
03:19
we kind of just give ourselves a way to make this change
03:22
at the same time that our registration fix goes out.
03:24
So let's run that.
03:25
Probably should have added alter to that, but that's okay.
03:27
We can change that name just slightly.
03:28
Scroll down, database, migrations.
03:30
I'm gonna go ahead and right-click on this, rename it,
03:32
and just remove the word create.
03:35
Okay, jump into that.
03:36
Now for this, unlike a traditional migration,
03:38
we're actually not gonna wanna perform
03:39
any of these actions against our database,
03:41
specifically for any tables.
03:43
So we can clear out our up and down.
03:44
And within our up method,
03:46
instead what we wanna do
03:47
is perform an action against our database.
03:48
So we can do this.
03:50
And use the defer method to make alterations
03:52
to our database as needed.
03:54
And this defer method is here to ensure
03:56
that if we were creating a table or something
03:58
in conjunction to this defer call,
03:59
that this defer runs after the up method has executed.
04:03
And it's provided a callback function
04:05
that gets our database query client.
04:07
We'll also wanna make that async.
04:08
And for this, we're gonna wanna get our users
04:10
that have a missing profile.
04:12
So we'll do const users equals await.
04:14
And rather than using this database module,
04:16
let's go ahead and use our models
04:18
as it will make this call a little bit easier.
04:20
So we can import our user model.query,
04:23
where doesn't have, and then just check for users
04:26
that doesn't have a profile record.
04:28
Looks like that wants some query callbacks.
04:30
So we'll go ahead and give it one to make it happy.
04:32
But we don't need to filter that down any further.
04:34
So we'll just leave that as it is.
04:36
Give that a save to fix formatting.
04:37
Okay, so now we just need an array of objects
04:39
with a user ID to pass into a create mini call
04:42
for our profile.
04:43
So we'll do const profiles equals users.map,
04:46
take our user.
04:47
And we'll return back an object that has user ID
04:50
as user.id.
04:51
Since we really only care about that user's ID,
04:54
we can go ahead and add a select
04:55
onto the end of our user query,
04:57
specifically selecting just that user's ID
04:59
to make that call a little bit quicker
05:01
and give that a save for formatting.
05:02
All right, so now we have our users that don't have an ID
05:05
and we have an array of profile objects
05:06
with that user's ID mapped in,
05:08
meaning that all that we need to do now
05:10
is await profile, import that model.createMini
05:14
and pass in our profiles array of objects, just like so.
05:17
We can give ourselves a little comment up here
05:19
to know exactly what we're doing.
05:21
Create profiles for any users missing one.
05:25
Let's go ahead and try and run it.
05:26
So we'll hide that back away, open up our terminal,
05:28
clear that out, node, ACE, migration run.
05:31
There we go.
05:32
So our migration successfully now ran,
05:34
meaning that if we were to jump into pgAdmin,
05:36
not sure exactly when we last refreshed this.
05:38
So I'm gonna go ahead and scroll up to Adana 6,
05:40
click that, refresh,
05:41
just to make sure it has all of our recent changes.
05:42
Come back down to our profiles, right click that,
05:45
view edit data, go ahead and select all rows.
05:47
And there we go.
05:48
So you can see the ones
05:49
that already have descriptions within there
05:50
are the ones that we've created with our fake data.
05:52
And then we have these three down here with null information
05:55
that we likely created with our authentication.
05:57
If we scroll down a little bit further,
05:58
we should be able to find our users.
06:00
Go ahead and right click on that.
06:01
So here we have user IDs nine, 10 and seven.
06:04
So right click on our users, view edit data,
06:06
all rows, seven, nine and 10,
06:09
are indeed our John Doe, John and AuthUser1.
06:12
So these are indeed our authenticated users.
06:14
Cool, so we can hide that back away,
06:16
clear this out and boot back up our server,
06:18
jump back into our text editor.
06:19
We can collapse down our database
06:21
and jump back into our profiles controller.
06:23
And now we are safe to make this assertion
06:25
because we've now verified that our users
06:27
will always have a profile record.
06:29
Meaning we can go ahead and just return view.render
06:32
and pass in pages, profiles, edit
06:35
with stateful information of our profile.
06:38
And if you wanted to,
06:39
you could also pass your users information
06:41
directly in there,
06:41
but we will have that accessible just via Auth.user.
06:44
So it's not necessarily needed.
06:46
Give that a save and let's go create that page real quick.
06:48
So right click pages, new file,
06:51
create a folder called profiles
06:52
with a page of edit.edge inside of it.
06:54
Again, before we end, I do want to emphasize
06:57
the only reason that we added this migration
06:59
with this defer call is because we had some users
07:02
in our database that did not have a profile
07:04
because we were missing the profile creation
07:07
in our registration step for those users.
07:09
If we had added this from the get go,
07:11
we would not have needed this migration
07:13
to add those missing profiles.
07:14
So if you do need your users to always have a profile
07:16
and you have this from the moment
07:18
that you launch your authentication
07:19
and you don't have any users missing profiles,
07:21
then you do not need this migration whatsoever.
07:24
But if you're launching something like profiles
07:26
inside of your application,
07:27
where it might come after you've launched
07:29
your authentication,
07:29
then this is an approach for how you can make sure
07:32
that those records exist for users
07:34
that already exist inside of your database.
Join The Discussion! (0 Comments)
Please sign in or sign up for free to join in on the dicussion.
Be the first to Comment!