Plan and validate fields0:00
So first and foremost we want to validate the data. Then if that goes well, we want to store the uploaded image, then yes, we want to create a new Puppy instance but attach to the authenticated User. And if that also goes well redirect to the same page. That sounds like a solid plan. You reckon we can do it? Let's try. All right, step one, we are going to take the request and validate all our fields. So we have three fields, a name, trait and image.
and validate all our fields. So we have three fields, a name, trait and image. So we want the name to be required as a string. We want the exact same for trait. And then for the image, it's also required, it has to be an image. We accept jpeg, png, gif, svg, yeah maybe and max 2048. So I'll accept this, but I will beef up the max capacity to 5120.
So I'll accept this, but I will beef up the max capacity to 5120. And by the way, allowing five meg images is pretty scary. But in the future lesson we are going to optimize the files uploaded. So even if they're gigantic, whatever we store and then serve to the browser is going to be much smaller. Alright, so let's go with this for now. Uh, and if we succeed, let's die and dump the valid message.
Uh, and if we succeed, let's die and dump the valid message. So you can see all three fields are required. And if I go to the new Puppy form, the fields are also required on the front end, which means that if I try to submit the form, it's going to force me to add some values. So it should never trust just the front end validation. But here I'm going to remove the required attributes on all of the three fields so
But here I'm going to remove the required attributes on all of the three fields so that I can actually submit the form without any fields. And so I've submitted the form, it's sent me back to the top of the file and I have no idea what happened. Did it work? Did it not work? If I scroll back down to the form, the form is empty. There is no messaging whatsoever. So we didn't get this valid message. So obviously something wrong went here.
Inspect validation errors2:23
So we didn't get this valid message. So obviously something wrong went here and it never reached that point. We don't have any messages in the console. So let's try one more time with the network tab open. So I will submit the empty form. So we submit an empty form and then we get a 200 response. But if you look at the preview of the response, you can see that in the props uhhuh we have an errors object that has validation message that are trying to tell us, Hey,
that in the props uhhuh we have an errors object that has validation messages that are trying to tell us, Hey, the image field is required. The name field is required, trait field is required. All right? So we need to find a way to get these error messages easily into our front end so we can display them and while they're available with the use page hook that we've used in prior lessons, you can also access the errors directly from the use form
Expose errors in form3:10
that we've used in prior lessons, you can also access the errors directly from the useForm hook in Inertia. So let me show you that in the new Puppy form, in the useForm hook, I will also go and access the errors object, which as you can imagine is going to be pretty handy. So before the form or maybe after the form, let's try to go and have a pre tag that renders the JSON string of the errors object.
and have a pre tag that renders the JSON string of the errors object. All right, and I will scroll down one more time. You can see that it's side by side. So maybe let me have a quick fragment so I can put the pre tag after the form so it shows below down here. Okay, and so let's submit an empty form. We scroll back to the top, and by the way, you know how to fix this.
We scroll back to the top, and by the way, you know how to fix this. And if I go back down, we now have errors showing up in our front end next to the form, which is super good. Alright, so let's see if we can display this error under the name field, this error under the trade field and so on, instead of just having a pre tag that dumps all of them. So before I forget
Preserve scroll on submit4:13
that dumps all of them. So before I forget because it annoys me every time in the post action here, we can hit a route, but then we can also pass some options. And here is where I want to have the preserveScroll set to true. So we stop going back up the page every time. So now let me refresh the page. So we have an empty errors object and when I submit we're going to stay at the bottom.
Show per-field errors4:32
So we have an empty errors object and when I submit we're going to stay at the bottom and it's going to show the errors. So as you can see, the errors is an object with a name key, a trade key, and an image key, which are the field names. So with a bit of luck, we can go in each field like the name field here and below the input say do we have errors that name? If yes, let's have a <p> tag. Let's go class name text-sm text-red-500.
If yes, let's have a P tag. Let's go class name text-sm text-red-500. And here we can display errors name. So let me copy that and I will scroll down to the trait field and do exactly the same but with the trait. And one more time for the image field, I will paste that, but with errors image. So now I should be able to remove the string output. And as you can see, the error messages is being shown under every field.
And as you can see, the error messages is being shown under every field. And I imagine if I had Simon here and submitted the form, again the error would disappear here. That is starting to feel pretty useful. So let's maybe make the error message a little bit smaller and add a little bit of margin top and continue the implementation. I could create an ErrorMessage component,
and continue the implementation. I could create an error message component, but here I will do changes in the three places. So let me select the three elements and I'll go text-xs and empty-1. I think it's just gonna look a little bit better. So remember we try to up the valid string if the validation has succeeded. So let's add some values in all three of the fields. And what I'm hoping is that it's going to trigger the
So let's add some values in all three of the fields. And what I'm hoping is that it's going to trigger the valid successful validation step in the code flow. All right, cool. So looks like our first step, the data validation is working and we are even showing some nice error messaging on the front end. So let's go to the next step in our implementation. I will remove the dump here. And the next thing we want to do is store.
Store uploaded image6:29
I will remove the valid dump here. And the next thing we want to do is store the uploaded image. So we are receiving that image, but we need to store it somewhere technically because the image is required and we've validated that it is matching the validation, it should be there. But just for some defensive programming, let's still assume that it might not be there.
But just for some defensive programming, let's still assume that it might not be there. And go. If the request has a file that is called image, then we want to store that image. Remember in storage/app/public/puppies. So we'll do $request->file('image'), and here we for sure know that it's here because we've checked here and required it. And then we will call the store method, put the image in the puppies directory.
And then we will call the store method, put the image in the puppies directory and with the visibility of public because we want people to be able to see this. So that is going to store the image in our puppies directory, but we also need to know how the file's going to be named. And then we want to store that file name or that file URL into our database. Remember we have this imageURL fields in our database.
or that file URL into our database. Remember we have this image URL fields in our database. And so we need to grab the path of this image we're storing so we can then pass it to the create Puppy instance. So here's what I'm going to do. I'm going to store the results of this file storage in a path variable. Then I'm going to, before the check, define a imageURL variable and set it to null so that we can assign it just like this.
before the check, define a imageUrl variable and set it to null so that we can assign it just like this. But wait up copilot again defensively. I'm going to check if we have a path. And if we do not have a path, I'm going to redirect to the same route with back and then have an error mentioning that the image fails to upload. So basically if we're not able to obtain this path, then it means something went wrong.
So basically if we're not able to obtain this path, then it means something went wrong. So we short circuit, we do not create the puppy, we just go back with the error. If we do get past this check, we can then assign the path to this imageUrl. So imageUrl. And we are not going to use asset, but we are going to use the Storage facade here to create a URL based from the path.
but we are going to use the Storage facade here to create an URL based from the path. So that's going to structure the path to the image in a way that the image URL field wants. And if you remember, if I go to the puppy cedar, we were doing exactly the same here, Storage::url, and then we were passing the path here. Alright, we're making good progress. So what we could do now, let's try to dd the image URL. If things went wrong, we will have null.
So what we could do now, let's try to dd the image URL. If things went wrong, we will have null. But if we have a URL, it means that a file was created, stored, and the path was added to the image URL. So let's try that. We'll go Simon, cool. And choose the same image we always do. And when I click add puppy, excellent news, we have a file in storage/puppies starting with F-W-G-M-F four. So if I go in storage/puppies
with F-W-G-M-F four. So if I go in storage/puppies and look for FW GM F four, there it is. The image has been uploaded along the other few tests that I've done off camera. As you can see.
