Two Model CRUD App - No Relationship - First Model




Lesson Objectives

  1. Init Directory
  2. Start express
  3. Create Home page
  4. Create Authors Index
  5. Create Authors New Page
  6. Set up Author Model
  7. Create Authors POST Route
  8. Show Authors on Index Page
  9. Create Authors Show Page
  10. Create Authors DELETE Route
  11. Create Authors Edit Page
  12. Create Authors PUT Route



Init Directory

  1. mkdir blog
  2. cd blog
  3. touch server.js
  4. npm init -y
  5. npm install express



Start express

Let's start with some boilerplate code inside of server.js:

const express = require('express');
const app = express();

app.listen(3000, () => {
    console.log('listening....');
});



Create Home page

  1. npm install ejs
  2. mkdir views
  3. touch views/index.ejs



Inside of views/index.ejs:

<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8">
    <title>Express Blog</title>
</head>

<body>
    <header>
        <h1>Welcome to the Blog</h1>
        <nav>
            <ul>
                <li>
                    <a href="/authors">Authors</a>
                </li>
                <li>
                    <a href="/articles">Articles</a>
                </li>
            </ul>
        </nav>
    </header>
</body>

</html>



Inside of server.js:

app.get('/', (req, res) => {
    res.render('index.ejs');
});



Create Authors Index

  1. mkdir views/authors
  2. touch views/authors/index.ejs

Inside of views/authors/index.ejs:

<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8">
    <title>Express Blog</title>
</head>

<body>
    <header>
        <h1>Authors</h1>
        <nav>
            <ul>
                <li>
                    <a href="/">Home</a>
                </li>
                <li>
                    <a href="/authors/new">Create a new Author</a>
                </li>
            </ul>
        </nav>
    </header>
</body>

</html>
  1. mkdir controllers
  2. touch controllers/authors.js



Inside of controllers/authors.js:

const express = require('express');
const router = express.Router();

router.get('/', (req, res) => {
    res.render('authors/index.ejs');
});

module.exports = router;


Use the controller in server.js:

const authorsController = require('./controllers/authors.js');
app.use('/authors', authorsController);



Create Authors New Page

First wetouch views/authors/new.ejs.

Then we can add the following markup:

<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8">
    <title>Express Blog</title>
</head>

<body>
    <header>
        <h1>Create an Author</h1>
        <nav>
            <ul>
                <li>
                    <a href="/">Home</a>
                </li>
                <li>
                    <a href="/authors">Authors Index</a>
                </li>
            </ul>
        </nav>
    </header>
    <main>
        <form action="/authors" method="POST">
            <input type="text" name="name" />
            <input type="submit" value="Create Author" />
        </form>
    </main>
</body>

</html>

Add the create route in controllers/authors.js:

router.get('/new', (req, res) => {
    res.render('authors/new.ejs');
});



Connect to MongoDB

  1. npm install mongoose dotenv
  2. touch .env
  3. Connect in server.js



Add ENV Variables

Inside of .env:

DATABASE_URL=mongodb+srv://<username>:<password>@general-assembly.1wjse.mongodb.net/meen-auth-starter?retryWrites=true&w=majority
  • Remember to use your own DATABASE_URL. Copying the one above will not work.



Configure the Database

Don't forget to include this at the top of server.js:

require('dotenv').config();



Then add this below, also in server.js:

// Dependencies 
const mongoose = require('mongoose');

// Database Configuration
mongoose.connect(process.env.DATABASE_URL, {
	useNewUrlParser: true,
	useUnifiedTopology: true,
	useFindAndModify: false,
	useCreateIndex: true,
});

// Database Connection Error / Success
const db = mongoose.connection;
db.on('error', (err) => console.log(err.message + ' is mongod not running?'));
db.on('connected', () => console.log('mongo connected'));
db.on('disconnected', () => console.log('mongo disconnected'));



STOP! Check your work.

Boot up your server with nodemon and make sure you should see:

Listening ... 
mongo connected



Set up Author Model

  1. mkdir models
  2. touch models/authors.js
const mongoose = require('mongoose');
const Schema = mongoose.Schema;

const authorSchema = new Schema({
    name: String
}, {
    timestamps: true
});

const Author = mongoose.model('Author', authorSchema);

module.exports = Author;



Create Authors Create Route

Use body parser inside of server.js:

app.use(express.urlencoded({ extended: false }));



Inside of controllers/authors.js, let's require the Author model and define a create controller:

const Author = require('../models/authors.js');
//...
//...farther down the page
router.post('/', (req, res) => {
    Author.create(req.body, (err, createdAuthor) => {
        res.redirect('/authors');
    });
});



Show Authors on Index Page

Inside of controllers/authors.js, we'll refactor the index controller:

router.get('/', (req, res) => {
    Author.find({}, (err, foundAuthors) => {
        res.render('authors/index.ejs', {
            authors: foundAuthors
        });
    })
});



Now we can index the authors inside ofviews/authors/index.ejs:

<main>
    <h2>List of Authors</h2>
    <ul>
        <% for(let i = 0; i < authors.length; i++){ %>
        <li>
            <a href="/authors/<%= authors[i]._id %>"><%= authors[i].name %></a>
        </li>
        <% } %>
    </ul>
</main>



Create Authors Show Page

Create the file withtouch views/authors/show.ejs, and add this markup to it:

<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8">
    <title>Express Blog</title>
</head>

<body>
    <header>
        <h1>Show Page for <%= author.name %></h1>
        <nav>
            <ul>
                <li>
                    <a href="/">Home</a>
                </li>
                <li>
                    <a href="/authors">Author Index</a>
                </li>
            </ul>
        </nav>
    </header>
    <main>
        <section>
            <h2>Author Attributes:</h2>
            <ul>
                <li>Name: <%= author.name %></li>
            </ul>
        </section>
    </main>
</body>

</html>



Toward the bottom controllers/authors.js, we'll add a show controller:

//avoid this handling /new by placing it towards the bottom of the file
router.get('/:id', (req, res) => {
    Author.findById(req.params.id, (err, foundAuthor) => {
        res.render('authors/show.ejs', {
            author: foundAuthor
        });
    });
});



Create Authors DELETE Route

  1. npm install method-override
  2. Use method-override in server.js:
const methodOverride = require('method-override');

app.use(methodOverride('_method'));



Inside of controllers/authors.js, we'll define our delete controller:

router.delete('/:id', (req, res) => {
    Author.findByIdAndRemove(req.params.id, () => {
        res.redirect('/authors');
    });
});



Let's make sure to use the _method URL param to make the delete button work in views/authors/show.ejs:

<section>
    <form action="/authors/<%= author._id %>?_method=DELETE" method="POST">
        <input type="submit" value="Delete Author" />
    </form>
</section>



Create Authors Edit Page

Create a link inside ofviews/authors/show.ejs:

<section>
    <a href="/authors/<%= author._id %>/edit">Edit</a>
</section>



Let's define the edit controller inside of controllers/authors.js like this:

router.get('/:id/edit', (req, res) => {
    Author.findById(req.params.id, (err, foundAuthor) => {
        res.render('authors/edit.ejs', {
            author: foundAuthor
        });
    });
});



Next, we'll create an edit page with touch views/authors/edit.ejs, and add this markup to it:

<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8">
    <title>Express Blog</title>
</head>

<body>
    <header>
        <h1>Edit <%= author.name %>'s Info</h1>
        <nav>
            <ul>
                <li>
                    <a href="/">Home</a>
                </li>
                <li>
                    <a href="/authors">Authors Index</a>
                </li>
            </ul>
        </nav>
    </header>
    <main>
        <h2>Author Attributes:</h2>
        <form action="/authors/<%= author._id %>?_method=PUT" method="POST">
            <input type="text" name="name" value="<%= author.name %>" /><br />
            <input type="submit" value="Update Author" />
        </form>
    </main>
</body>

</html>



Create Authors PUT Route

Now we just need to define our update controller inside of controllers/authors.js:

router.put('/:id', (req, res) => {
    Author.findByIdAndUpdate(req.params.id, req.body, () => {
        res.redirect('/authors');
    });
});