Placeholder Image

Subtitles section Play video

  • in today's video, we're going to be looking at creating the index new and create fuse for the books, as well as flushing out the homepage of our site.

  • We're going to be looking at doing multipart form up loads with files as well as some more complex searching that we didn't get into with the author's page.

  • So let's get started now to get started was first, look at what we're going to create.

  • So we have an idea of what we need to do is out of our routes and models.

  • We're going to be creating this search books page, which is going to have a title published after and published before Field that we can search by as well as it'll lists all the books down here that matched that search.

  • Also, we're going to have an ad book page which will allow us to add a title to a book and author, which we select from a list of authors that we've already created.

  • We can select a published A Here we can select page count will just stay 200 for example.

  • We select which book cover that we want to use, and we can add a description, your book, and then we can hit, create, and that will bring us back to this book page where, as you can see, we could see the title of our book here and we can search.

  • So if we titled our book title, for example, in this case we concerts and we could see that book.

  • But if we search for something that's not the title, you'll see it does not show up, and this is what we're going to work on.

  • Creating these pages are very similar to the pages that we created for authors in the last video.

  • So instead of our Roots folder here, let's take our authors file, let's copy it and change it to be called books instead of called authors so we can call its books dot Js.

  • And instead of here, we're going to find all of our routes are books.

  • So the first thing we can do is we can select our book model instead of our authors model, which we have not created yet, but that's okay.

  • This is going to bear all books route, and we'll just believe everything inside of these routes for now because we don't really want to worry about what's inside the ropes.

  • We just want to worry about the actual rouse themselves.

  • So we have a great book route and our new book, Crabs, and there we Go and these methods inside of here for these different functions.

  • They're going to be very similar to what we created for the author.

  • But since the book is more complex, they're going to be quite a bit more complex.

  • The next thing that we want to do is set up our model for our books, which again we can copy our offer model here, change your name to be book Js, And then, instead of corn and author schema, we'll call it a book schema.

  • Give it a title here, a book.

  • You can change this variable to book ski myth, and our book is going to have a bunch of different properties inside of it.

  • While offer only had name, the book is going to have a title.

  • We're also going to have a description which is going to be very similar to the title, and the description is not going to be required so they can remove this required field here.

  • Changes to be description.

  • This will just allow us to add a book that has no description.

  • We're also going to want a public date for our books.

  • And this published date is going to be of the date field so we can just set that type here is equal to date, and we want this to be required.

  • So where s that required?

  • True.

  • We're gonna have a page count.

  • This is going to be an imager.

  • So we'll say type is number.

  • Since in mongo, D B uses the same types as Jason, which is going to be number for any number.

  • And we also are going to require this so we'll stay required true.

  • Then we're going to need another date.

  • This day is going to be the created at date.

  • And the reason we're having a created at date is because inside of our application, our main page is going to show all of our recently added books in order from when the most recent one to the least recent one.

  • So we need a date at which these books were added to the application.

  • So we know which books were created when this is going to be, of course, of the type date, and we want to require this, obviously And also, we want to set this to a default value.

  • We always just want to set this to the current date.

  • So we can just say date dot now And this will set the creator that date to the current date every time that we create an object so we don't have to manually set this every time we create a book.

  • Next, each book is going to have a cover image, and instead of actually passing in the image itself into the database, we're disappointed past the name of the image so we can restore a single small string, and then we could store the actual image itself on our server in the final system.

  • Since you always want a store files in the file system, when you can, we're gonna put this as a type of strength and we're also going to be required true for this, then lastly, as we all know, every book has an author, so we need to set an author type for our object.

  • And this is going to be a little bit different because we want to actually reference the author from our authors collection that we created over here.

  • So instead of putting the type here to be some kind of author type or I d type we're going to be using the mongoose dot schema dot types dot object i d.

  • And this essentially is just referencing another object.

  • This is just the I d of the author object.

  • This is telling mongers that this reference is another object inside of our collections.

  • So we also want to put this to be required true, since every book must have another And then lastly, since we're referencing something else, we need to tell Mongoose what we're referencing.

  • So we can say we're referencing Theo author collection, which we created earlier, And this author name must match the name that we set here for our model.

  • Now that's all we need to do for our model for now.

  • So inside of our server, what's actually used the book routes that we created so we can copy this off The variable changes to book changed this to books.

  • So now we are have all of our book droughts in here and down here we can tell our route that we want all of our slash books routes to Goto, our book writer that we created looks like a spell that here we go.

  • And as you can see in her application over here, when we're at books, it's just slash books at book is going to slash book slash new and so on, just like it was for the author's, it'll be slashed.

  • Authors and Slash authors News.

  • Let's go back to our route here for our books, and we just want to send some information to the page so that we know are rendered in these pages.

  • So we'll say rez dot send all books copy is down, we'll say new book and right here will also do create Look that what?

  • We actually can see these rocks when we go to them.

  • And then let's start up our server and can run.

  • Don't start, which we created earlier.

  • That'll start up our server locally.

  • We see that everything works successfully.

  • So if we open up our local host Port 3000 refresh this zooming in.

  • So it's easy to see and we go to our slash books page.

  • You see that we get all books and we can go to our slash books slash new, and we get new book.

  • So we know that these routes are working perfectly and they're hooked up as we want them to pay.

  • Now we can actually work on implementing them in the same mother we implemented, our author wraps.

  • The first thing we want to do for that is actually add links to our headers because right now we need to type in the euro manually.

  • So if we go into our partial here for our header, we could just coffee these two author links and change these to be book links.

  • So we'll change.

  • Offers two books here, and we'll also change this to, say books and will say this to say, add author for at book.

  • I'm sorry we'll save that refresh.

  • And now we have links to our books page, and we'll suddenly tore at book page.

  • Now the first thing that we want to do is actually set up our new books page so we can add books which we can view later.

  • Let's look at this ad view book page.

  • Resume this out so it's easy to see and you see that we need Fields for the title author published eight page count, cover and description.

  • So let's get started with that.

  • First, we need to create a new folder here for our books views, because this is going to be the same as our rap name up here to be easier.

  • And we can just copy the new view here that we're using for our author.

  • Hasten into books because it's gonna be very similar.

  • We'll say we want to create a new book.

  • The action is going to go to the books Euro instead of the author's Euro and instead of one we canceled.

  • We want to go back to the books instead of back to the authors, and we'll still render a form fields partial in here just like we did for authors.

  • So let's copy that partial into our books page here and now we need to just change this to be all the book fields that we want.

  • So if we look over here, we see our first field is going to be titled type of text.

  • We're going to give it a name here of title so that we can reference this on the server and this will be our book, that title, which we're going to be using as the value.

  • And let's just copy this.

  • Hey, sit down and do the same exact thing here for author.

  • But author is going to be quite a bit different because this isn't actually Text Field.

  • This is a select box.

  • As you can see, we can select a different values for author from A list.

  • So we need to actually create a select input here and populated with all the offers to do that we need to look through.

  • All the different authors are Paige and one way that we could do that very easily.

  • It just by accessing that authors collection, we could say dot find passage in that we want to find everything and then we could say dot each, for example.

  • But this is really not the best way to do this because this is a synchronous.

  • We don't want to render all this code inside a bar.

  • A few files.

  • We want this to be inside of her actual server.

  • So we're going to remove this and actually pass a variable into our view here.

  • What, you're going to be called authors, which is all the authors that we want to look over and inside of our actual server, we're going to pass the author's very book down into our view.

  • Next, we can actually create each one of our options.

  • So to do that, we create an option here.

  • We want to slip the label.

  • This label is going to be equal to hear the value of our author dot name so they can say author dot name is going to be the label that the user will see way want to set the value here to be the actual idea of the author.

  • So we'll set that author that i d.

  • And there we go.

  • That is our option variable created.

  • But if a user has already selected an author, we want to set that option as selected.

  • So we're going to create an if statement here.

  • This if statement is going to say that if the author di Di is equal to the book dot author and remember the reason we're doing booked out author here instead of booked out author, that I d is because this author field is actually I d.

  • If you remember, instead of our model, this is a I d object.

  • So our author is actually I d of the author inside of our book, so we can check to make sure that the I d of the author is equal to the author of the book I D.

  • And if so, this is going to be our selected value.

  • So this option here, we'll just set it to be selective.

  • You just put the selected attribute on your option, and now this is a selected option.

  • But if, for example, this author idea is not that so we'll put an l statement here.

  • Then you want to do our option, but without the selected attribute so that this will be de selected for our options by default.

  • And then lastly, we wanna put in our brackets here so that we know that this is right there.

  • This is going to be opening up our l statement.

  • And finally, we need to close out our brackets for l statement just like that.

  • And this is the hardest part about writing your code in the server like this is you need to make sure that you have all of your opening and closing brackets properly lined up inside of these tags here, with the percent simple so that the server knows where to open and start.

  • These if statements and these loops.

  • And that's all the code that we need to do in order to render this author's loop right here.

  • Let's remove this extra input here, save this and actually view what we have.

  • So we can go to our ad book page and you'll see that we're actually not rendering anything on here.

  • And that's because inside of our server for our books, forget this.

  • We're just doing rez dot send all books.

  • So instead of doing that, we actually want to render our new page that we just created here.

  • So instead of here, we want this to be an asynchronous function.

  • As I mentioned in the last video, we're going to be used in a sinking dysfunction.

  • Since it makes working with Monty, it's much easier.

  • So the first thing inside this sink in a statement we want to do is we want to create a try and catch block so that we catch any airs from our asynchronous code.

  • And since we're passing the authors into that page, we want to first get all the authors.

  • So we'll say that our authors are going to be equal to the author model dot find.

  • And we just want to find everything what has passed a heavy object.

  • And we wanna wait this so that our code will wait here until it gets all the different authors.

  • We also need to make sure that here we employ our author model so we can actually use our offer model in order to get all the authors So it will pace that and they're just like that.

  • And then we want to actually create a new book.

  • So we'll just say our book is equal to new book, and this is just like we did with the authors.

  • We create this new book so that when the user modifies it and we send back data saying that they incorrectly entered their data, we can populate the field so that they already created, and that's all we need to do here.

  • We'll catch any heirs.

  • And if we do get in there, what is going to redirect the user to the book's page so we'll just stay here slashing books and this is going to send them back to the books in case there's an area getting any of this data.

  • But if there's not an air getting it is data, then we're just gonna say rez dot render And we want to render that book's page that we just created still say books slash new.

  • Make sure you put our slash at the beginning here, and we want to pass some variables into that.

  • So we're gonna pass the author's variable that we created as well as the book Variable just like that.

  • And now we have all the author is being sent to this new page as well as the book information.

  • Now, if we save that and refresh our page here, you'll see that we couldn't air.

  • That's because I accidentally put this slash at the very beginning here so we could just remove that we save our page and refresh, and you'll see that we get our title being created here, as well as a list of authors inside of her application.

  • And since none of our authors are currently selected, it'll just like the very 1st 1 in the list by default.

  • So now let's go back to our farm fields here open up what we should be having inside of our page and you'll see that the next thing we need to do is the published date.

  • So this is going to be very similar to how we did our title.

  • Just paste this down here.

  • We're going to want this to be the publish date.

  • We're going to want to get this input a type of date.

  • Since this is going to be a date field, we want to set the title here to be published date, and the value here will be published.

  • One thing that we will notice, though, is that this value here for this published date inside of our Jason object of book is not in the correct format to be used inside of this input data opted, so extra need to convert this to the correct notation.

  • So in order to do that, we're going to do a little bit of tricky job a script here.

  • So I'm gonna put this on a new line so that it's easier to see what we're doing.

  • We're going to first say that if the published book is equal to know because we first want to check to see if the object is no before we actually try accessing it.

  • And if it is no, we're going to be using this turn ery operator.

  • So this is pretty much like an if statement, so we'll say if it is no.

  • Then do what's after the question mark, which is just going to be returning empty string as the value.

  • But if it's not?

  • No.

  • So that's what this Colon is.

  • This is essentially the else section.

  • So if this is false, it does everything after the colon and what we want to do here is we want to say, look dot published eight and then we want to convert this to the correct format so we'll set too high.

  • So string.

  • And we just want to split this on the tee variable here because this converts it to a string that has time inside of it.

  • And we don't want the time section.

  • So this string will be date, then t so it'll have date here.

  • So if you like 2019 0909 for 19 and then we'll have tea, for example, and then it'll have like 12 23 for example, for time, so we only want this date section of its.

  • We split it on that tea and we just get the first section of that string which will get us this date section since we only want a date and out of time.

  • So now that we have that all done, this will actually populate our published a field for us and it would be safer.

  • Refresh.

  • Over here we have our published date field showing up right here and is defaulted to nothing for now because there's actually no value for published date because it is no to make this form a little bit easier to work with addicts.

  • Everything's on one line right now.

  • Let's just wrap all of our different inputs in dibs to break these up on two different lines so accredited here, draft this section also do the same thing for our author in dental.

  • This this is just going to make it a little bit easier for us to visualize this form instead of its non created CSS state that we have here right now.

  • And there we go Now If we say that, refresh our page.

  • You see that over inputs are on a different line, which makes it much easier to follow.

  • What's going on now.

  • Let's move on to our next input, which over here we can see is our page count will copy over published eight, and we'll change this to be here instead of Polish state.

  • It'll be page count.

  • We want this to be a number field instead of a date field.

  • Change the name to be page count, and we don't have to do any fancy transitions for the value.

  • So we'll just set the value to be equal to book dot page count and remove all this other fancy stuff that we did for the date.

  • Fields were also just going to put a quick minimum value on here, which is going to be equal to one because we could never have a book that's less than one pages long.

  • Now I can move on to our last two sections, the first of which is going to be our cover so we can change page count here to be cover, and instead of putting our name here to be cover image name because this is what the variable is our model, this isn't actually going to be the name of the image.

  • This is going to be the file itself.

  • So we're going to set us to cover so that we know that this is the actual cover file image, as opposed to just the name.

  • We also want to change the type here, to be filed instead of number removed the minimum and also, unfortunately, file inputs don't allow you to set a default value.

  • So we have to remove the value field as well.

  • And this is just always be a blank file and put that we can always add to now.

  • Lastly, we want to add in the description.

  • So change this description and description is a bit different because this is a large text Terry, as you can see, which supports us being able to use the enter key as well as other keys inside of here.

  • But you can't use inside of a normal text input, so we need to use what's called a text area.

  • So said this to be a text area as opposed to a input of type text, and the text area also needs a closing tag of text area because this is where all the text for your text.

  • Terry is going to go.

  • We also want to set the name here.

  • So the name for this is just going to be a description.

  • And then instead of having a value property on text area, we actually need to put the value inside of the text area here.

  • So what we'll do is we'll just have this'll value instead of here will say book dot description is the value for a text field and every goat that's going to have all the information inside of here that we want.

  • Now if we go over there, Pidge, refresh this and zoom in a little bit, so it's easy to see.

  • You see, we have our title.

  • Author published a page count, which is a number field that can't be dropped below one.

  • I'm getting the down can.

  • I won't let me go below one.

  • We have our file and put where we can choose our input for our file as well as the Description field.

  • But we can put anything for our description that we want now that we have our entire form completely built.

  • What's working, actually hooking up our back into that we can use that form in order to create our books.

  • So inside of our wraps file here we could go down to our great book crap and in here is where we need to set up all the logic for creating our book, which is going to work somewhat similarly to how we did this for authors again is going to be a synchronous, as was mentioned in the function definition here because we're going to be using mongers and awaiting instead of using callbacks.

  • And the first thing we want to do is actually construct our book object.

  • And we're going to do that.

  • We've got a new book, Variable.

  • We're going to set it equal to a new book.

  • But instead of defaulting it to nothing, we want to actually set all of our different properties for a book.

  • The 1st 1 is going to be our title.

  • What is going to come from the rip less not body DOT title then we're going to do today is excellent for the author author of our book is going to be a request that Body Doc author I wish, Dave, it's going to be again exactly the same here except for we need to wrap this inside of new date because this request our body about published date is actually going to return to US string.

  • So we need to convert that strength into a date using a new date function here, which will give us an actual date we can store on her database and then we can do the page count.

  • So it was that page count equal to request Stott body dot page Count and lastly, the description of our book here, which is request stop body description.

  • Here we go and you'll notice that we're not actually putting the cover image name inside of this book object yet.

  • And that's because we first need to create the cover image file on our file system, get the name from that and then say that entire book object.

  • The easiest way for us to do that is to use a library called Moulter.

  • So what's install that library would've still in P.

  • M.

  • I moulter and multiple allows us to work with multi part forms, which is what a file form is also, In order to use files, we need to change our form inside of our view page here to be of the type of multi part form.

  • In order to do that, we need to set the E and C type to be equal to multi part form data, so slash form data.

  • And this tells our server that our form is going to be sending multipart data, which could include a file.

  • What?

  • Say that and go back to our server here and instead of here, we had to use that multi library in order to create the actual book file to do so.

  • Let's go to the very top of our page here and import that moulter file.

  • So we're going to say a variable called upload is going to be equal to set up for Moulter.

  • So before we could do that, we need to require Moulter so constant multi equals require Walter.

  • And then we can use this multi variable in order to call the function on it, which is going to help us to configure Moulter in order to be used with our project.

  • The first thing we need to do is tell us where the upload is going to be, so we want the destination to be some form of upload path inside of her project.

  • And of course, we're going to want to put this inside of our public folder inside of another folder called Book Cover names or something like that.

  • But we don't want a hard code this inside of our folder here for our server.

  • We want this to come from our actual book model.

  • So is open up our book model and create a variable here inside of it that we can use to set up this.

  • We could just call this to be a constant variable called cover image Face path.

  • This is just going to be the path to where all of our comer images are going to be stored on.

  • We want a store that inside of our uploads slash book covers folder, which is going to be inside of our public folder here.

  • Now that we have that, we also want to export that variable down here.

  • So in order to do that, we need to use our module about exports and we don't want to export.

  • This is the default.

  • We want to export this as a named variable, which would be called cover image based path.

  • And we'll set that to our cover image Base Pack.

  • Now we can actually import this inside of our books route.

  • In order to do that, all we need to do is first take that variable we create in our book model and use that to create the path that we need.

  • But before we could do that, we need to import a library which is called Path built into no Japs.

  • And we could just do this by saying require and putting in path here as the name of the library that we're going to require.

  • Then we can create our upload path.

  • Variable this upward path variable where you just call a footpath.

  • And we can use this upload path by setting a equal to path dot Join, which is going to combine together Two different paths are First Path is going to be our public folder.

  • And then after that, we're going to use that book variable so we could say book dot cover image basepath.

  • Now, this upload path that we see here is going to go from our public folder into that cover image based path we created.

  • We can use that right down here to say that this is going to be upload path for our destination.

  • The last thing that we need to do is actually filter files.

  • We're going to use file filtered, which allows us to actually filter which files are server accepts.

  • This is going to take a few variables.

  • It's going to take the request of our file.

  • It's going to take the actual file object as well as a callback, which we need to call whenever we're done here with our actual file filter.

  • So let's create that arrow function, and it's out of our final filter here.

  • We just want to call that callback function first permit we want to send it is just going to be no, since we have no error because this is an ever perimeter and the second option is going to be a boolean.

  • That says, true, if the file is accepted or false, if the fire was not accepted and all we want to do is accept image files, so we want to set up a variable here, we're gonna call this a image mind types variable, and this is just going to be in a rape that has all of the different image types that we accept.

  • And these are default variables that you confined just by googling image mind types, these we're going to be available.

  • And they're always exactly the same from the server.

  • So in that case, we're going to support J pigs, which is images slash j.

  • Peg.

  • We're going to support PNG, which is going to be the same thing images slash kanji.

  • And lastly, we're going to support gifts, which is images are.

  • Now that we have all that set up, we can actually work on setting up our route to accept files.

  • So the first thing we need to do is added another perimeter here, we're going to take that upload variable.

  • Tell that we have a single file being uploaded in this form, and it has the file name of cover.

  • This variable main cover here is whatever you set the name of your input to be.

  • So we set our cover input here to have a name of cover.

  • So now it's telling us, Moulter, that were uploading a single file with the name of cover, and it's going to do all the work behind the scenes for us to create that file uploaded onto our server and put it in the correct folder.

  • This library is also going to add a variable to our request here.

  • What is going to be called file?

  • So request dot file.

  • He's going to equal the file that we're uploading to our server so we can check that.

  • If that file is not equal to know, then we actually want to get the file name from it.

  • And we're again using this turn ery operator.

  • So we'll say if their file name is not equal to know, then we want to get the file name from it.

  • So what's that file about file name.

  • But if it is a, well, you know, we'll just return No.

  • Here.

  • And we want a credit variable called file name, which we said equal to that.

  • So, essentially, what is getting the file name from the file?

  • If it exists, and then we can use this file name here.

  • Actually, set our cover image may sow our cover image.

  • Name is just going to be in the name of that file file name.

  • And now, if we uploaded a file, this is going to be equal to the name in that file.

  • But if we did not upload a file.

  • It'll just be equal to know so we can send in air saying they didn't upload a file.

  • Now, with all of that set up, we actually have our entire book object correctly created, and we can work on saving that.

  • So we'll wrap this and try to catch again, because we're going to be using a synchronous code in order to execute this.

  • And the first thing that we want to do is just trying to save the book.

  • We'll create a new book.

  • Variable.

  • We're going to set the sequel to a book not save.

  • If the book does save correctly, we just want to redirect to that book's page, just like we did in the author's file.

  • If I open it up here are author out.

  • What we want to do if we created an author was we wanted to redirect that author to the new Authors Page.

  • But since we don't actually have a new book pages created yet, just like we didn't with the new author, we're going to say that instead of redirecting to the new book dot i D.

  • Which kind of comment that out for now, every direction just to the straight books page, because that's going to be easier for us because we already have that page implemented in the next couple Videos will be implementing these pages and switching this over to redirect to the correct page.

  • If for some reason that there's an error on the page, we want to render the new page and pass it this book variable.

  • But this new pages, you can see does quite a bit of logic inside of it to render.

  • So let's create a function that allows us to encapsulate this logic so we only have to write it in one place.

  • So we removed this from here and we'll come down to the bottom of our pager and we'll create a new function.

  • We're just going to call it render New Page and inside of this function, we're going to do all this coat here.

  • The first thing that we want to do is we actually need to pass in the response variable so we can render or redirect as needed.

  • We need to pass in the book variable because we sometimes we're gonna render a new book, sometimes going to render an existing book, and that's all we need to pass into there.

  • And lastly, we just want to pass in an air message here because sometimes we're going to have an heir, a message from our server.

  • So we'll just say, actually has air.

  • We're gonna default this to false because most of our request before we not have an heir.

  • But if it does, we'll set this to true now, inside of her code here, we can see that we can select the authors as we need to.

  • And if getting those authors fails, we'll redirect back to the book page.

  • But if it doesn't, we'll run to the authors were rendered the book.

  • And if we have an heir, we also want to render an error message in orderto dynamically create this error message.

  • We're going to create a new very book here called Haram's.

  • We're gonna set that praying variable to equal.

  • The primaries were sending to the server and we're just past that and here to send us down to our view and then we want to add dynamically to this primes variable.

  • If we have an error so we can say if has air, then we want to execute some code.

  • In that case, we just want to say Prime Spot Aaron message is going to equal.

  • They're creating book and there we go.

  • That's all that we need to do for our message handling.

  • And now we just need to call this method where it's being used.

  • We also need to make sure that this is an ace ing function because we are using a single weight inside of it.

  • So now it's copy that render New Page appeared our new book route.

  • We're going to pass it the response.

  • We're gonna pass a new book and we don't have to worry about passing anything for has error because we're never going to have an error on this page.

  • Then we could do the same exact thing down here instead of our catch.

  • We just want to render that new page again.

  • So we're gonna pass of the response.

  • We're gonna pass it our existing book object, and this does have an heir.

  • So we want to just pass true here for has air object.

  • Now we can set up our server again by brain and PM Run Dev start and we can actually test to see if this code is working for us, as we expected to.

  • As you can see, we already have an up loads book covers folder that was created by our multiple library, which is great for us.

  • And I wouldn't have to worry about automatically creating this ourselves.

  • And we can work on testing this new page.

  • Let's refresh it to make sure everything works.

  • We're just passing a title here of title.

  • We use an author of Kyle.

  • Published Date is just going to be here.

  • Page count will be 100.

  • We'll put a cover of just some default cover and we'll finally put a description here of description and will create this and you'll notice that it created it.

  • Added.

  • It redirected us to this all books page.

  • You see here that we have a book cover that was dynamically created with a unique name, so we never have to worry about our names being overlapping.

  • And it added that book to our book database, which is why we got redirected here to this book page instead of being shown an heir.

  • Butts, for example, say that we forgot to put the title we should get redirected back here with an air.

  • So if we quit, create and you say it says air creating book, you may also know that when we created this with an air and actually added that book cover to our book covers over here, which we don't want.

  • We don't want to save a book cover for a book that's not actually in our database.

  • So if we do have an air saving the book, we want to make sure that we remove the book cover that was saved If there was one that was saved.

  • In order to do this, we need to install a new library.

  • This library is going to be called F s, which stands for file system.

  • This is again built into note so we can just say require f s.

  • And now we have access to that file system library, and we can use that to delete the book covers that we don't actually need anymore.

  • So if we have an air before we render the new page we wanted just call another function that will create and we'll call this remove book cover so removed but cover and we're going to pass it the name of that cover image.

  • So in our case, this is going to be look, not cover image name, and we only want to call this if we actually have a cover image name.

  • So in our case, we're going to say if book dot cover him, his name is not equal to know.

  • Then we're going to call this code for removing the book cover because if we don't actually have a name, then there is no book cover for us to remove.

  • Now let's create that function which we called remove book, cover function, removed, book cover, and it's going to take file name.

  • And instead of here, we want, actually, just unlike that file so we could say f s dot on link.

  • This will remove the file that we don't want any more on our server and we want to pass it the path of where that finals at.

  • So we can say path dot Join this path variable is something we imported earlier.

  • We want it to join to the upload path which should give us public upwards book covers and we want to combine that file name on to the end of the upload path So this is going to get rid of any file that has the final name inside of this book covers folder here, and this is going to take here a function which will have an Arab parameter.

  • And if we get an error, all we want to do is log that era.

  • So let's say if Air Consul by Air Air and essentially all this is doing is it's just going to log the air that we get out to our counselor here so that we can see it because we don't want to ruin the user.

  • The experience, by redirecting them, are throwing an error to them because it doesn't actually matter to the user.

  • If this file gets the leader, do not.

  • This is only for our own good and not for the user.

  • So we don't actually worry about sending this error to the user.

  • Now, with that out of the way, let's cry again.

  • Saving this will upload a file here, and we're gonna check to see if our book covers increases and buy one or not.

  • So if we click create, you'll see that we don't actually get a new book cover being added here to this book covers, which is perfect.

  • It gets added and then immediately removed when we failed to save the book.

  • So we don't have to worry about accidentally uploaded and saving files that aren't actually linked to any of the books in our database.

  • Now that we have the crate and new pages already done as well as file uploading handling, let's work on creating our books.

  • Page will weaken.

  • View all of our different books to make this easier on ourselves.

  • We can just copy the index page from our author section, paste it into our books and change this to be just like we want for books.

  • So we want to search our books, not our authors.

  • We want to get the books route, and here we can set the different labels we want to search for.

  • First thing we want to search for is going to be the title of our book is going to be text for the name of title, and we wantto pulled this from our search options dot title object.

  • Also, we want to wrap this in sedative just so that we have these on different lines, so it's easier to use our input form.

  • And there we go.

  • We have about an indifferent line, and we can just copy this down here in order to do are published after So Save published after Field.

  • We want this to be a date with the name of published after, and we want our value to come from that published after variable and if you remember right in our form fields here, we had to do a bunch of fancy logic to convert things to a nice oh String because from our database, this published date came out a little bit differently formatted than we actually want it.

  • But since we're posting and getting the exact same data from our server, we're sending this published after and reading this exact same publish after hitting the database.

  • First, we could just use this published after variable in here, and it'll work just fine.

  • We could get the same it back thing here for published before, so we'll change these variables to published before published before and finally published before books foolish before and never get.

  • That is the basics of our form set up and then down here, we actually want to look over our books instead of our authors will do this inside of a div again.

  • So we'll say Dave here and invent that.

  • So it looks good.

  • Copy that did downs that we have access to it.

  • Close it off and in here will say books not for each book.

  • And instead of just rendering out the books name, we actually want to show the image of the book because that looks a little bit better in my opinion.

  • So cancel this up will make this an image.

  • Give it how you hear of 150 with is going to be equal to 100 and we're going to set the source here and we want to get the path to this image.

  • But right now we don't have an easy way to get this path from the book.

  • We have the name which is cover image name, but we want something like cover image path.

  • There is going to give us a direct path to where that cover image is uploaded.

  • So let's actually work on creating a variable that does exactly that for us.

  • If we go inside of our books model and we can actually create a virtual property.

  • So what we want to do is we want to take that book schema, and we want to say dot virtual and this will allow us to create a virtual property.

  • It'll essentially act the same as any of these variables that we have here on our book, but it will actually derive its value from these variables.

  • We want to call this cover image half and then which wanted to find a dog, get function for it.

  • So we can say when we call book dot cover image path, it's going to call this get function here, and we'll just pass this in a function and it's that dysfunction we're actually order to find how we get that.

  • And the reason we're using a normal function here instead of an air of function is because we need to have access to the this property, which is going to be linked to the actual book itself.

  • So make sure you use a function here and not an arrow function, and the first thing we're gonna do we want to check if this book actually has a cover image applied to it so we can sit, cover image, name is not equal to know.

  • So if there is a cover image, then we actually want to return the path which leads to this book.

  • Public uploads book covers full there section inside of her file structure.

  • To do that, we're going to use that path library that we used earlier.

  • So it's just important that will save constant path is equal to require, huh?

  • And now we have that required an added in We can come down here and we can say that we want to return path of dot join.

  • We want to join our route of our object, which is going to be inside that public folder.

  • And we want to attend here, that cover image based path variable that we created up here.

  • As you can see this up close, both covers.

  • So it's going to be inside our public uploads book covers folder and then, lastly, want to upend the actual file name to the end of this route so we can see that we have our root folder, which is public.

  • We have the path to the book covers folder inside of that public folder, and then finally, the name of the actual file which corresponds with the book cover for this book.

  • So now that we've created that property inside of our index page here for books, we could just access it just like this as if it was any other property on our book.

  • And that's all we need to do to really get started working on this page right here.

  • But we need to actually implement this page on our server.

  • So let's go back to our books server here and let's go all the way up to our all books route and here we actually want to render that page.

  • So what's a rez dot render and we want to render that looks slashed in next page right here, and we need to pass it a few things.

  • First, we need to pass it our books, which is going to be a list of books we're going to create, and then we need to actually pass it the search parameters.

  • So we'll say search programs, and this is just going to be equal to our request dot clear parameters just like that.

  • And now we can actually access this book very bullet actually created.

  • So again we're going to wrap this in a try catch because this is going to be using asynchronous code instead of our catch weaken.

  • Just redirect the user back to the home page in case for some reason we get in air.

  • And if we're successfully execute this, we want to render art books Index page so inside of this tribe.

  • Let's first try to get all the books I was going to for now get every book without actually searching on it.

  • So it will say book dot find passed in everything right here.

  • And if that actually execute successfully, we'll get our books here and our search parameters are going to be returned.

  • So what say that?

  • Refresh our server over here and you notice we immediately get in air.

  • And it's because search options is not to find.

  • This should just be search options instead of search Karim's.

  • And now, if we save that, refresh our page, you'll notice we get another air, and it's saying that book stopped for each is not to find.

  • So in order to debug this, we just booked back where books variables to find and you notice I forgot to include the await key word here which is incredibly important to put this awake.

  • He work because it's how we actually get the result of this executed function.

  • Now, if we say this one last time, refresh our page, you'll see that everything loads up just fine and you'll see that our first book is being rendered, which is exactly what we want.

  • But you'll notice if we filter by something and hit search.

  • It is just stay there because we're not actually doing any filtering on our book dot find.

  • You also notice that are such prominent are staying in here, which is what we want, which is nice.

  • Now, in order to do this query, it's going to be a little bit more complex, since we first need to check if the name is somewhere to this name.

  • Wilson.

  • A check if the date is after this or if the published data is before this.

  • So we need to do a little bit more than just a simple matching query.

  • So to get started was first create our query object will say constant query is going to be equal to book don't find.

  • And if we just passed this book dot find with nothing and don't actually do anything.

  • Don't actually execute any methods.

  • This returns to us a quarry object which we can build a query from and then execute later.

  • And we want to build this query from our request Query parameters.

  • So just like we did in the author's page, we're going to check to see if our request doc query contains the parameters we want.

  • So first we'll check for the title.

  • The title is not equal to know.

  • And if the request queria dot tale is not equal to an empty string, then we know that they actually passed a title to this page, and we can actually check and render this title inside of our query.

  • So we can say that we want our query to be equal to our query.

  • Essentially, this is just a pending onto our query, die rejects, and we use this regular expression in our earlier example with the authors.

  • So this is going to be very similar.

  • We want to check on the title of our book.

  • This is our database model parameter.

  • So this is gonna be the book dot title object of an RV, Davies, and then we want to create a new regular expression.

  • This regular expression is just going to contain our title.

  • So replace dot query dot title and we get past the I flag, which just says that we don't care if they typed in a capital s or lower case s is going to be treated exactly the same.

  • Now we needed again do this query for published after and published before.

  • But let's first just look at this query for a title.

  • So here, instead of awaiting booked out find we just wanna wait query dot execute.

  • And this is just going to execute our query that we defined up here and we appended to down here.

  • Now, if we save that and we actually cook our search, you'll see again we get another error.

  • And this is because I'm using const here and I'm reassigning the variable.

  • So we need to make sure that we used light here instead of constant.

  • Now, if we say but and click search, you'll see that it works and that our book doesn't show up because the title does not match this title.

  • If you remember earlier we titled this book title.

  • So if we search for something like this and click Search.

  • You'll see that the book shows up with the correct title.

  • Let's try adding another book Tore a page for When we call this one book for the title and we're going to put a published eight here.

  • We're going to do this on March 1st 2019 and we want a page count.

  • Doesn't really matter file.

  • We'll just make this bluish file and description again.

  • Doesn't matter now.

  • We have both of these books here, so if we search for a title of a book, will you see that we get this book, me returned research for a title?

  • We get the other book, Green returned.

  • And if we wanted to search for published Before, remember that that one book was published on the first of March, so we would want to do a search such as Second of March.

  • It would click Search.

  • That book should show up, but right now we're not actually filtering because if, for example, we selected something before you'll see that this book is still showing up, and that's because we haven't added our filters over here for published before and published after.

  • So let's do that now, first thing that we need to do is copy this down and paste it here, and we just want to change a few things we want to check first for published before we want to do this again to make sure the published before is not equal to an empty A string.

  • So this means that we have a published before variable, and instead of doing a rejects here, we're going to do a less than so we'll say that our query is going to be equal to query Got less than or equal to.

  • This is the same text here.

  • For that we have lt for Weston and then e for equal to We pass it in the field in our database.

  • We want to check if you want to check the published date in our database, and we want to pass it in the request Cleary stuff published before.

  • So essentially what we're saying is if the published eight is less than or equal to the published before date, then we want to return that object.

in today's video, we're going to be looking at creating the index new and create fuse for the books, as well as flushing out the homepage of our site.

Subtitles and vocabulary

Click the word to look it up Click the word to find further inforamtion about it