As the title states I am having issues rendering the image file that I'm uploading in my node.js application. I have included multer and the images are correctly uploading to the appropriate folder, however when referencing these images in ejs I get a
GET http://localhost:3000/public/uploads/2021-11-20T15:36:02.319Zlakeside.jpg 404 (Not Found)
When I update the href's in the index.ejs and show.ejs
<div ><img src="<%= article.image %>" alt=""> </div>
I get different pathing errors which lead me to believe it's just an issue with routing?
File structure
Lefiatv2
- controllers
- models
- article.js
- public
- uploads
- routes
- blog.js
- views
- blog
- edit.ejs
- index.ejs
- new.ejs
- show.ejs
server.js
schemas.js
blog.js
const express = require('express')
const multer = require('multer')
const Article = require('./../models/article')
const router = express.Router()
const storage = multer.diskStorage({
// destination for file
destination: function (req, file, callback) {
callback(null, './public/uploads')
},
// add back the extension
filename: function (req, file, callback) {
callback(null, new Date().toISOString() file.originalname)
},
})
const fileFilter = (req, file, cb) => {
// reject a file
if (file.mimetype === 'image/jpeg' || file.mimetype === 'image/png') {
cb(null, true);
} else {
cb(null, false);
}
};
// upload parameters for multer
const upload = multer({
storage: storage,
limits: {
fileSize: 1024*1024*3,
},
fileFilter: fileFilter
})
router.get('/', async (req, res) => {
const articles = await Article.find().sort({ createdAt: 'desc' })
res.render('blog/index', { articles: articles })
})
router.get('/new', (req, res) => {
res.render('blog/new', { article: new Article() })
})
router.get('/edit/:id', async (req, res) => {
const article = await Article.findById(req.params.id)
res.render('blog/edit', { article: article })
})
router.get('/:slug', async (req, res) => {
const article = await Article.findOne({ slug: req.params.slug })
if(article == null) res.redirect('/blog')
res.render('blog/show', { article: article })
})
router.post('/', upload.single('image'), async (req, res, next) => {
console.log(req.file)
req.article = new Article()
next()
}, saveArticleAndRedirect('new'))
router.put('/:id', upload.single('image'), async (req, res, next) => {
req.article = await Article.findOneAndUpdate(req.params.id)
next()
}, saveArticleAndRedirect('edit'))
router.delete('/:id', async (req, res) => {
await Article.findByIdAndDelete(req.params.id)
res.redirect('/blog')
})
function saveArticleAndRedirect(path) {
return async (req, res) => {
let article = req.article
article.title = req.body.title
article.description = req.body.description
article.markdown = req.body.markdown
article.image = req.file.path
try {
article = await article.save()
res.redirect(`/blog/${article.slug}`)
} catch(e) {
res.render(`blog/${path}`, { article: article })
}
}
}
module.exports = router
article.js
const mongoose = require('mongoose')
const marked = require('marked')
const slugify = require('slugify')
const createDomPurify = require('dompurify')
const { JSDOM } = require('jsdom')
const dompurify = createDomPurify(new JSDOM().window)
const articleSchema = new mongoose.Schema({
title: {
required: true,
type: String
},
description: {
type: String
},
markdown: {
type: String,
required: true
},
createdAt: {
type: Date,
default: Date.now
},
slug: {
type: String,
required: true,
unique: true
},
sanitizedHtml: {
type: String,
required: true
},
image: {
type: String,
data: Buffer,
}
});
articleSchema.pre('validate', function(next) {
if (this.title) {
this.slug = slugify(this.title, { lower: true, strict: true })
}
if (this.markdown) {
this.sanitizedHtml = dompurify.sanitize(marked(this.markdown))
}
next()
})
module.exports = mongoose.model('Article', articleSchema)
show.ejs
<div class="container">
<div class=""><img src="<%= article.image %>" alt=""> </div>
<h1 class="mb-2"><%= article.title %> </h1>
<div class="text-muted mb-2">
<%- article.createdAt.toLocaleDateString() %>
</div>
<div class="text-muted mb-2"><%= article.slug %></div>
<a href="/blog" class="btn btn-secondary">All Articles</a>
<a href="/blog/edit/<%= article.id %> " class="btn btn-info">Edit</a>
<div>
<%- article.sanitizedHtml %>
</div>
</div>
index.ejs
<link rel="stylesheet" href="/stylesheets/blog.css">
<div >
<!-- <div >
<div >
<p>Do your dreams follow the clouds?</p>
<a href="/trips" >Follow Our Adventures</a>
</div>
</div> -->
<div >
<div >
<div >
<h3 >Do your dreams follow the clouds?</h3>
<form action="#" >
<div > <input type="email"
id="email"
placeholder="Your Email" name="email"> </div>
<div > <button type="submit" >Follow Our
Adventures</button>
</div>
</form>
</div>
</div>
</div>
<h1 >Latest Articles</h1>
<a href="/blog/new" >New Article</a>
<% articles.forEach(article => { %>
<div >
<div >
<div >
<div >
<h4 > <%= article.title %> </h4>
<div >
<%- article.createdAt.toLocaleDateString() %>
</div>
<div >
<%= article.description %>
</div>
</div>
<div >
<img src="<%= article.image %>" alt="">
</div>
</div>
<div >
<a href="/blog/<%= article.slug %>">Read More</a>
<a href="/blog/edit/<%= article.id %>" >Edit</a>
<form action="/blog/<%= article.id %>?_method=DELETE " method="POST" >
<button type="submit" >Delete</button>
</form>
</div>
</div>
</div>
<% }) %>
</div>
CodePudding user response:
add this to your server.js file
app.use(express.static(path.join(__dirname, 'public')))
app.use('/uploads', express.static(path.join(__dirname, 'uploads')))