Begin with the End In Mind
New, Create, Delete, Update, Edit Routes
- Create a New, Create, Delete, Update, Edit routes and appropriate views
- Add interactivity to your site with forms
- Create a put & delete requests
- Define middleware
- View body of a post request
- Redirect the user to another page
Explanation
Remember where we are going
Where Does It Fit in With MVC
| URL | HTTP Verb | Action | Used For | Mongoose Method | View |
|---|---|---|---|---|---|
| /fruits/ | GET | index | Displaying a list of all fruits | Fruit.find | Index.jsx |
| /fruits/new | GET | new | Display HTML form for creating a new fruit | none | New.jsx |
| /fruits/:id | DELETE | destroy | Delete a specific photo | Fruit.findByIdAndRemove or Fruit.findByIdAndDelete | none |
| /fruits/:id | PATCH/PUT | update | Update a specific fruit | Fruit.findByIdAndUpdate or Fruit.findOneAndUpdate | none |
| /fruits | POST | create | Create a new fruit | Fruit.create | none |
| /fruits/:id/edit | GET | edit | Return an HTML form for editing a fruit | Fruit.findOne or Fruit.findById | Edit.jsx |
| /fruits/:id | GET | show | Display a specific fruit | Fruit.findOne or Fruit.findById | Show.jsx |
Note: Only GET Requests render a View In RESTful Routing
Understanding Structure
| Connections | Schema | Models | Document | Collection | Database | Cluster |
|---|---|---|---|---|---|---|
| In server.js, or connection file Connect to DB using Connection URL | In model file identify the structure of your data | Use the schema to create a new Model that can connect to DB with JavaScript methods like .find, create and .findOneAndUpdate |
An instance of the Model that passes the schema, residing in a collection | The group of documents that were added to the database by a specific Model | A collection of all your collections, every app should have it's own Database | All your databases in your Atlas Account live in your cluster, you only need one cluster and all your databases go in the cluster |
For people that know SQL
- Collection ====> Table
- Document ====> Row
- Key on Schema =====> Column
Pick Up Where we left off in Index.jsx
Add a link to the new page:
<nav>
<a href="/fruits/new">Create a New Fruit</a>
</nav>Have Create Route redirect to Index After Fruit Creation
Inside the create route
Fruit.create(req.body, (error, createdFruit)=>{
res.redirect('/fruits');//sends to /fruits get route
});Update Show.jsx
Edit the views/fruits/Show.jsx file- Change JSX
const React = require('react');
class Show extends React.Component {
render(){
const { name, color, readyToEat } = this.props.fruit
return (
<div>
<h1>{ name } show page</h1>
The { name } is { color }
{ readyToEat ? `It is ready to eat` : `It is not ready to eat` }
</div>
)
}
}
module.exports = Show;Render the jsx
app.get('/fruits/:id', (req, res)=>{
Fruit.findById(req.params.id, (err, foundFruit) => {
res.render('fruits/Show', {
fruit:foundFruit
});
});
});Test that you can do the following
- Go to
http://localhost:3000/fruits/new - Create a new
fruit - See the fruit at
http://localhost:3000/fruits - Show page for fruit works
- You can see fruit in your MongoDB Atlas DB fruits database
Review Questions
❓ In your own words, describe the use case for Mongoose (what is it's purpose and when might you choose to use it?).
❓ A Mongoose _ is used to make a Mongoose Model.
❓ We use a Mongoose _ to perform CRUD operations on a MongoDB..
require('dotenv').config()
const express = require('express')
const mongoose = require('mongoose')
const fruits = require('./models/fruits')
const app = express()
app.use(express.urlencoded({ extended: true}))
app.set('view engine', 'jsx');
app.engine('jsx', require('jsx-view-engine').createEngine());
mongoose.connect(process.env.MONGO_URI, { useNewUrlParser: true, useUnifiedTopology: true });
mongoose.connection.once('open', ()=> {
console.log('connected to mongo');
});
// Index
app.get('/fruits', (req, res)=>{
Fruit.find({}, (error, allFruits)=>{
res.render('fruits/Index', {
fruits: allFruits
});
});
});
// New
app.get('/fruits/new', (req, res) => {
res.render('fruits/New');
});
// Delete
// Update
// Create
app.post('/fruits', (req, res)=>{
if(req.body.readyToEat === 'on'){ //if checked, req.body.readyToEat is set to 'on'
req.body.readyToEat = true;
} else { //if not checked, req.body.readyToEat is undefined
req.body.readyToEat = false;
}
Fruit.create(req.body, (error, createdFruit)=>{
res.redirect('/fruits');//sends to /fruits get route which renders index page
})
})
// Edit
// Show
app.get('/fruits/:id', (req, res)=>{
Fruit.findById(req.params.id, (err, foundFruit)=>{
res.render('fruits/Show', {
fruit:foundFruit
});
});
});
app.listen(PORT, () => {
console.log(`${PORT} is lit`)
})❓ Essential Review Questions
- What is the difference between New and Create?
- What is Middleware?
Deleting & Updating Data
Big Gotcha
- We already used a form to create a fruit but now we want to be able to update or delete the data we added
- First instinct is to use another form which is correct, but we should also consider the fact that PUT & DELETE requests cannot be sent through HTML Forms by default
- HTML Forms can only send GET & POST Requests without the aide of JavaScript
We can use middleware to help us
- We will use a middleware package called
method-override - Middleware is just a fancy way to say that you want to take some code and run it in the middle of when the user sends a request and when the express passes the request to the relevant route handler
- User sends request
- Middleware function runs
- Then express passes it the relevant routeHandler that was created with
app.get, or app.post etc - Method Override will run a function that checks to see if you received a post request that actually supposed to be an PUT or DELETE etc.
npm i method-overrideNow, in our server.js file, add:
//include the method-override package place this where you instructor places it
const methodOverride = require('method-override');
//...
//after app has been defined
//use methodOverride. We'll be adding a query parameter to our delete form named _method
app.use(methodOverride('_method'));Add Routes Delete, Edit & Update Finishing Induces
Delete
app.delete('/fruits/:id', (req, res)=>{
Fruit.findByIdAndRemove(req.params.id, (err, data)=>{
res.redirect('/fruits');//redirect back to fruits index
});
});Edit
app.get('/fruits/:id/edit', (req, res)=>{
Fruit.findById(req.params.id, (err, foundFruit)=>{ //find the fruit
if(!err){
res.render(
'fruits/Edit',
{
fruit: foundFruit //pass in the found fruit so we can prefill the form
}
);
} else {
res.send({ msg: err.message })
}
});
});Update
app.put('/fruits/:id', (req, res)=>{
if(req.body.readyToEat === 'on'){
req.body.readyToEat = true;
} else {
req.body.readyToEat = false;
}
Fruit.findByIdAndUpdate(req.params.id, req.body, (err, updatedFruit)=>{
console.log(updatedFruit)
res.redirect(`/fruits/${req.params.id}`);
});
});Edit View
Now the lets make the JSX file by using the command line to touch a Edit.jsx file in our views folder, then opening it in VS Code:
const React = require('react');
class Edit extends React.Component{
render() {
const { name, _id, readyToEat color } = this.props.fruit
return (
<>
<h1>{name} Edit Page</h1>
<form action={`/fruits/${_id}?_method=PUT`} method="POST">
Name: <input type="text" name="name" defaultValue={name}/><br/>
Color: <input type="text" name="color" defaultValue={color}/><br/>
Is Ready To Eat:
{ readyToEat? <input type="checkbox" name="readyToEat" defaultChecked />: <input type="checkbox" name="readyToEat"/> }
<br/>
<input type="submit" value="Submit Changes"/>
</form>
</>
)
}
}
module.exports= Edit;Add Delete Button to Index and Show Page By adding the following code
<form action={`/fruits/${fruit._id}?_method=DELETE`} method="POST">
<input type="submit" value="DELETE"/>
</form>In Index.js
{
fruits.map((fruit,i) => {
return (<li key={fruit._id}>
<a href={`/fruits/${fruit._id}`}>
{name}</a> is {color}
<br/>
{
readyToEat?
'It\'s ready to eat':
'It\'s not ready to eat'
}
{/* Your Delete Form Goes Here It's incomplete we will fix below*/}
<form action={`/fruits/${fruit._id}?_method=DELETE`} method="POST">
<input type="submit" value="DELETE"/>
</form>
</li>
)
})
}