Rebuilding Jagr.Co, Username Sign In & Post CRUD

In this livestream we cover adding the ability to sign in using either a username or email address. We also dig into setting up the ability to create, read, update, and delete our posts.

Published
Nov 06, 21
Duration
2h 20m

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

Join me live as I begin rebuilding Jagr.Co with AdonisJS. In this livestream we cover adding the ability to sign in using either a username or email address. We also dig into setting up the ability to create, read, update, and delete our posts.

Transcript

Looking for something specific? Feel free to search the page for keywords to find a specific portion of the live stream that interests you most.

0:31

okay so i did a little bit of extra work not too much um since we last left off you'll

0:37

notice that the inputs um for well the input components are a little

0:43

bit different looking i went through kind of copied through my typical input edge component so it uses

0:51

alpine to kind of track the internal value and to be able to set max and mint lengths

0:57

for those values so that's the main thing this will be up

1:02

on github within the new jagerko repository if you want to take a look at it but it also sets you know if the type

1:10

is password it's going to allow you to toggle on and off the password settings so like for example if i have testing here we

1:16

can toggle it on and off things like that

1:21

so i believe that's the gist of what i've changed so far i also set up

1:26

the theme that i want to test out at least starting out for the code base so that's just all

1:33

tailwind changes so i just set brands and some default typography settings and

1:39

things like that but to start this video out i actually want to start with a comment that i got

1:45

on the last stream which uh danang commented

1:52

on the js framework can we use just the username slash password instead of using email password to log in

1:59

um yeah absolutely this is actually something that i don't have written up for the previous jaeger site which

2:06

there's no excuse for it because it's actually really really easy to add in so let's go ahead and add that into the new

2:11

code base so first and foremost we just want to go into config and then within the auth config there is this uids array

2:18

which defaults to email so this is what allows us to log in with the email so whenever

2:24

within our auth controller you know whatever we try to authenticate it's going to use that

2:29

uid array to check what the uid value is that we

2:35

pass into the attempt call so if we want to add

2:41

just the username so you users can just log in with the username then we would just replace email with username here

2:46

but in my case i'd like it to be username or email so i can just add username and email to this uids array

2:55

and now if we come back to the login and last lesson we created testuser1 and

3:01

testuser2 so

3:09

oh youtube's telling me i'm streaming in 4k which is not optimal but that seems to be going okay

3:16

um okay oh well we'll try it out we'll see how it goes um but yeah so test user one

3:22

so we'll just leave that as that um actually this input is an email so it

3:28

will block so let's go to the sign in here and change the input

3:34

type from email to text and then we'll do username slash email for the label there

3:42

and i'll still grab it the value on the back end as email so i'll just leave that as that

3:50

so now we have username or email enter

3:57

here's your name or email so now we can do test user one instead

4:02

of test user one on gmail.com and we should be able to log in now with just the email just like that

4:09

and we can confirm that using the email still works so we can do test user one at

4:14

gmail.com and there we go so we have that working

4:20

a-okay so that's really all that you need to do config off

4:26

add in whatever uid you want the user to be able to log in with now of course you want to make sure that that's going to

4:32

be a unique value on your database um so that you know

4:38

it's unique per user so that a user can't log into another account or get accounts mix match and stuff like

4:44

that so that's one thing to consider there um but

4:49

let me go ahead and log back in here

4:55

okay and since we have the basic authentication working now uh let's go ahead and start with getting

5:02

basic posts working so believe we set all of that stuff up in

5:08

the last lesson or last stream yep

5:14

cool cool cool so really all that we need to do is set up the environment to be able to handle that so uh what i like

5:22

to do is place everything admin based for stuff like this within a particular

5:28

namespace and so that could either be admin or if

5:33

it's going to be more than just admins you can name it something like studio or

5:39

panel or something like that i tend to go for studio so i'm going to

5:47

see all right over here on the right make a new controller so node is

5:53

make controller and then if i remember correctly you can just prefix your

6:00

controller name with whatever namespace you want to place it in so studio

6:06

and that would be like post controller so now this yep so there it created it within app controllers http studio post

6:13

controllers so now we have this nice new studio controller your studio folder with a

6:18

post controller within it and so now let's do public

6:24

async index and we will just return back let's see we're

6:30

going to want a view for this so we'll do view let me comment out the http

6:37

context contract there we go and for right now let's just return view

6:44

dot render and then i'm going to name space this within the view as well so this will be

6:50

views studio posts index so views or no sorry that's not

6:56

needed studio posts index and for right now we'll just pass

7:03

it an empty state so we'll define a route for that and

7:09

we'll name space everything within the route as well so we'll do route dot group

7:17

dot name space is studio sorry

7:22

use the whole path app

7:29

controllers http studio alternatively i could have

7:35

name-spaced it like this where it's app studio controllers but i i kind of prefer this approach so

7:41

that's personal preference and then i'm going to go ahead and prefix everything within this with

7:48

studio as well as studio and prefix the name as well

7:53

so we'll do route dot and then i'm going to do another group specific to posts

7:59

so dot prefix

8:04

posts as posts

8:09

and then we'll do wrap.get and we'll leave that blank um well all right up here i was doing

8:15

slashes on my other project i'm excluding the slashes but i i'll stick with slashes on this one it is a little

8:21

bit easier to read and since we have the namespace set we should be able to reference everything

8:28

just the same as though it wasn't in a namespace since the namespace is set on this group so

8:34

this would be posts controller dot index

8:40

as index

8:46

so last thing to do is actually set up that view so we will do a new file within views

8:53

this will be studio posts index dot edge

9:00

all right and uh let's do layout we will create a new layout for this

9:06

called studio.edge but for right now let's just do main

9:12

layout slash main there we go section content

9:20

and let's just plopping each one in there of working

9:26

so let's go ahead and test that out so now we should be able to go to

9:32

studio posts and there we get working so that's working all right

9:40

so next thing to do is to be able to create a post so

9:46

in order to be able to show our posts within our index view we need to actually have some posts so let's go ahead and cover the creation

9:54

so async create we'll want view for that one as well since this will be

10:00

viewing not viewing rendering the creation form

10:06

so there we go render out studio post create sounds good and then

10:12

we'll leave that as an empty state for now as well and i'm just going to go ahead and

10:20

copy and paste my index and rename it

10:25

to create and then while i'm here i'm going to go

10:31

ahead and copy and paste my main.edge and rename that to studio.edge2 before

10:37

we get too many files using the main layout so paste that in there

10:43

rename and instead of main we'll name that studio

10:49

currently there's going to be no difference here i'll go ahead and rename the title just so i know where i'm at

10:54

and that i'm actually using the studio one currently there will be no difference but there will be a difference later on

11:00

so i'm going to go ahead and make that file now before we get too many things relying on layouts main within our

11:06

studio so there we go so there should be absolutely no change

11:12

to this page all right cool and for our create page we should uh no

11:19

i didn't make the route4 yet so it shouldn't work so let's go ahead and make the route for it

11:25

brow.getcreatepostcontroller.create as create sounds good and you'll notice i'm not using a resource i tend to prefer to manually

11:33

define all of my routes again that's a personal preference i could absolutely just do route.resource

11:40

for posts here and it would work just fine just a personal preference of mine to

11:46

manually define everything and

11:52

let's see so now now that we have that let's go ahead and verify that that is working just before we start doing anything and

11:59

all right make sure that it is actually the create page by changing that yep okay cool

12:10

so now we need to actually start on our form we're going to keep this pretty

12:15

basic to start with let's see what all we have that is not nullable within our database

12:21

first so i'm going to just open up the schema structure within my database if i can find it so

12:29

posts and then change it over to structure

12:36

so title slug not nullable and state is not nullable everything

12:43

else is nullable so to start with i'm going to take care of everything that is not nullable so

12:50

in this case slug we're going to have as something that you can manually

12:56

define uh but it should automatically set if it's left empty uh title is

13:02

absolutely required and state we will set as a default if it's not provided

13:08

so we'll take care of all of the default states first

13:14

and then we will take care of being able to manually provide a value for those so

13:19

first and foremost let's go ahead and just get our well let's go ahead and plot an h1 of

13:26

something up here just so that we can confirm that that's the page that we are on and then we will have form

13:31

method post action equals

13:36

and we will do route studio dot posts dots

13:43

yeah this will be store we haven't created it yet actually we need to create it since we are referencing its path so we'll go

13:50

ahead and end our form here and go ahead and create that because since this route currently doesn't exist but we're trying

13:56

to grab it we should be getting an error yeah

14:01

so we'll go ahead and create that so that we are not getting that error there we won't do anything with it yet but it will exist so

14:08

public async not post store and again i could have created this as a

14:14

resource controller i probably should have but i didn't here i can

14:19

probably go ahead and just grab one of these

14:28

there we go okay so for this one

14:35

we will want the request and for right now we'll just leave it as that actually and let's just

14:42

go ahead and define the route for it so this will be route.post and everything there looks right so

14:48

we'll stick with that okay so now if we

14:53

go back to our page since we got an error we need to refresh but there we go we refreshed and we no longer have an

14:58

error which is what we want so

15:05

let's see let's go ahead and take care of the title well yes thank you uh co-pilot i do need to see our csrf field

15:14

so we'll go ahead and add that in csrf field

15:20

and that will add in a hidden input containing the csrf value from there let's go ahead and do

15:29

a component components.input

15:34

see label will be title name will be titled value will just be

15:42

flash messages dot get title in case something errors out flash

15:47

smashes it the old value will come back within the flash flash messages

15:53

and we can grab it using get title so that the value is exactly as we left it

16:00

prior to submission errors we can again get off of flash messages

16:08

this time at errors.title what else what else what else required

16:15

true these are all things that i've set to be applicable

16:20

on my input component so these are all things that are used so like um let's see we have a placeholder

16:28

i could define rows if it's a text area if it's not i can define it as a group

16:33

which will just place whatever i have in a slot of the component within there handles selects inputs

16:41

all that fun stuff max length min length um

16:46

arya attributes so these are all just things that are applicable to that particular component

16:53

and i think that should do it for right now

16:59

so we'll just save that actually we need a button so i'm just going to do a button type equals

17:05

submit

17:12

save post good enough right now save that so now we should have a form

17:19

with csrf field is not a function do i have csrf

17:24

enabled and installed shield

17:32

see is it csp no

17:43

oh wait a minute i think that was wrong i think it's

17:48

camel cased i think i think that's it

17:55

no okay i'm gonna go take a look at the documentation real quick

18:01

over here

18:13

yep that's how i have it okay so something in my project is

18:18

missing the csrf portion so i'm gonna make sure that i have

18:24

adonis shield installed and configured so

18:29

got shield config so it should be but we'll double check it um let's see nope not kernel where does that go down src

18:38

there's the shield provider

18:47

okay

19:00

let's see if maybe csrf token works oh need to copy that whole thing

19:08

let's just hit the copy button all right go back to here place that in there

19:14

let's see what we get for that

19:21

ooh that's an ugly form page that's all right we can fix it up here

19:26

in a second so yeah we get undefined so something with that's definitely missing

19:35

let's see let's see let's see

19:51

no dmv should not be testing

19:56

nope let's take a look and see if we're getting the cookie

20:05

nope all right

20:14

well for right now let's go ahead and just remove csrf and see if it even checks for it

20:21

so we'll remove that and then we will just check on our back end

20:28

to see whether or not we are getting our title so we will do const title equals

20:37

request only title nope not return title um

20:45

just console.logging out for right now

20:54

i don't have view plugged out of my http context here

21:01

view dot render let's see [Music]

21:07

hmm how do i go back nope i'm thinking about this wrong it's response dot

21:12

redirect back that's what it is

21:21

okay because for right now i just want to go back to the form after submission just to see whether or not we are getting the

21:26

title here or to see if we're going to run into a csrf issue

21:32

so refresh here post up testing okay

21:38

check out the console and so yeah so csrf just isn't enabled or configured

21:43

correctly so we'll go ahead and just move forward for

21:49

right now i will take a look at that in a little bit so let's see so we have our title

21:58

within here i'm going to go ahead and create a

22:03

validator so node ace make validator uh

22:09

post store validator

22:17

okay and within here whoops within here

22:24

let's go ahead and define the title

22:31

and i need to import rules okay

22:36

rules max length is what is my max length

22:43

100 okay and then

22:48

everything else we'll go ahead and define in here as well so page title description meta

22:54

description all are going to be pretty similar to this so

23:01

page title description

23:08

met a description the max length on those will vary so we have 100 for page title

23:15

and 255 for description of meta description so 100 remains for page title

23:21

i don't have commas so we get red squigglies let's add those commas in and then this one goes to 255 and this

23:29

one goes to 255. and let's copy that once more because i saw canonical as the next one

23:35

there is canonical then we have body which will not have a max length

23:41

video url which will have a max length of 255. so body schema string

23:49

uh and no rules for that one and video url

23:54

yes video url schema dots do we have url is that a

24:01

thing no that's a rule okay so string

24:07

yep rules.max length 255 rules.url

24:15

okay and then we have is featured in this person i'm going to

24:20

leave off right now i am not currently actually using those um view count is not something that

24:27

will be set whenever you create uh let's see i'm going to take the time

24:32

zone and publish that user and publish that get that as well actually i don't

24:37

remember what i was doing for that so i'm going to take a look real quick

24:47

okay so we have time zone is just a string schema.string

24:58

and then we have publish at

25:03

which is

25:11

dot optional actually all of these need to be optional

25:17

oh the afterthought okay and then we have let's see publish that

25:22

user all right let's just be published

25:28

publish at user schema dot and this one is just a

25:33

string okay and then i'll tack optional on everything but the

25:39

title

25:55

okay there we go um actually post type id needs to come

26:00

up with this too although if it's not set we will have a default ready for it so that will

26:07

just be let's see we should have an enum that i copy and paste it over yeah post type so

26:14

what we can do here is we can do schema.enum

26:20

object keys of that enum which should be post

26:25

type which will auto import and then

26:35

no not keys values there we go

26:42

thought something felt off about that okay so that should be good so also that needs to be optional

26:49

okay so now it should be good so we should be just fine just passing in the title everything should validate just

26:55

fine i'm not going to actually create this yet i'm just going to verify validation succeeds so we will take the

27:03

request dot only off and instead we will do const data equals await

27:09

request validate post store validator

27:15

and instead of console.logging title we can go ahead and just console.log data and redirect back so we'll come back

27:21

into our form send off testing again and validation

27:27

should succeed

27:34

the fact that we got to our console log actually did did we yes we did okay because i was last up

27:40

there so yes we actually have data with a title in it so the fact that we got to the console log means that the validation succeeded otherwise it would

27:47

have thrown an error and we never never would have gotten to the console log

27:53

so that all should be good we need to go ahead and take care of the

27:59

[Music] slug create actually we need to add slug into the validator because

28:05

we should be able to manually set it but if it's not going to be manually set then we need to set the default so let's

28:11

do schema string since it has additional hyphens and

28:16

everything in there i think the default for that is 150 or or 255 okay

28:25

so there we go uh and make that optional

28:32

okay so now if that's not provided then we want to create it so

28:38

let's see

28:45

looking real quick

28:52

looking looking looking there it is okay

28:58

so let's go into our post model and we can add a hook

29:04

onto the before create

29:14

and call this create slug

29:20

and this will take in an instance of our post

29:25

so if the post has a slug then we just want to return because we don't need to

29:30

do anything because we manually defined the slug otherwise

29:35

i'm going to install a package let's see what package do i use

29:44

slugify there is also a adonis package for sluggification um

29:52

i i i i'd recommend using that if you're just getting started

29:58

um i don't remember my reasoning for using this package but i'm going to stick with this package

30:09

so whatever that guy's username is slash slogify

30:17

and let's go ahead and well let's see if it'll auto import

30:23

no okay so import

30:29

slugify from

30:35

there we go

30:42

and

30:47

go back down so i can see how this package is actually used and it looks like you're just passing the value to a slogify method so we'll do const slug

30:55

equals yeah i don't think that's actually in there

31:02

all right and then const cur there's only one r in there and it

31:10

says there we go oh wait and

31:15

let me use the database module here query from

31:21

posts where

31:26

actually let's do a where raw

31:32

slug are like i don't know this might be

31:38

i'm pulling this off of my previous writing of the code base

31:45

so this may be specifically for

31:50

my sql but we'll see if it'll work if i can type it right zero through nine

31:59

nope dollar sign there we go so do i have that all right

32:14

yes okay

32:19

and then the question mark will be our slug

32:25

oh i got something wrong oh i didn't start the string it would help if i start the string

32:30

and then where did this guy come from

32:37

oh oh okay my bad that is a member of the actual

32:43

string so we need to wrap that in that there we go

32:50

okay and then that takes in not just a value but an

32:56

array there we go all right i think that's right

33:02

and then we set the slug to

33:11

occurrences.length whatever the slug is

33:17

whatever the occurrences of the slug are

33:22

or if there are no occurrences then we just use the slug

33:27

okay so very curious to see whether or not that's my sequel specific or if it will

33:33

work in postgres mainly i'm not sure about the r like i would assume it would be okay but we'll

33:40

see uh so that should now run whenever this is created so we should be okay to go

33:45

ahead and try to create a post record so we will do const post equals await

33:52

post dot create

33:59

our data and then

34:04

we will redirect instead of back

34:10

to route yep studio posts index

34:16

uh actually we don't need the post to come back so we'll just do oh wait postdoc creed okay

34:24

so let's test that out so come back into our ugly

34:30

post form refresh to make sure everything and yep all right what do we got here

34:39

oh no did i spell his name wrong

34:46

it did install yeah yeah installed okay

34:52

let's go back to our post model

34:59

all right let me take another look

35:05

let's see we have s-i-n

35:11

and i'm covering it up d-r-e-s

35:20

huh yeah got it right okay

35:30

interesting did i spell it right here

35:40

yep all right

35:49

[Music]

36:00

just try to just copy and paste it

36:06

here it is see if it did change at all

36:13

nope i did have it right okay well then let's take a look at the package maybe we will be changing packages for this

36:18

rewrite

36:32

go ahead and try to reinstall it using a copy and paste version in case i did spell it wrong

36:40

okay nope looks like it was installed

36:50

that does appear to be how i'm using it

36:56

let's go confirm

37:05

yep all right well it's on the arizona import so it wouldn't be how it's being

37:10

used

37:30

just to change the require of index.js so i wonder

37:37

i mean i am using a newer node version i wonder if the way that they're

37:43

exporting their package here is no longer supported

38:05

hmm

38:37

okay well let me go ahead and i don't know try to find a different one

38:44

it should work though i don't think anything should have broken between

38:50

this version and that version

39:01

did i save maybe i forgot to save

39:14

make sure that we're getting a value to pass it well it's on import so yeah but all right well let's see if we

39:20

get there for whatever reason let's try this again

39:29

oh right i just refreshed so yeah we didn't even submit okay

39:37

and it is specifically that package that's causing it yeah

39:50

yeah okay

40:02

uh let's see uh maybe i will just use the adonis version

40:08

see is it lucid slugify i think it is

40:23

okay

40:37

and let's uninstall you okay

40:55

all right and for the most part that looks like exactly what i want

41:01

so instead of doing this via a before create hook instead it looks like adonis will take

41:07

care of all of that logic for me which is nice and let's see that goes on the slug

41:13

not the title right yes okay so plop that in there i'll retype it

41:20

since it'll need imported didn't offer to auto import

41:31

outcome

42:01

all right let's test this out so testing save post

42:13

oh yeah all right so it seems to be working um or

42:19

at least we're failing out on a different error so state id

42:25

needs a default uh

42:31

so we can either do that in a before create i don't recall exactly where i

42:37

was doing it before

42:43

let's see i think i was just doing that within the data so instead of

42:49

doing this it would be what is that state id

42:55

equals state dot nope not is it state enums states is

43:02

it the stadium that i want here nope

43:08

it is oh i was in status yes it is states

43:13

sorry state dot

43:20

public is that the default one that i use um

43:32

let's see that'll do for now and then we need to spread our data so

43:39

now if state id is within our data it will get overwritten with whatever that state id is

43:44

um and so now we should be good to go ahead and retry this so since i submitted i'm

43:50

going to go back and refresh to make sure that i got latest

43:56

testing save it off and okay cool so there we go it seemed to have saved we will jump

44:01

into the database to verify that sorry i had to jump through some hoops

44:07

there to get it to actually go and so there our slug is populating we can go

44:13

ahead and test it out by trying to create another post with a title of testing to

44:20

make sure that it's doing what i want refresh oh yeah that's exactly how i was

44:26

trying to write it with the other package so that's that's perfect cool

44:36

all right so now all that we need to do is kind of fill in the void with all of these other fields

44:43

um yeah

44:48

so let's see let's go back to our post

44:55

nope that's the model i want the view post create all right

45:00

and let's make this a little nicer on the eyes so let's do

45:07

div class flex um

45:13

negative mx now let's do six

45:20

okay and nope nope don't quite paste yet let's also do flex wrap on that

45:36

let's do two thirds okay and now we can paste that in

45:41

and then we will do another div

45:49

and we also need a padding on these so px let's see ah three

45:59

okay and let's actually limit that to lg

46:11

no yeah i need to be in the crete all right

46:17

all right so that does need to be six oh that i need to change the negative

46:23

to three there we go all right

46:28

and then let's set

46:37

actually i'm gonna set yeah and we'll just leave it here right now oh

46:44

okay yeah that that works uh so i will move this off into

46:51

i guess the studio wrap it with the component

47:03

did i copy the whole class yes okay

47:14

all right cool so that looks good um so we have our title let's see we

47:20

also need janet

47:25

dog's saying hi did you write in the mic uh let's see

47:33

so back to our post create so we also need in addition to this we need to be able

47:39

to manually set our slug

47:44

so we will do slug

47:53

and this is not required so i can just leave that off

47:59

and then we also need to be able to do

48:04

our uh seo stuff so i want to put this in

48:10

what is it details i think and this takes

48:17

a summary

48:27

all right and we'll put these fields in here so we'll have two one well

48:33

really would be three i guess one for um page title

48:45

uh page title page title page title

48:54

one for meta description

49:09

and one for our canonical so can cool there we go

49:16

what yeah no that's the name and then actually for the meta description i want to change this to

49:23

type text area set it as rows of three i can't remember

49:31

what the default i set on that is so we'll stick with rows three um

49:37

and let's see canonical

49:43

canonical and then we're gonna need some kind of a wysiwyg editor for the body uh normally

49:48

i use tip tap um prefer to have more of a all-in-one solution as opposed to rebuilding it but

49:57

i might just copy and paste that over but let's go ahead and save this check and see what we got so far so we have

50:04

our title our slug search engine stuff goes inside of there i'm gonna

50:10

cut back on this a little bit so if we go take a look at

50:17

because i actually rather like the way that the post creation form is set up

50:24

currently so if we go into posts and

50:30

see i go to edit this one so i've got it to where

50:35

everything's just kind of cleanish um

50:43

and then yeah everything with the yeah so i might stick with this

50:50

approach

50:56

as opposed to for the most part we're sticking pretty

51:02

close to it it's just the inputs need a different styling um see i think all of this is using

51:12

inertia so this is all in view but we don't need view for this so for the rebuild i'm

51:19

keeping it nice simple and we're going to just sprinkle in

51:24

view where we need it let's see i actually have alpine all throughout here so maybe we can find an alpine solution i doubt that there's any alpine wysiwygs

51:31

out there though and tip tap is just in view all right

51:37

well we'll we'll move forward with just plopping things on here for now sorry i'm rambling

51:43

um so let's just outside of the details now

51:51

copy the meta description we'll just plot this in there as the body

51:57

for right now sorry no that doesn't need to remain text area

52:05

and replace this with a wysiwyg editor later on i need to find

52:11

one that i want to use okay and

52:16

i believe that's oh yeah no sorry

52:21

so we have a meta description but we also need the actual description so is that description or is that summary

52:28

that's description okay so i already have the meta description

52:33

copied so i will just paste that in up here

52:40

that is also going to be a text area and just get rid of meta

52:50

okay

52:58

there we go um put some spacing on the details here

53:08

there we go that's a little bit better and then off to the right hand side i'm going to skip over the

53:16

thumbnail input but i will go ahead and keep the video url over there for right

53:22

now and then i think i might go ahead and copy this input style for this so we'll have a secondary input

53:30

component of some kind to mimic that style so

53:36

let's see go ahead and copy one of these

53:43

and paste that over on the right hand side so this one will be video

53:49

url

53:59

and to demonstrate the purpose that i have this flash messages get the name

54:04

here uh if since our title is required if i leave the title off and i just

54:11

type in some stuff in these other fields

54:20

right and i go ahead and save what will happen is the validation will fail and it will redirect back with those

54:27

these values that i already have propagated within the flash messages so all that i'm doing is getting that value

54:33

out of there and reapplying it to those fields so if we hit save here we should come back to the page exactly as it

54:39

appears right here and there we go so that's that's what that is doing

54:45

right there so this little value setting of the flash messages

54:51

um all right so it's not pretty but it should

54:57

allow us to do everything that we need so far so we can do this as test post i should be

55:04

able to manually define some slug here and not have it

55:10

be auto set although i actually since i'm not the one that's doing the

55:16

slug validation anymore i don't know whether or not that will actually work but we will test it and see and then i'm just gonna yeah that works

55:22

for the description body and video url um actually

55:34

i already have a video open so let's why not just go ahead and copy that there we go all right so let's save

55:40

that seemed to work we'll get those listed out here in a second refresh this so

55:47

awesome yeah so the actual the actual slug so it seems like adonis's sluggify

55:53

package was doing exactly what i was manually doing which is super nice so if the slug is provided it remains

55:59

as you provided it if it's not provided then it will auto increment with a hyphen and the version

56:07

uh and then we got oh i forgot to expand my seo to test that but we got the description the body and the video url

56:14

set as we set it as well so we have although it's not very nice we have a

56:21

couple of dummy posts here to go ahead and list out on our index page

56:28

so we'll just get that going with a very simplistic table and then i'll go in later on and style it up a little bit

56:33

so within our index well first and foremost we have to query it oh shoot i have no

56:39

modules open

56:45

okay so let's go ahead and query for it so within our index const posts equals

56:52

we only want the authenticated users post so we'll get off off

56:57

user and i'm going to put an authentication middleware on this here in a second

57:04

so authuser related posts

57:10

and let's go ahead and paginate it as well

57:17

see what's what's the first argument there is it per page or is it the page i think it's the page

57:24

that is my one gripe about github copilot is it kind of breaks the

57:30

tooltip oh well i broke it i didn't do query dot paginate so that is my bad

57:35

yeah okay so the first argument is the page i'll manually pass it in as one for right now and then per page

57:43

yeah yeah 20 is fine and then we can

57:48

either get this off of the query string or the params i'm going to go ahead and do the

57:54

params so const page equals

58:02

params.page otherwise one

58:10

and pass that in as page there and then we will return back to our view

58:16

e posts and then i'm gonna go ahead and add that optional param

58:22

onto the route so here on index we have the optional param

58:29

of page and then i'm going to do where page

58:34

route matchers and number so that it validates that it's a number

58:40

and we'll actually cast it to a number for me within my controller so that should all be good let's go ahead

58:48

and plop it out on our index page just to verify everything so i'm going to put this

58:54

inside of a pre okay

58:59

and then i'm going to do inspect and

59:05

adonis passes everything to edge unserialized whenever we're using it

59:10

like this so i'm going to go ahead and do posts dots

59:18

serialize so that i only print out the actual data that we get

59:25

[Music] oh no my bad all right let's try it just as posts first

59:38

oh i killed it

59:50

there we go all right yeah so we're not getting back our posts so i did something wrong on the back end let's go see what i did wrong

1:00:02

okay let's try taking the paginate off

1:00:08

it could be how i have the relation shut up set up sorry can't speak

1:00:18

okay that seems to be getting it

1:00:27

so let's go ahead and take a look um instead of getting back oh i don't have a weight that's let's see

1:00:34

and the reason i noticed that is because i'm still having an instance of the connect query object here not an

1:00:41

instance of my posts so now that we have the await there if we actually take a look at what we get

1:00:46

back okay that's fair

1:00:52

so i have something set up with my relationship wrong

1:00:58

relation post user does not exist is that trying to use that as a table or

1:01:04

a column as a table so let's go back into our

1:01:11

models take a look at how i'm defining that relationship here

1:01:16

so user to post is a many-to-many relationship via the table

1:01:24

author posts so yeah that's absolutely wrong i forgot the outcome so for one we're calling it author post

1:01:30

or our authors on our post so we need to set that so not table name pivot table

1:01:37

is author posts yeah yep

1:01:43

and we need to do that on the inverse side as well but first is there any pivot columns no oh author type id

1:01:50

i don't remember why i put that in there but all right we'll go ahead and

1:01:56

type id so now we'll copy this and let's define that on the inverse side as well

1:02:01

so over on our post let's find our authors there it is

1:02:10

okay now let's give that another go

1:02:20

that's fair so we created the posts

1:02:25

but we didn't assign the posts any authors so we also need to do that so i'm going to go ahead and delete all of

1:02:30

these posts here well now let's leave them here for a second to verify that they don't come through whenever we

1:02:36

actually do query for the actual authors so what we need to do

1:02:42

is within our post controller whenever we create

1:02:47

and i can either do this on create or i can do this just within the creation logic i think i'll go ahead and do it

1:02:53

within on create because we always want it to happen on create

1:02:59

so before create public static async

1:03:04

set initial author i guess set off and let's

1:03:10

just do set author

1:03:16

right that will take back the post of type post

1:03:21

post there no this needs to happen after doesn't it

1:03:30

after create since we already need a post id

1:03:36

uh to assign to the mini mini relationship and let's see i'm also going to yeah so

1:03:43

let's not do it as a hook i also need my authenticated user i could pass that

1:03:48

in um but at that point i would feel better just not having it within there

1:03:55

so let's go back to here on store

1:04:01

let's do our const post equals await and then we want to grab our auth from here

1:04:10

and we can do the yeah that looks

1:04:16

is that right that looks right no it's not right off user i think that

1:04:21

needs to be related posts

1:04:26

all right attach and attach ticks in array

1:04:34

so now that should be good i believe so we need to go back i'm gonna go ahead

1:04:40

and just plop a button on here so i don't have to keep manually altering the url

1:04:49

a href route studio posts

1:04:55

create

1:05:00

okay now we got a button all right so let's test this again

1:05:06

test with author and go ahead and just type something in

1:05:12

there type something in there plop something in here

1:05:22

and save all right so now we came back to our index page and now we no longer have an

1:05:28

empty array so we have something coming back and it looks like it's our test with author so that is working

1:05:34

as we'd like and we can verify that in the database for sanity's sake and there we go

1:05:44

so instead of just returning back an array of all

1:05:51

posts let's go ahead and paginate with the page

1:05:58

and we'll manually set the limit to 20. so now this will be

1:06:04

slightly different i believe

1:06:14

well once we serialized it would be but yeah so paginate still applies the attributes

1:06:20

and everything on there but we can also reference everything via rows and then somewhere on here we should

1:06:26

have yeah our pagination data so there we go

1:06:31

so now we can go back to our index page and get some kind of a table going on here so

1:06:41

let's see

1:06:54

just do title for right now

1:07:00

that's the wrong syntax but that's pretty close stick with it

1:07:08

okay for each

1:07:14

post in posts instead of doing dollar sign posts we want to post that title

1:07:21

and we can also do rows there as well if we'd like so

1:07:27

yeah okay that way we're using the paginated data so

1:07:32

nope what do we got wrong reading title

1:07:38

i think this is each isn't it

1:07:45

co-pilot was more wrong than i went on to believe yeah so there we go now we got that

1:07:50

working so we can get rid of our inspect and i did not end the table

1:08:00

okay so there is our junky table telling us that we have

1:08:06

a single post to this author so let's see what else do we want to be on

1:08:12

here we do the author we can do the status we

1:08:19

can do the type number of views the publish date so we actually need to add the publish date

1:08:24

into the form as well so let's see so

1:08:30

go ahead and add this stuff here first so yeah we can put the slug underneath the

1:08:36

title so here we can do the title itself

1:08:43

is an anchor

1:08:48

and this will go to the edit so route studio

1:08:54

posts we haven't created it yet so we're going to get an error here for a little bit but we'll do edit

1:09:00

and then this takes in as the post.id

1:09:08

and then underneath that we do another anchor that actually goes to the uh

1:09:13

actual post itself which we don't have this route created yet either so i'm actually just going to leave that as an empty anchor

1:09:22

because we're not quite ready to get to that yet and this will be the post dot slog that

1:09:28

renders out in there so go ahead save this it's going to cause

1:09:33

an error because studio post edit doesn't exist yet but we can go ahead and make it exist

1:09:44

so let's say we're going to want view and params

1:09:50

const post equals awaits

1:09:56

looks good to me return view dot render

1:10:02

studio posts edit and of course i could do this in a

1:10:08

single view so it would be like add or edit um

1:10:16

which actually yeah let's go ahead and do that

1:10:22

add or edit why make things harder for yourself right

1:10:27

so it should be good to go ahead and save that let's define the route

1:10:34

so route.get posts this will be the id

1:10:40

oops and edit or do we need it is anything

1:10:46

else going to live there and we'll leave edit in there okay and this will be posts

1:10:53

controller dot edit as edit

1:10:58

go ahead and clean this group up here so far

1:11:04

okay

1:11:12

we'll leave it there all right and then we need to alter the view name for our create

1:11:18

from just create to really should be creator

1:11:24

edit yeah yeah i like that better than add or edit it

1:11:38

fits better with the naming so let's go with that and then on all of these

1:11:45

where we have the flash flash messages that get um

1:11:51

we also need to just try to get it off the post as well so

1:11:56

let's see what so let's see we could do a turn area i guess since i already have this

1:12:02

defaulting back i let's see do i need that default because then we could just do

1:12:09

does the post internally default to an empty string or the input internally

1:12:19

yes it does okay so we should be able to just do

1:12:24

post dot well i'm gonna actually leave that empty for a second here just to test so let's

1:12:30

go back into here refresh let me fix that error should be

1:12:36

able to go into the edit okay cool yeah so it comes back and we don't get any errors about well let's

1:12:42

open up the terminal i guess to make sure there's no javascript errors either

1:12:49

yeah cool so it should be good to go ahead and add in

1:12:55

post dot title otherwise that let's test that out so

1:13:01

whenever we're creating post won't exist so i'm going to place a question mark here so that we don't get an error

1:13:06

whenever we try to reference title and if post.title does not exist and it will fall back to trying to get the flash

1:13:12

message i really cannot say that word and then if our flash

1:13:18

flash messages don't have the title on it then our input component

1:13:24

misclicked will check for that and it will default its internal value to an empty string if

1:13:30

a value is not provided so that's the flow going on there so if we come back into here

1:13:37

bam there is our post title so now we just need to do that for all of the inputs

1:13:43

so post slug that should allow us to alter the slug

1:13:50

if it did not get created to our liking or if for some reason we changed the title and we also need to reflect a new

1:13:57

slug for that post dot description

1:14:05

post dot page title

1:14:11

i forgot to do the question mark up here

1:14:17

post dot meet description

1:14:23

meta meta description there we go

1:14:31

post dot canonical

1:14:38

post up body and [Music] post dot

1:14:48

video url and just like magic there's everything

1:14:53

within our form so one last thing to change

1:14:59

the submission so first and foremost i don't believe by

1:15:05

default the um what's it called um

1:15:11

uh method spoofing is i don't think that's enabled by default let me see if i can remember where that is is that an

1:15:17

app yeah so i'm gonna allow method spoofing

1:15:23

set that to true so that i can do underscore is it a single underscore

1:15:28

yeah underscore method uh as a query program on the url to define that it should send up as either

1:15:34

a put or delete on the form um so that's what that's for so

1:15:40

instead of just doing route post store we could do

1:15:46

a store or update here but i'm going to keep these separate because i feel like in the end once i'm

1:15:53

done with everything the difference between storing and updating is going to be great enough that it deserves a separate endpoint

1:16:01

as for the page that's going to be pretty much similar for both so we can use the same page for that so

1:16:07

let's do post if we have a post then we're going to want to update actually let's do post id be a little bit more

1:16:14

specific so if we have a post id studio

1:16:21

posts update otherwise go ahead and use store

1:16:29

now in addition to this let's also add on a query string i've

1:16:36

i've never done it adding a query string like this via the object so

1:16:42

bear with me here for a second let's see um

1:16:47

actually let's clean this up even more let's use an internal edge component or not

1:16:52

component variable so at set

1:16:58

action post dot id

1:17:07

no it's defaulted to store

1:17:15

trying this out too i've never tried resetting a edge variable inside of an if but let's

1:17:22

try so if post

1:17:28

id at set the action so change the action

1:17:35

variable to

1:17:41

route again i've never tried this so i don't know whether or not this will work so let but yeah you never know unless

1:17:47

you try right so query string and then i think we want no just one method equals

1:17:56

put so let's try that out let's see what that gets us

1:18:03

all right and then we'll plop action in there so give that a save come back to

1:18:08

here unexpected token something i got wrong writing it or is

1:18:14

it that it does not expect this

1:18:23

i've never tried the query string set in there so maybe i got that wrong so i'm going to try taking that off just to see

1:18:29

oh oh yeah no it does need the um the id doesn't it

1:18:35

so id is post dot id

1:18:42

all right now so it's at least getting in there um let's define that route

1:18:49

better define the action no okay let's go and do that real quick

1:18:56

so i want the response we want the request so that we can validate it

1:19:02

and want the param so that we can get the id i think that's it

1:19:09

so we'll do const post equals awaits post finder fail

1:19:16

for right now we'll just leave all of the extra data off of it like the um

1:19:23

like the images the authors and all that and we'll just update the post so merge oh we need to validate first so

1:19:31

here we go uh yeah we'll use the post store validator

1:19:37

up until it doesn't become relevant if it does ever become irrelevant

1:19:43

if it might end up just changing that to be post validator instead we'll see if it

1:19:48

can be used for both and then we will await

1:19:55

no post.merge i don't think that also saves i think

1:20:00

yeah no that doesn't also save pass in the data await post dot save to

1:20:06

save that and then return response

1:20:11

redirect to route the post index page okay

1:20:17

so there's a simplistic update so let's do route dot put

1:20:25

id posts controller updates as update

1:20:41

okay so now that route should exist

1:20:48

so we can refresh here and let's check out what the generated route for our action is

1:20:59

studio post 5. so this is working exactly as i hoped it

1:21:04

did cool let's plop the query string in there

1:21:10

nope i believe that goes in as an object

1:21:15

yeah something like that it starts with an underscore yeah i think that's valid

1:21:22

try it out so now if we refresh we should have studio post 5 with a query string of

1:21:29

method equals put so now this should send up it well it will send up as a post via html but the back end adonis

1:21:37

will use this method spoofing to then change it into a put and use

1:21:43

our put route that we have here so let's test it so let's try to change

1:21:48

something so we'll put edit on the title

1:21:56

and we'll do it for the description as well so there we go so this just isn't

1:22:03

rendering right so this is the title and this is the slug so the edit did work we can go back into the edit form

1:22:10

to verify so cool everything's working there so far um

1:22:18

what to do next well we can make that a little bit better so it's easier to see

1:22:26

index

1:22:31

oh stomach's starting to grow sorry about that

1:22:37

i'm just gonna flex it

1:22:53

okay

1:23:03

and then in between all of the data i'm also going to have the actions over here to

1:23:09

the right so that we can edit and we can delete them um so let's go ahead and do that so i have

1:23:15

another td over here

1:23:20

spot on and we also want one for deleting

1:23:26

so we can use method spoofing for this as

1:23:32

well so we can do this as a form action equals or

1:23:38

method equals post action is and we don't have this route

1:23:44

created yet either but studio dot posts dot

1:23:50

destroy and we need the post id to come up with that as well

1:23:58

okay

1:24:05

and then here all we would need to do is a

1:24:11

button type submit or actually we could put this form off somewhere else and then have

1:24:16

the button reference the form but that this this works button type submit delete

1:24:24

yeah gotta define the route so let's go make the delete functionality first

1:24:30

so let's see we're going to need our request our response

1:24:37

and our params

1:24:42

so that is actually

1:24:48

pretty much correct good job um so yeah no we actually don't need request we don't need to validate

1:24:54

anything we're just using the id passed in from the param however we are not cascading the

1:25:01

deletion of our post authors so we need to kind of remove

1:25:07

that as well prior to deletion

1:25:14

so whenever we get our post we will do await post dot

1:25:21

related authors yes

1:25:27

and detach which will detach all relations for this particular post

1:25:33

so we're good to go ahead and save that that should do everything that we need to currently do

1:25:41

and we'll build from there as we go so route dot delete id post controller dot destroy destroy perfect

1:25:49

all right and uh now we should be good to go ahead and test it

1:25:56

so refresh this it's not beautiful but it's something uh

1:26:03

so go ahead and click delete and it should get rid of well let's create a new post

1:26:09

here so let's do test delete

1:26:20

okay save this one off again not beautiful but it's something

1:26:27

hit delete and oh oh yeah i forgot the method spoofing um

1:26:35

so let's tack on clear string

1:26:41

underscore method delete

1:26:47

okay so now whenever we hit delete we should be redirected back well it should delete

1:26:54

the record and then we should be redirected back to this page minus our record so delete and there we

1:27:00

go so that's working just fine as well

1:27:05

uh let's see i can immediately tell that the table's not taking off the full width because it's

1:27:13

wrapping so let's go ahead and make it take up the full width

1:27:20

there we go and change this to be text small so class

1:27:27

equals text extra smallest extra small and then

1:27:44

and let's not do space x3 because it adds spacing to the end of it as well i just want it in between see so

1:27:55

or maybe it doesn't okay either way this works so

1:28:01

this route here i guess we can step out of studio real quick and get those routes working as

1:28:07

well um at least partially maybe man let's see

1:28:23

so we have our creating the post working we have our editing and post working deleting the post working

1:28:30

we do need to go ahead and do the publish app

1:28:40

um yeah let's go ahead and do that so i don't remember why i have publish

1:28:48

at user as a column so i'm going to go take a look see if

1:28:54

i can find that being stubborn i know if i go back far enough i find my project again there we

1:29:01

go all right so let's see what i'm using that for so

1:29:07

app controller studio

1:29:14

post controller store

1:29:24

do do do data standardies public data.publish at

1:29:30

diff now seconds is less than zero publish app becomes the present

1:29:36

time oh here it is so publish that is date time from iso date time at user zone so i'm resetting

1:29:44

the user zone to whatever the user selects as their time zone to utc and then

1:29:54

re-saving it back with their time zone okay gotcha

1:30:02

so back within our create or edit

1:30:07

i think the one thing that i'm doing is i'm adding a hidden field so input type equals

1:30:14

hidden with the user's time zone as that value so name would be

1:30:20

time zone and the value would be whatever the user's time zone is

1:30:28

so we might need to use javascript to populate that i think that's what i was doing in this project

1:30:34

so i'm going to open this up in another tab go take a look real quick

1:30:42

pretty sure that's what i was doing let's see studio is within here because it's an

1:30:47

inertia well yeah okay that makes more sense that everything was in javascript here

1:30:53

post adder edit

1:31:00

do

1:31:07

yeah maybe i didn't have it in here maybe i was probably patching it up with

1:31:12

the yeah right here so it's patching out with the form data all right

1:31:18

regardless we can go ahead and take care of that since adonis isn't aware of what the

1:31:25

user's time zone is we can either make adonis aware or we can just pop it pop

1:31:31

propagate this populate this with the value so i'm going to just do that

1:31:36

so we'll add another section to studio

1:31:43

so do at section

1:31:50

as scripts so that it's always down at the bottom in case we need to add anything else before it

1:31:56

so then outside of this section we can now do another section called scripts

1:32:05

and let's take in a script here just do this in line it's not gonna be

1:32:10

much so document.forms dots let's give our form a name so that

1:32:17

we can access it post form

1:32:26

dot time zone dot value and there we go

1:32:32

so that's all that we need to do so now that should auto populate with whatever the user's time zone is

1:32:38

and then what was i using i think i was just using the

1:32:44

browser's default date and time inputs

1:32:51

for the publishing

1:33:00

let's try it out i don't know how that's going to appear in this component but let's try so let's see i think it's date

1:33:06

is the date type

1:33:13

and name is date the value would be

1:33:19

post dot publish at

1:33:24

dot uh

1:33:31

date that sounds wrong we'll leave that off for right now we'll come back to it i need to look at lux

1:33:38

and see exactly how you probably just to string with a format um [Music]

1:33:46

and then this would change the date i might merge this all into a date

1:33:51

time and then that's

1:33:56

date types let's see if that even renders yeah yeah it's got some

1:34:03

weird padding on the bottom but yeah it's there okay and then let's make use of the

1:34:09

group actually so at component

1:34:15

components input

1:34:21

type group

1:34:27

and component plop that in there

1:34:33

plop it in there again and i think the time input is just

1:34:38

called time we can take the label off of this

1:34:45

time time time

1:34:50

and take the label off of this one as well and i might need to wrap these

1:34:55

and probably do so let's do div class equals

1:35:00

flex item center

1:35:08

see how that looks where'd it go

1:35:14

okay

1:35:20

so something's going wrong there

1:35:31

all right check out the input components type

1:35:37

group to see what i'm doing here so

1:35:43

well did i give the group a label let's first try that because that should show up i did not let's give the group a

1:35:49

label

1:35:55

publish it and yep there's our label so it's definitely something with the group

1:36:04

slots dot input

1:36:09

so i named the slot so then what the heck do i have is the default slot is there a

1:36:15

default slider can i change this to the default slot

1:36:20

um what is the name of the default slot is it main it is oh i used it for select

1:36:26

okay i guess that makes sense so then let's see how do i name a slot i forget

1:36:32

is it section i'm gonna go take a look i'm not gonna guess i'm gonna go take a look

1:36:40

components slot

1:36:49

ah at slot that makes sense okay

1:36:54

so then it would be at slot input

1:37:02

and slot increment that and then we should get

1:37:07

our date time inputs oh ew what do we have going on here

1:37:12

okay bad refresh so

1:37:18

that is funky default styling for it um

1:37:24

but now right surely that's not the actual default styling right

1:37:42

no i i overrode it i yeah okay well

1:37:47

that's all right it's not pretty but it'll do fine for now so

1:37:54

we go ahead and test this so if we save this one to be published on say the 17th at

1:38:00

3 o'clock p.m um it should at least save as this because

1:38:07

it's going to send up as part of the data actually no it won't because we're expecting publish at

1:38:12

as a single string so we can either change it to where we

1:38:17

expect the date and the time separate

1:38:23

or i can have a concatenated version

1:38:30

it has like a hidden input somewhere

1:38:36

i'm going to say let's handle it separate that make things a little bit easier i think so we'll have

1:38:43

instead of i think we can get rid of publish that user and just do that as a time zone

1:38:50

we can mutate the publish app if need be so

1:38:57

publish at date will take as a date

1:39:03

publish at time

1:39:09

is there a way to first is their time i doubt it

1:39:14

probably if it if there is it's probably built in with date let's go take a look

1:39:22

let's see validator take a look at the date options

1:39:28

so we do format so

1:39:33

this i believe is the default format

1:39:40

for the html5 um or html inputs for the date and time

1:39:49

so we should maybe be able to do format

1:39:54

of this for the date so format

1:40:05

of that for the date and then optional format

1:40:11

of this for the time

1:40:20

did that twice oops all right so i'm not 100 certain whether or not those codes are correct for the default

1:40:26

uh html date and time inputs but we'll try it and see if it comes through so now we have published that date

1:40:33

publish at time within our validator so now we need to go up to here

1:40:38

and prior to and we can either do this as a before save

1:40:44

or we could do it directly in here before

1:40:49

the save and before the update i'm gonna go ahead and just console.log

1:40:54

out whatever we get for the data first just to make sure that it comes through and that it's actually

1:40:59

correct so let's let's do publish at um

1:41:06

date as publish at date and publish that times publish that time and make sure it comes through okay

1:41:16

okay so i'll come back into here

1:41:24

refresh you change you to the 17th and you too let's do 5 p.m something a

1:41:30

little bit further away from the time that it is right now and

1:41:37

save post let's take a look at our console log see what we got yeah so and to find it undefined so

1:41:44

either the format is wrong or something else

1:41:53

i'm going to be stubborn instead of going and looking to see what the actual format i need to use is i'm going to

1:41:59

change these to strings and we'll see what it actually come back as

1:42:05

we'll just take that off because that's not a valid string option and go back into here back into edit

1:42:15

yeah we don't need to change anything with it just checking to see what it comes through as and uh oh undefined and not defined

1:42:21

still

1:42:28

hey felipe uh yes this code will be up on github um and the code from the

1:42:34

previous stream is also up on github um

1:42:39

it's at jagerko and it should be this one right here

1:42:45

jager dot co and it's public so you should be able to find it

1:42:50

um so

1:42:56

it could be that these were defaults that the reason that they didn't come up it could be

1:43:03

i spelt something wrong it could be that the name isn't right that i have in the form so let's check

1:43:09

the name setting first i guess oh yeah yeah i've got date and time

1:43:16

i guess we could use that and publish at date be a little bit more descriptive i guess

1:43:23

and publish at time

1:43:30

so let's do 17th go to 5 o'clock again

1:43:35

try this one more time so it could be that the format was right oh cannot define publish that date on post

1:43:42

model since it's not oh yeah well that makes sense we have to delete it out before we try to save it so go into nope not there go

1:43:49

into here and instead of including it as a portion of our data we will take data spread it

1:43:55

out and prior to spreading out the data we will grab the publish at date and publish at time

1:44:04

so that they're no longer a member of our data so that we're not going to get this error saying that you know publish

1:44:09

that date's not a member of post you can't can't try to make it one um

1:44:14

and now instead of console.logging amount like this we can just do it like this

1:44:20

as well okay let's try this one more time 17 5 p.m

1:44:27

save okay cool so what did we get 2021 11 17 and the time just

1:44:37

didn't work so yeah i do believe the format that we had on that date validator was correct

1:44:44

time though why are you not coming through i changed the name wrong

1:44:51

publish that time so now that should be correct

1:44:57

hmm

1:45:03

publish that time as a string yep okay

1:45:11

and publish at time so looks like everything is referencing publish at time

1:45:18

we can

1:45:28

i don't remember if all gets data off of the body or not

1:45:35

let's see let's see what sends

1:45:42

up okay try this one more time five o'clock save

1:45:49

see what we got oh yeah cool so publish at times going up is

1:45:56

null interesting let's see why would you be null

1:46:03

why would you be null

1:46:24

let's check out the actual input on here to make sure i mean based off of how that's rendering it's

1:46:30

definitely a time input let's make sure that the name got onto it correctly

1:46:36

yep publish that time

1:46:48

and we're trying to pass it up as a string so that shouldn't be any issue with the formatting

1:47:01

i wonder if it's something with the model

1:47:07

let's see five o'clock going to the console here

1:47:14

all right well you're printing it out here but uh not really familiar with safari so i'm

1:47:20

gonna go ahead document dot forms dot

1:47:27

what did i name my post form i should just be able to do forms dot

1:47:34

post form make sure that's something nope

1:47:40

okay dot

1:47:46

publish at time all right dot

1:47:53

value yeah it's an empty string

1:48:20

oh gosh yeah see that's the thing that i hate about chrome 2 is it gives you the tree of it i want the

1:48:25

actual properties

1:48:32

okay so it's just that we're not getting back the actual value of the input

1:48:38

or the value is not setting um

1:48:52

remember the sign in i don't have any um authentication checks yet

1:49:01

so i just need to remember to sign in okay see yeah okay so it's something with safari with the reason that those

1:49:07

are so massive they look perfectly fine on firefox

1:49:12

um all right so let's take a look here so five o'clock

1:49:18

p.m maybe safari like shows you the defaults but it's not actually set

1:49:24

maybe that's just like a placeholder i don't know so document dot forms dot

1:49:33

publish at time dot

1:49:38

oh

1:49:44

no yeah skipped a step dot post form dot publisher time dot value

1:49:51

yeah there we go 1700 hours so

1:49:57

i'm gonna go back to safari here

1:50:05

and finish that up let's type everything in it if that is just a placeholder and that's not like a

1:50:12

default value that is super misleading yeah now it's coming through so that's

1:50:18

just a placeholder wow

1:50:24

like firefox's placeholder a lot better it's just dashes like i

1:50:29

i i assumed that that was going to be a default because i didn't set any placeholder on it but okay

1:50:37

so we can go ahead and actually work with this now that we know what we're getting back

1:50:44

so let's see so within our validator

1:50:50

publish that date i'm going to go ahead undo um

1:50:56

we're getting back 1700

1:51:01

so that would be hours hours minutes minutes no seconds

1:51:07

and i believe the dates right so we can change these back to dates

1:51:15

test to see whether or not they come through now so post controller console.log we can get rid of i believe

1:51:22

all in just in case and give this a save to test and see what we get now so

1:51:28

i didn't need to refresh but i just did uh set this to sure and we'll do five

1:51:36

o'clock p.m save

1:51:41

take a look at our console log see what we get all right so now we get a datetime object

1:51:46

for the time it defaults to

1:51:53

hours 17 minute is zero so that seems to be working and for the day

1:52:00

month is 11 days 18 so that seems to be working so now we just need to group them

1:52:05

together until one date time and plop it onto our data prior to our save

1:52:10

so const publish at equals

1:52:17

and we can either build this out as a string or i would say let's use one and alter it

1:52:24

to make it the other so publish at date dot set

1:52:32

hour is publish at time dot yep hour and minute and that's giving me red

1:52:39

squigglies why probably because it's optional and it's nullable yes

1:52:47

so well this is nullable 2. so we would

1:52:53

want to set an overall default so if

1:52:58

so const publish at equals

1:53:05

date time now need to import date time actually okay

1:53:13

if publish at date

1:53:19

then we will do publish at dot or no equals because it's immutable

1:53:26

publish at set is there a better way to merge two locks

1:53:32

and dates hmm

1:53:38

i don't know off the top of my head i'm going to go ahead and just stick with this because i know that this will work

1:53:43

and i put this as a const which is a no no because i'm changing it so we'll do let

1:53:49

why are you red squiggling now cannot redeclare block scope to variable

1:53:55

oh because it's also defined down here okay and if publish at time we'll do the same

1:54:02

thing not pretty but it'll at least work for right now so hours minutes we do not get

1:54:08

any seconds so we'll take that off and then last thing to do is data dot

1:54:14

publish at equals publish at

1:54:22

trying to decide whether or not that's going to try to throw an error or not okay well we'll go ahead and save try it

1:54:27

out see if it works we can get rid of this all now oops one two four there we go yep so publish

1:54:33

that's not a member of data so instead of doing that we can actually simplify this even further actually by doing dot

1:54:39

dot dot and then after we set the data set publisher i don't know why i didn't

1:54:44

do that initially that's a lot cleaner okay so come back into here

1:54:50

try to set the date to the 18th we'll leave the time empty

1:54:56

to verify that you know it just sets to whatever now is which would be for me 1102 am

1:55:02

so go ahead and save come back in and it should now still be the 17th to the oh i didn't do not have

1:55:08

it populating i do not all right i wasn't sure how it

1:55:15

was going to okay well we have the formats so we already know

1:55:22

what that is um we can actually populate that

1:55:29

see on our post

1:55:36

i don't know if it's worth it but we can do a computed property here

1:55:44

nope what am i doing that's completely wrong computed public

1:55:49

get publish at date string

1:56:00

uh for the most part that's right i'm gonna go ahead and copy the date as it's defined

1:56:06

on the validator though no clue what ll does

1:56:13

all right and we'll do another one again not sure if this is worth it might end up changing it but publish that time

1:56:19

string return pull chat to format perfect

1:56:26

is hours hours uh the 24 hour clock or is that the 12.

1:56:33

well we'll we'll we'll see it should be the 24 actually because we can't log stuff out and it went at 17.

1:56:39

so it should be okay okay and then we should be able to just use those two to actually set the

1:56:45

default value for these so we do post dot publish at

1:56:52

date string otherwise that and we do post dot

1:56:59

publish at time string otherwise the flash

1:57:04

so back in here and perfect so we can see that we got 11 18 20 21 at 1102 am which

1:57:12

was the time that i last saved this uh and if we change this to five

1:57:19

o'clock p.m now that should save two

1:57:26

perfect so that seems to be working

1:57:36

okay um

1:57:43

what else what else what else did i miss anything

1:57:49

see we need to find a wysiwyg editor which i will do off stream we need to get images at some point but

1:57:57

i need to add in

1:58:02

my environment variables to be able to do that and i

1:58:07

store all of my assets within a single bucket for all projects so i that's not a

1:58:13

secret that i want to share it is a super secret so i'm going to hold on to that [Music]

1:58:19

we could get it to where it just saves locally onto the disk but that's vastly different from

1:58:25

how i need to save it so we'll skip that for right now uh let's see

1:58:33

we can go ahead and start rendering stuff out i guess um

1:58:38

see so we have those posts that we that i accidentally created earlier that have no author let's go whoops go ahead

1:58:45

and delete those okay and then

1:58:51

oh you know what we could do the states so there's various states here

1:58:57

um if i can find my enum for it so states

1:59:03

so we have whether it's a draft whether it's in review unlisted public private archived or

1:59:09

declined which i've yet to use but it's there just in case i need it so we can set up kind of like a save as

1:59:19

and then allow the user to select between these five values here so to show you what i'm

1:59:25

currently doing for that if we come into here i've got a publish now button save as

1:59:31

draft save as unlisted save as private so if i save this one as private you would no longer be able to find this

1:59:37

post anywhere on the site however since i am logged in and am an administrator

1:59:42

it would still did i leave it there with me no yeah no it would still show for me

1:59:48

uh unlisted i believe i have that set to where it would still show everywhere on the site

1:59:55

no no it wouldn't show anywhere on the site but you would still be able to view it that's what that is and then draft would be it would go as a work in

2:00:02

progress so it wouldn't be anywhere um

2:00:08

so let's go ahead and set those states up

2:00:13

so that we have them ready to test whenever we actually query out outside of our studio

2:00:19

so let's see

2:00:28

how do i want to incorporate that so i think we'll do another hidden input

2:00:38

is state id the default value for this will be post

2:00:45

dot state id

2:00:51

otherwise probably draft um so the other thing

2:00:57

that would be good is to provide those states into the

2:01:05

update and create page so let's go ahead and do that so const states equals

2:01:14

uh we'll just do state we'll do it as the actual enum right

2:01:19

and then consts no i don't think we need state descriptions at all so we'll just leave

2:01:25

it as states and plop that in there and then we'll do the same thing

2:01:32

for edit

2:01:42

so now on our creator edit we should be able to do states dot

2:01:49

draft and have that pre-populate with whatever

2:01:54

that state ideas which actually uh we have them setting to use the default of five

2:02:03

so i don't remember if that was a database default

2:02:08

state id no no no it doesn't have a default so it must have been something that i

2:02:13

temporarily plopped in the controller earlier today so

2:02:20

let's go ahead and test this out with a new post so that we can verify that it actually does show up

2:02:26

with the states.draft value so coming in here create new post

2:02:33

let's go into inspect and i don't need all of that

2:02:38

shrink how do i get that back over there this one yeah all right and go into our form

2:02:45

and there's our hidden input with a value of one is one

2:02:53

yes so that is the state of draft perfect

2:03:00

so now i guess we'll keep this pretty similar to how i currently have it where it's just four buttons um and then the user can

2:03:07

select between them and then clicking on a particular button will change

2:03:13

um well let's think about that for a second because if we do it that way i've done

2:03:19

this before how did i do it see so now the issue with having the buttons separate is that

2:03:27

the they'll still need to be submit buttons that kick off this request i think that's how i did it i didn't have

2:03:32

them as submit buttons i just had them as buttons that changed that value

2:03:37

and then submitted the form afterward so it would be something like this so

2:03:48

let's see no what am i doing

2:03:54

function uh save

2:04:00

state id switch

2:04:07

the state id that is eerily close yes

2:04:15

uh it's a little off but it's all right so what all states do i have let's go ahead and post plop those over on the right

2:04:22

hand side so states

2:04:27

okay so we have draft right there instead of published

2:04:35

see there is no in review state to be had so we'll do unlisted

2:04:41

and then instead yeah no that's fine well hold on a minute is there really a purpose to have this if

2:04:48

no if you're providing the state idea there's no purpose to have that so you just do

2:04:55

this i just realized that all of those case statements were going to have the same output

2:05:00

so there we go so now we just overwrite that value and then yep submit the form

2:05:08

so then we have our buttons which we will place outside of the form as

2:05:13

non-submit buttons so this would be button type equals button

2:05:25

do unclick save as

2:05:31

states dot public and this would be the

2:05:38

publish button okay and we're going to have something very similar for

2:05:45

unlisted uh draft unlisted and private yeah

2:05:52

so draft unlisted

2:05:58

and private

2:06:03

okay

2:06:13

so now that should change the state id and

2:06:19

then kick off the submission of the post form

2:06:25

so we'll save that all right we have our unstyled buttons here looking all fancy

2:06:32

so we can see create a new test post

2:06:38

and we had the others default to public so first we'll go ahead and try draft

2:06:43

so we'll save post as the draft if i can find the button save as draft right here so go ahead and

2:06:50

click that all right nothing happened uh we're using a nurse or no not inertia

2:06:57

um alpine so i don't know why i'm not using that here

2:07:03

definitely could if i can remember how that works it's changed since i last used it used

2:07:09

it there's really no need to what

2:07:25

see if we're getting there

2:07:30

it's been a minute since i've done direct attribute actions

2:07:36

so we're not getting an error so i guess i'm doing that right but

2:07:42

this probably needs to like be different somehow

2:07:57

oh man let's see

2:08:05

i know that's doable maybe it's not on click

2:08:16

i don't like w3schools but i'm gonna yeah see i'm sure

2:08:21

they're they're doing it i should be able to do it too yeah so we got unclick maybe it's not called

2:08:26

save as no it's called save well i like savios better let's call that save as

2:08:33

okay test draft save as draft there we go now we have

2:08:39

test draft there let's verify that its state id is one where's my refresh button there it is

2:08:46

where's my state id nope it came through as five

2:08:52

is that because of how i'm setting the state id temporarily or is that because it didn't

2:08:57

send up with the correct state id let's take a look so store

2:09:04

state id public so all right let's first well let's leave it as public right now because

2:09:10

we're still testing so it must not have gone up as a member of data

2:09:16

either that or our well know if our validation plugged it out

2:09:22

then i'm either not sending it up with the right name or our validation came back as an error

2:09:29

and we went to the index page so our validation didn't error out so state id is just oh it's not in there

2:09:36

at all i thought i did it i didn't know you got post type id

2:09:43

all right so i didn't do state id in my band let's see state id

2:09:49

it'll be very similar to post type id so this will be enum type optional because we have a default

2:09:55

that we're going to set on the back end object values

2:10:02

[Music]

2:10:08

okay now that should work and um we'll leave i want to change the spec to

2:10:16

why are you ready now state id is specified more than once

2:10:23

ah we'll look at you okay

2:10:30

well then we will do this oops if

2:10:35

not data dots date id then state id equals

2:10:42

i do want to ultimately use draft for this but while we test out that we're able to set

2:10:47

draft whoops that needs to be data.state id i'm going to set it to public if it

2:10:52

doesn't exist so now we can just change this to be data

2:11:00

and now that hasn't read squiggly so why do you have a red squiggly

2:11:07

state id are incompatible so i think that comes back to i didn't use

2:11:14

the enum type to describe where is state id it's number or null so

2:11:21

really instead of number here that should be the enum

2:11:26

let's see if that fixes it

2:11:33

types of state idea incompatible type stream state or undefined is not assignable to stipe type

2:11:40

state null or undefined okay so we have it's nullable

2:11:50

uh

2:12:18

okay

2:12:24

well so the issue is so i could fix this on my model

2:12:31

um what i think i think putting null or undefined

2:12:36

there would probably fix it maybe or probably need to also handle the string portion of that

2:12:43

which i don't want it to be a string so um but whoops instead of

2:12:49

doing that approach how do i open up my terminal is that ben open my bad

2:12:55

um i'm instead just going to

2:13:00

really i don't think that should have been nullable in the first place it's definitely required because of a postdoc of a state i have no clue what to do

2:13:06

with it so that really should be required

2:13:12

so that takes care of one portion of that i don't know why that's still saying that's undefinable

2:13:24

um state or undefined oh because it's re

2:13:38

all right well i'm going to change the validator regardless because we are definitely sending up some form of a state with it so i'm going to change

2:13:45

that from well really that just needs to be a numbered not necessarily

2:13:51

let's see let's see sorry i'm thinking out loud uh

2:13:57

[Music] type string or state now so yeah we need

2:14:02

it to be a number not a string that's the underlying issue

2:14:08

is that coming through with how i'm setting it here i don't think so because that's definitely a number that i have

2:14:13

set

2:14:19

objective values enum uh yep there's where it's coming through

2:14:24

string or state i want that to be number or state

2:14:30

let's take a look at the validator documentation here i don't know if there's a way to do that

2:14:40

i feel like i've come across this before but i don't remember what my solution for it was or if i had a look that's the

2:14:45

wrong one validator you know you know you know where are you

2:15:16

okay

2:15:32

does that fix it no

2:15:45

you know it's under because it comes back with the data all right

2:15:58

well now i have it set as a const which i don't want and it's no longer a member of my data

2:16:05

all right let's go ahead and just keep it simple so

2:16:16

dot number optional

2:16:24

is there a rule where i can say is in there's not in

2:16:32

no i can make that rule

2:16:37

but for right now just to test and make sure everything is working okay

2:16:44

saving wise let's go ahead and just save the state id as a number probably going to run into the same

2:16:49

issue with the post type id so i'm going to go ahead and just change that to a number right now as well

2:16:59

okay and

2:17:04

oh no still red squiggly argument of type number is not assignable to a perimeter of type string

2:17:09

so number on identify well

2:17:19

all right which makes that redundant which makes that valid okay there we go

2:17:26

so let's go ahead and test this out so our

2:17:33

draft did not save as a draft but we can go ahead and edit it and then save as a draft and it should

2:17:40

no i didn't put that in that i just put that in store dang it all right so then we'll go ahead and delete test

2:17:48

draft and we'll recreate it test draft

2:17:53

save as draft now if we check it out there we go now the state id is one

2:18:04

so

2:18:10

let's go ahead and apply that to the edit as well

2:18:16

so all we need to really do is add that check to it no

2:18:21

that's not needed because it will already have a state id on it so if a state id is not

2:18:28

provided then we don't need to do anything with it so really edit or update should already be

2:18:34

taken care of on that front so if we edit our test draft

2:18:40

to test unlisted

2:18:45

and we save as unlisted now it should be what two

2:18:50

three three all right so it's three let's verify that that's actually correct

2:18:55

so go find state all right it's right over here just click on

2:19:00

unlisted is three yes so and then we'll test private which is four

2:19:15

which is working all right and then we will test finally

2:19:21

our making it public again so test public as publish which should now make

2:19:28

it five all right so that all seems to be working so

2:19:33

not pretty but working cool so i think that is where we are going to

2:19:39

end it off today i've got to start my saturday so thank you all for watching uh

2:19:45

hopefully it actually went okay um

2:19:51

i know youtube told me to check my video resolution because it's 4k which is not optimal but

2:19:56

it seems like the stream from when i can tell went okay i'll check back hopefully it went okay

2:20:03

but yeah thank you all for watching i appreciate your support and have

Join The Discussion! (0 Comments)

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

robot comment bubble

Be the first to Comment!