Begin with the End In Mind
New and Create Routes
- Create a new route and page
- Add interactivity to your site with forms
- Create a post route
- 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
Connect Express to Mongo with Mongoose
npm i mongoose- Inside server.js:
Here's the latest options to include to get rid of the deprecation warnings:
const mongoose = require('mongoose');
//... and then farther down the file
mongoose.connect(process.env.MONGO_URI, { useNewUrlParser: true, useUnifiedTopology: true });
mongoose.connection.once('open', ()=> {
console.log('connected to mongo');
});Create Fruits Model
mkdir modelstouch models/fruit.js- Create the fruit schema
const mongoose = require('mongoose');
const fruitSchema = new mongoose.Schema({
name: { type: String, required: true },
color: { type: String, required: true },
readyToEat: Boolean
});
const Fruit = mongoose.model('Fruit', fruitSchema);
module.exports = Fruit;Have Create Route Create data in MongoDB
Inside server.js:
const Fruit = require('./models/fruit.js');
//... and then farther down the file
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.send(createdFruit);
});
});Create a new route and page
- Let's create a page that will allow us to create a new fruit
-
First, we'll need a route for displaying the page in our server.js file IMPORTANT: put this above your show route, so that the show route doesn't accidentally pick up a /fruits/new request
//put this above your Show route app.get('/fruits/new', (req, res) => { res.render('fruits/New'); }); -
Now lets's create the html for this page in our /views/New.jsx file
const React = require('react'); class New extends React.Component { render() { return <div>New Page</div>; } } module.exports = New; - Visit http://localhost:3000/fruits/new to see if it works
Add interactivity to your site with forms
We can use forms to allow the user to enter their own data:
const React = require('react');
class New extends React.Component {
render() {
return (
<div>
<h1>New Fruit page</h1>
{/* NOTE: action will be the route, method will be the HTTP verb */}
<form action="/fruits" method="POST">
Name: <input type="text" name="name" /><br/>
Color: <input type="text" name="color" /><br/>
Is Ready To Eat: <input type="checkbox" name="readyToEat" /><br/>
<input type="submit" name="" value="Create Fruit"/>
</form>
</div>);
}
}
module.exports = New;NOTE: the form element has an action and a method attribute. We get these values from our RESTful routes table. We'll need this info for the next step too.
Review and Refactor Index Route
Edit views/fruits/Index.jsx
Have Index Route Render All Fruits
app.get('/fruits', (req, res)=>{
Fruit.find({}, (error, allFruits)=>{
res.render('fruits/Index', {
fruits: allFruits
});
});
});Update the jsx file:
const React = require('react');
class Index extends React.Component {
render() {
return (
<div>
<h1>Fruits index page</h1>
<ul>
{
this.props.fruits.map((fruit, i) => {
return (
<li key={fruit._id}>
The { fruit.name } is { fruit.color }
{ fruit.readyToEat ? `It is ready to eat` : `It is not ready to eat` }
</li>
)
})
}
</ul>
</div> );
}
}
module.exports = Index;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
});Have Index Page Link to Show Route
{
this.props.fruits.map((fruit, i) => {
return (
<li>
The <a href={`/fruits/${ fruit._id }`}> { fruit.name } </a> is { fruit.color }
{ fruit.readyToEat ? `It is ready to eat` : `It is not ready to eat` }
</li>
)
})
}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?