Type something to search...
Creating a Dynamic Blog with Node.js, Express, and EJS: A Comprehensive Guide - Part 2

Creating a Dynamic Blog with Node.js, Express, and EJS: A Comprehensive Guide - Part 2

Creating a Dynamic Blog with Node.js, Express, and EJS: A Comprehensive Guide (Part 2)

Introduction

Welcome back to our two-part series on building a dynamic blog using Node.js, Express, and EJS. In Part 1, we covered setting up the project, creating a basic Express server, implementing EJS templates, creating routes for the blog, and implementing basic blog functionality. In this part, we’ll enhance the blog further by adding image uploads, styling the blog, implementing user authentication and comments, addressing security considerations, testing, and deploying the application.

Table of Contents for Part 2

  1. Adding Image Uploads
  2. Styling the Blog
  3. Adding Extra Features
  4. Security Considerations
  5. Testing
  6. Deployment
  7. Conclusion and Next Steps

Adding Image Uploads

Enhance the blog to include image uploads using multer:

npm install multer

Updating app.js to Include multer

// Update app.js to include multer
const multer = require('multer');
const upload = multer({ dest: 'public/uploads/' });

// Update create and edit post routes to handle file upload
router.post('/create', upload.single('image'), async (req, res) => {
  try {
    const { title, content, tags } = req.body;
    const image = req.file ? `/uploads/${req.file.filename}` : null;

    const result = await global.db.collection('posts').insertOne({
      title,
      content,
      tags: tags.split(',').map(tag => tag.trim()),
      image,
      createdAt: new Date()
    });
    res.redirect(`/post/${result.insertedId}`);
  } catch (error) {
    console.error(error);
    res.status(500).send('Error creating post');
  }
});

// Handle file upload in the edit post route similarly
router.post('/edit/:id', upload.single('image'), async (req, res) => {
  try {
    const { title, content, tags } = req.body;
    const image = req.file ? `/uploads/${req.file.filename}` : null;

    const updateData = { title, content, tags: tags.split(',').map(tag => tag.trim()) };
    if (image) updateData.image = image;

    await global.db.collection('posts').updateOne(
      { _id: new ObjectId(req.params.id) },
      { $set: updateData }
    );
    res.redirect(`/post/${req.params.id}`);
  } catch (error) {
    console.error(error);
    res.status(500).send('Error updating post');
  }
});

Styling the Blog

Adding CSS Styles

Add a public/css/style.css file to style the blog:

/* public/css/style.css */
body {
    font-family: Arial, sans-serif;
}

.card {
    margin-top: 20px;
}

.btn-primary {
    background-color: #007bff;
    border-color: #007bff;
}

.header, .footer {
    background-color: #f8f9fa;
    padding: 20px;
}

.container {
    margin-top: 40px;
}

Adding Extra Features

User Authentication

Integrate user authentication using passport and passport-local:

npm install passport passport-local express-session bcrypt

Implementing User Authentication

In app.js and routes/user.js:

// app.js

const passport = require('passport');
const LocalStrategy = require('passport-local').Strategy;
const session = require('express-session');
const bcrypt = require('bcrypt');

// Configure session
app.use(session({
  secret: 'mySecret',
  resave: false,
  saveUninitialized: false
}));

// Configure passport
passport.use(new LocalStrategy(async (username, password, done) => {
  try {
    const user = await global.db.collection('users').findOne({ username });
    if (!user || !await bcrypt.compare(password, user.password)) {
      return done(null, false, { message: 'Invalid username or password' });
    }
    return done(null, user);
  } catch (error) {
    return done(error);
  }
}));

passport.serializeUser((user, done) => {
  done(null, user._id);
});

passport.deserializeUser(async (id, done) => {
  try {
    const user = await global.db.collection('users').findOne({ _id: new ObjectId(id) });
    done(null, user);
  } catch (error) {
    done(error);
  }
});

app.use(passport.initialize());
app.use(passport.session());

const userRoutes = require('./routes/user');
app.use('/', userRoutes);

// routes/user.js

const express = require('express');
const passport = require('passport');
const router = express.Router();
const bcrypt = require('bcrypt');
const saltRounds = 10;

router.get('/login', (req, res) => {
  res.render('login', { title: 'Login' });
});

router.post('/login', passport.authenticate('local', {
  successRedirect: '/',
  failureRedirect: '/login'
}));

router.get('/register', (req, res) => {
  res.render('register', { title: 'Register' });
});

router.post('/register', async (req, res) => {
  try {
    const { username, password } = req.body;
    const hashedPassword = await bcrypt.hash(password, saltRounds);
    await global.db.collection('users').insertOne({ username, password: hashedPassword });
    res.redirect('/login');
  } catch (error) {
    console.error(error);
    res.status(500).send('Error registering user');
  }
});

router.get('/logout', (req, res) => {
  req.logout();
  res.redirect('/');
});

module.exports = router;

Comments

Add comments to blog posts:

// Update routes/blog.js

// Add comment to post
router.post('/post/:id/comment', async (req, res) => {
  try {
    const { comment } = req.body;
    await global.db.collection('posts').updateOne(
      { _id: new ObjectId(req.params.id) },
      { $push: { comments: { text: comment, createdAt: new Date() } } }
    );
    res.redirect(`/post/${req.params.id}`);
  } catch (error) {
    console.error(error);
    res.status(500).send('Error adding comment');
  }
});

// Display comments in post view (post.ejs)
<% if (post.comments && post.comments.length > 0) { %>
  <div class="comments">
    <% post.comments.forEach(function(comment) { %>
      <div class="comment">
        <p><%= comment.text %></p>
        <small><%= comment.createdAt.toDateString() %></small>
      </div>
    <% }); %>
  </div>
<% } %>

<form action="/post/<%= post._id %>/comment" method="POST">
  <div class="form-group">
    <textarea name="comment" class="form-control" required></textarea>
  </div>
  <button type="submit" class="btn btn-primary">Add Comment</button>
</form>

Security Considerations

Ensure passwords are stored securely:

Secure Passwords

// Update user registration to hash passwords
const bcrypt = require('bcrypt');
const saltRounds = 10;

router.post('/register', async (req, res) => {
  try {
    const { username, password } = req.body;
    const hashedPassword = await bcrypt.hash(password, saltRounds);
    await global.db.collection('users').insertOne({ username, password: hashedPassword });
    res.redirect('/login');
  } catch (error) {
    console.error(error);
    res.status(500).send('Error registering user');
  }
});

// Update passport strategy to compare hashed passwords
passport.use(new LocalStrategy(async (username, password, done) => {
  try {
    const user = await global.db.collection('users').findOne({ username });
    if (!user || !await bcrypt.compare(password, user.password)) {
      return done(null, false, { message: 'Invalid username or password' });
    }
    return done(null, user);
  } catch (error) {
    return done(error);
  }
}));

Testing

Integrate testing frameworks like Mocha and Chai:

npm install mocha chai supertest

Implementing Tests

Create a test folder with blog.test.js:



// test/blog.test.js

const request = require('supertest');
const app = require('../app');  // assuming app.js exports the express app

describe('GET /', function() {
  it('responds with 200', function(done) {
    request(app)
      .get('/')
      .expect(200, done);
  });
});

describe('GET /post/:id', function() {
  it('responds with 200', function(done) {
    request(app)
      .get('/post/60c72b2f9b1d8b3d4c8d889e')  // Use a valid post ID from your database
      .expect(200, done);
  });
});

Deployment

Deploying to Heroku

Ensure you have a Procfile and app.json:

// Procfile
web: node app.js
// app.json
{
  "name": "nodejs-express-blog",
  "description": "A dynamic blog built with Node.js, Express, and EJS",
  "scripts": {
    "start": "node app.js"
  }
}

Pushing to Heroku

heroku create
git push heroku main
heroku config:set MONGODB_URI=<your_mongodb_uri>
heroku open

Conclusion and Next Steps

In this two-part guide, we’ve covered the essentials of building a dynamic blog using Node.js, Express, and EJS. From setting up the project and creating routes to implementing user authentication, adding comments, and deploying the application, you now have a solid foundation to build upon.

For further improvements, consider adding features like social media integration, SEO enhancements, and performance optimizations. Happy coding!

Related Posts

Mastering Asynchronous Data Streams: A Beginner's Guide to Accumulating Data Chunks

Mastering Asynchronous Data Streams: A Beginner's Guide to Accumulating Data Chunks

Mastering Asynchronous Data Streams: A Beginner's Guide to Accumulating Data Chunks Introduction Navigating the world of asynchronous programming can often feel daunting, especially when dealing with…

Read more...
A Beginner's Guide to Web Development: How to Integrate Bootstrap with Visual Studio Code - Part 1

A Beginner's Guide to Web Development: How to Integrate Bootstrap with Visual Studio Code - Part 1

A Beginner's Guide to Integrate Bootstrap with Visual Studio Code Bootstrap is a popular open-source CSS framework used for developing responsive and mobile-first websites. This guide will walk you…

Read more...
A Beginner's Guide to Web Development: Understanding Bootstrap and Responsive Design - Part 2

A Beginner's Guide to Web Development: Understanding Bootstrap and Responsive Design - Part 2

A Beginner's Guide to Web Development: Understanding Bootstrap and Responsive Design Web development can be a challenging field for beginners. One common issue that beginners often encounter involves…

Read more...
A Beginner's Guide to Web Development: CSS and Bootstrap - Part 3

A Beginner's Guide to Web Development: CSS and Bootstrap - Part 3

A Beginner's Guide to Web Development: CSS and Bootstrap Welcome to the world of web development! This guide is designed to help beginners understand the basics of CSS and Bootstrap, complete with…

Read more...
A Beginner's Guide to Web Development: Advanced Layouts with Bootstrap 5 - Part 4

A Beginner's Guide to Web Development: Advanced Layouts with Bootstrap 5 - Part 4

Getting Started with Bootstrap 5: A Beginner's Guide Welcome to the exciting world of web development! This beginner-friendly guide will introduce you to Bootstrap 5, the latest version of the world's…

Read more...
Building Your First Web App: A Beginner's Guide to Creating a To-Do List with Node.js and Express

Building Your First Web App: A Beginner's Guide to Creating a To-Do List with Node.js and Express

Building Your First Web App: A Beginner's Guide to Creating a To-Do List with Node.js and Express Introduction Embarking on your web development journey can be both exciting and overwhelming. With…

Read more...
Creating a Dynamic Blog with Node.js, Express, and EJS: A Comprehensive Guide - Part 1

Creating a Dynamic Blog with Node.js, Express, and EJS: A Comprehensive Guide - Part 1

Creating a Dynamic Blog with Node.js, Express, and EJS: A Comprehensive Guide (Part 1) Introduction In the ever-evolving landscape of web development, it's crucial to choose tools that are versatile,…

Read more...
Event Prevention in Web Development: A Comprehensive Guide

Event Prevention in Web Development: A Comprehensive Guide

Event Prevention in Web Development: A Comprehensive Guide Introduction Event prevention is a crucial concept in web development that allows developers to control and customize user interactions. This…

Read more...
Exploring OCaml: A Functional Approach to Web Development

Exploring OCaml: A Functional Approach to Web Development

Exploring OCaml: A Functional Approach to Web Development Introduction: Unveiling the Power of Functional Programming in Web Development In the ever-evolving landscape of web development, where…

Read more...
Integrating Google reCAPTCHA for Enhanced Website Security

Integrating Google reCAPTCHA for Enhanced Website Security

Integrating Google reCAPTCHA for Enhanced Website Security Introduction In an era where cyber threats are increasingly sophisticated, protecting your website from automated attacks is crucial.…

Read more...
Secure Authentication: Integrating Lucia with Astro for Robust User Management

Secure Authentication: Integrating Lucia with Astro for Robust User Management

Integrating Lucia Authentication with Astro To integrate the Lucia authentication system for login functionality in your Astro project, follow these steps. This guide will help you structure your…

Read more...
Mastering HTML: Tips & Tricks for Stylish Web Pages

Mastering HTML: Tips & Tricks for Stylish Web Pages

Mastering HTML: Tips & Tricks for Stylish Web Pages Introduction HTML is the backbone of web development, providing the structure that powers nearly every website you visit. Whether you're creating…

Read more...
JavaScript Fundamentals: The Foundation for React Development

JavaScript Fundamentals: The Foundation for React Development

JavaScript Fundamentals: The Foundation for React Development Introduction: Why Learn JavaScript Before React? As you embark on your journey to learning web development, it's crucial to understand the…

Read more...
Introduction to React: Building on Your JavaScript Knowledge

Introduction to React: Building on Your JavaScript Knowledge

Introduction to React: Building on Your JavaScript Knowledge Transitioning to React React is a powerful library developed by Facebook, primarily used for building user interfaces. It builds on…

Read more...
Advanced React Development and Best Practices

Advanced React Development and Best Practices

Advanced React Development and Best Practices Advanced React Topics Refs and the useRef Hook Refs allow you to interact with the DOM directly from functional components: Example: import React, {…

Read more...
Mastering JavaScript Fundamentals: A Comprehensive Guide – Part 1

Mastering JavaScript Fundamentals: A Comprehensive Guide – Part 1

Introduction JavaScript is a versatile programming language that plays a crucial role in web development. Whether you're building dynamic websites or developing modern web applications, understanding…

Read more...
Mastering JavaScript Fundamentals: A Comprehensive Guide - Part 2

Mastering JavaScript Fundamentals: A Comprehensive Guide - Part 2

Introduction In this guide, we will cover essential concepts in JavaScript, including operators, array manipulation, random number generation, and error handling. Understanding these concepts is…

Read more...
Mastering JavaScript Fundamentals: A Comprehensive Guide - Part 3

Mastering JavaScript Fundamentals: A Comprehensive Guide - Part 3

Mastering JavaScript: A Journey Through Code Debugging Introduction JavaScript is a powerful and essential language for web development. While it enables developers to create dynamic and interactive…

Read more...
Mastering JavaScript Fundamentals: A Comprehensive Guide - Part 4

Mastering JavaScript Fundamentals: A Comprehensive Guide - Part 4

Mastering JavaScript as a Beginner: A Fun and Interactive Journey Introduction JavaScript is a programming language that brings web pages to life, making them interactive and dynamic. As a beginner,…

Read more...
Mastering useCallback in React: Optimizing Function Management

Mastering useCallback in React: Optimizing Function Management

Mastering useCallback in React: A Beginner's Guide to Optimizing Function Management Introduction In the dynamic world of React development, performance optimization is key to creating smooth,…

Read more...
From Words to Web: Kickstart Your MERN + ANAi Stack Journey for Translators and Writers – Prerequisites

From Words to Web: Kickstart Your MERN + ANAi Stack Journey for Translators and Writers – Prerequisites

MERN + ANAi Stack Mastery: Prerequisites for AI-Enhanced Web Development Introduction Welcome to the MERN + ANAi Stack Mastery course, an intensive 10-weekends journey designed to elevate your web…

Read more...
MERN + ANAi Stack Mastery: Your Journey to AI-Driven Web Development – Overview

MERN + ANAi Stack Mastery: Your Journey to AI-Driven Web Development – Overview

Transitioning to AI-Driven Web Development: MERN Stack Journey Enhanced by ANAi Module Overview This 10-weekends comprehensive course equips you with the skills to build AI-enhanced web applications…

Read more...
Navigating JavaScript Updates for Beginners: A Comprehensive Guide

Navigating JavaScript Updates for Beginners: A Comprehensive Guide

Title: Navigating JavaScript Updates for Beginners: A Comprehensive Guide Introduction As a beginner in the world of programming, it's essential to stay updated with the latest developments and…

Read more...
The Necessity of Keeping Documentation Soup Repository Locally and Updated

The Necessity of Keeping Documentation Soup Repository Locally and Updated

Title: The Necessity of Keeping Documentation Soup Repository Locally and Updated Introduction In today's fast-paced technological landscape, developers rely on a vast array of libraries and…

Read more...
Node.js for Newbies: Mastering the Fundamentals

Node.js for Newbies: Mastering the Fundamentals

Node.js for Newbies: Mastering the Fundamentals Introduction Node.js is an influential runtime environment that leverages Chrome's V8 JavaScript engine. It empowers developers to craft server-side…

Read more...
OOP Concepts: Interview Questions and Answers for Junior Web Developers

OOP Concepts: Interview Questions and Answers for Junior Web Developers

OOP Concepts Answer Sheet for Junior Web Developers OOP Concepts: Interview Questions and Answers for Junior Web Developers 1. Encapsulation Q: What is encapsulation, and why is it important? A:…

Read more...
Securing Next.js API Endpoints: A Comprehensive Guide to Email Handling and Security Best Practices

Securing Next.js API Endpoints: A Comprehensive Guide to Email Handling and Security Best Practices

Securing Next.js API Endpoints: A Comprehensive Guide to Email Handling and Security Best Practices Introduction In the fast-paced world of web development, rapid code deployment is often necessary.…

Read more...
Slam Dunk Your Productivity: How Playing Basketball Can Boost Efficiency for Web Developers

Slam Dunk Your Productivity: How Playing Basketball Can Boost Efficiency for Web Developers

Slam Dunk Your Productivity: How Playing Basketball Can Boost Efficiency for Web Developers Introduction Playing basketball might seem like an unlikely activity for web developers, but this fast-paced…

Read more...
Testing GitHub OAuth Authentication Locally in Astro Build with Lucia and ngrok

Testing GitHub OAuth Authentication Locally in Astro Build with Lucia and ngrok

Setting Up Lucia for Astro Build: Testing GitHub Authentication Locally Using ngrok Introduction In this article, we will walk through the steps to set up a secure authentication system with Lucia and…

Read more...
A Comprehensive Guide to Troubleshooting Your Simple BMI Calculator

A Comprehensive Guide to Troubleshooting Your Simple BMI Calculator

A Comprehensive Guide to Troubleshooting Your Simple BMI Calculator Introduction Building a web application can be a complex endeavor, and ensuring smooth functionality is crucial. In this guide,…

Read more...
Understanding OOP Concepts: A Guide for Junior Web Developers

Understanding OOP Concepts: A Guide for Junior Web Developers

Understanding OOP Concepts: A Guide for Junior Web Developers As a junior web developer, one of the most crucial skills you need to develop is a strong understanding of Object-Oriented Programming…

Read more...
Understanding Server-Side Rendering (SSR) and Its SEO Benefits

Understanding Server-Side Rendering (SSR) and Its SEO Benefits

Understanding SSR and Its SEO Benefits Server-Side Rendering (SSR) involves rendering web pages on the server instead of the client's browser. This means that when a user (or a search engine bot)…

Read more...
Automatically Converting Weather Codes into Descriptive Text with JavaScript

Automatically Converting Weather Codes into Descriptive Text with JavaScript

Automatically Converting Weather Codes into Descriptive Text with JavaScript Introduction Weather APIs often return forecasts and conditions using numeric codes, which can be challenging for users…

Read more...
Web Development Mastery: A Comprehensive Guide for Beginners

Web Development Mastery: A Comprehensive Guide for Beginners

Web Development Mastery: A Comprehensive Guide for Beginners Unlocking the World of Web Creation Welcome to the exciting realm of web development! Whether you're a coding novice or an experienced…

Read more...
Web Development for Beginners: A Comprehensive Guide Using Rust

Web Development for Beginners: A Comprehensive Guide Using Rust

Web Development for Beginners: A Comprehensive Guide Using Rust Introduction Web development is an exciting field filled with opportunities to create dynamic and engaging user experiences. Rust, a…

Read more...
Implementing Authentication with the Lucia Library: Backend vs. Frontend Approaches

Implementing Authentication with the Lucia Library: Backend vs. Frontend Approaches

Implementing Authentication with the Lucia Library: Backend vs. Frontend Approaches Authentication is a crucial aspect of modern web applications, ensuring that users are who they claim to be and…

Read more...
Mastering MySQL Integration in Modern Application Development

Mastering MySQL Integration in Modern Application Development

Mastering MySQL Integration in Modern Application Development Connecting to MySQL from Different Programming Languages Introduction In today's fast-paced world of application development, seamlessly…

Read more...
SQL Basics for MySQL: A Beginner's Guide

SQL Basics for MySQL: A Beginner's Guide

SQL Basics for MySQL: A Beginner's Guide Introduction to SQL and MySQL SQL, which stands for Structured Query Language, is a domain-specific language used in managing and manipulating databases. It is…

Read more...