remove({}) 대신 deleteMany({})를 사용한다. 

 

Campground.remove({}, err => {
// 위의 코드를 아래와 같이 수정한다.
Campground.deleteMany({}, err => {

 

(node:1129) UnhandledPromiseRejectionWarning: MongooseServerSelectionError: connect ECONNREFUSED 127.0.0.1:27017
    at NativeConnection.Connection.openUri (/workspace/webdevbootcamp/YelpCamp/v3/node_modules/mongoose/lib/connection.js:800:32)
    at cb (/workspace/webdevbootcamp/YelpCamp/v3/node_modules/mongoose/lib/index.js:341:10)
    at Promise (/workspace/webdevbootcamp/YelpCamp/v3/node_modules/mongoose/lib/helpers/promiseOrCallback.js:31:5)
    at new Promise (<anonymous>)
    at promiseOrCallback (/workspace/webdevbootcamp/YelpCamp/v3/node_modules/mongoose/lib/helpers/promiseOrCallback.js:30:10)
    at Mongoose.connect (/workspace/webdevbootcamp/YelpCamp/v3/node_modules/mongoose/lib/index.js:340:10)
    at Object.<anonymous> (/workspace/webdevbootcamp/YelpCamp/v3/app.js:9:10)
    at Module._compile (internal/modules/cjs/loader.js:778:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:789:10)
    at Module.load (internal/modules/cjs/loader.js:653:32)
    at tryModuleLoad (internal/modules/cjs/loader.js:593:12)
    at Function.Module._load (internal/modules/cjs/loader.js:585:3)
    at Function.Module.runMain (internal/modules/cjs/loader.js:831:12)
    at startup (internal/bootstrap/node.js:283:19)
    at bootstrapNodeJSCore (internal/bootstrap/node.js:622:3)
(node:1129) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by reje
cting a promise which was not handled with .catch(). (rejection id: 1)

 

데이터를 불러올 mongodb와 연결에 문제가 있을 경우 발생한다.

1. mongodb가 실행되어 있는지 확인
mongdb 실행 명령어: mongod

2. mongoose와 mongodb connection을 확인한다. 기본 포트는 27017이다.

// mongodb와 mongoose 연결하여 js로 mongodb 사용 가능하게 설정한다. 27017은 mongodb의 기본 포트
mongoose.connect("mongodb://localhost:27017/yelp_camp", {useNewUrlParser: true, useUnifiedTopology: true});

RESTful ROUTES table

Name Path HTML Verb Purpose Mongoose Method
INDEX /blogs GET List all blogs Blog.find()
New /blogs/new GET Show new blog form N/A
Create /blogs POST Create a new blog, then redirect somewhere Blog.create()
Show /blogs/:id GET Show info about one specific blog Blog.findById()
Edit /blogs/:id/edit GET Show edit form for one blog Blog.findById()
Update /blogs/:id PUT Update a particular blog, then redirect somewhere Blog.findByIdAndUpdate()
Destroy /blogs/:id DELETE Delete a particular blog, then redirect somewhere Blog.findByIdAndRemove()

 

# Sanitize(바람직하지 못한 부분을 삭제하다. 살균하다) blog body

# Style Index # Update REST Table

1. Sanitizer (block '<'script> tag from userside(req.body)

1) install sanitizer npm install express-sanitizer --save

2) call and config

const expressSanitizer = require("express-sanitizer"), app.use(expressSanitizer()); 
// Only requirement is expressSanitizer should be used after bodyParser

3) Apply sanitizer for CREATE and UPDATE

 

2. Edit index.ejs

1) Put all contents in the center

2) Other design

 

 

Hi All,

In the next lecture, around the 4 minute and 10 second mark, Colt cuts the sanitizer code from the create (post) route. You should leave this code there and copy it instead. Both the create and update routes need the sanitization code.

Also, if you get the Cannot read property 'substring' of undefined error then you have Blog post(s) in the database that don't have a body property. This can be fixed by removing the existing blogs from the database (mongo shell). You can also add client side validation to the form to ensure that the body property gets added by adding the required attribute to the opening <textarea> tag.

--------
Cheers,
Ian

#DESTROYYYYY
* Add Destroy Route
* Add Edit and Destroy Links

1. Add DELETE ROUTE

1) Use delete method

2) connection test

3) find and remove

Blog.findByIdAndRemove(req.params.id, err => {

4) redirect page to the "/blogs" either success or not

(normally it should've had "fail page(Opps.. something is wrong....")

2. Edit show.ejs

1) Create button for destroy with DELETE method

2) Create edit <a> (or you can also use <form method="GET"> because EDIT is declared as "get method "

 

3. Design show.ejs

1) <a> and <button> are block level elements (cannot stay in same line)

2) use app.css (customised css) for display: inline;

#Edit/Update
* Add Edit Route
* Add Edit Form
* Add Update Route
* Add Update Form
* Add Method-Override

1. Add Edit Route

2. Add Edit Form

1) Make Edit Form page has information of editing blog(data from DB)

: combination of the SHOW + EDIT

2) call origin data from DB and make them to be shown in page

<!--title--> <input type="text" name="blog[title]" value="<%= blog.title %>">
<!--imgage--><input type="text" name="blog[image]" value="<%= blog.image %>">
<!--body--><textarea name="blog[body]"><%= blog.body %></textarea>
		<!-- <textarea> doesn't have a value attribute  -->

3. Route config

1) HTML doesn't support PUT method via

<form class="ui form" action="/blogs/<%=blog._id%>?_method=PUT" method="POST">	https://webdevbootcamp-mjkog.run.goorm.io/blogs/5f7597099aba501f1e2503e0?blog%5Btitle%5D=Person+in+black+t-shirts+with+%3Cstrong%3E%3C%2Fstrong%3E+tag+test-1&blog%5Bimage%5D=https%3A%2F%2Fimages.unsplash.com%2Fphoto-1601408656579-bd835432e773%3Fixlib%3Drb-1.2.1%26ixid%3DeyJhcHBfaWQiOjEyMDd9%26auto%3Dformat%26fit%3Dcrop%26w%3D934%26q%3D80&blog%5Bbody%5D=Fourth+Edited+text+">

<form>태그의 method는 POST임에도 실제 전달된 Request Method는 GET임을 알 수 있다.

 

2) How to solve?

a) Install method-override

b) forcely convert mehod as put using "?_method=PUT"

<form class="ui form" action="/blogs/<%=blog._id%>?_method=PUT" method="POST">

action 속성으로 전달되는 부분에 ?_method=PUT을 하드코딩한 후 methodOverride framework를 사용한다.

3) Insert method-override

// app.js 에 추가
methodOverride = require("method-override"), // call method-override so that method="POST" can be used

 

a) express서버가 요청받은 url에 "_method" 의 syntax가 있을 경우 자동으로 적용

 app.use(methodOverride("_method")); //url에 있는 argument에 "_method"가 있을 경우 사용됨

 

4) find existing data and update that data

app.put("/blogs/:id", (req, res) => {
	// 3) use sanitize for preventing <script> attact
	req.body.blog.body = req.sanitize(req.body.blog.body);
	// 1) connection test
	// res.send("UPDATE ROUTE!")
	// 2) find existing data and update that data 
	Blog.findByIdAndUpdate(req.params.id, req.body.blog, (err, updatedBlog) => {//findByIdAndUpdate(id, newData, callback) takes three arguments 
		if(err){
			console.log(err);
			res.redirect("/blogs")
		} else {
			res.redirect("/blogs/" + req.params.id);
		}
	}) 
})

a) Blog.findByIdAndUpdate()

: 이름처럼 실제로 findById로 DB를 조회한 후 Update를 시키는 메소드이다.

b) Blog.findByIdAndUpdate(id, newData, callback) takes three arguments

: findByIdAndUpdate는 3개의 arguments를 가지며, 사용되는 형태는 아래와 같다.

Blog.findByIdAndUpdate(req.params.id, req.body.blog, (err, updatedBlog) => {//findByIdAndUpdate(id, newData, callback) takes three arguments 
	if(err){
		console.log(err);
		res.redirect("/blogs")
	} else {
		res.redirect("/blogs/" + req.params.id);
	}
}) 

 

5) findByIdAndUpdate 사용 시 에러 관련 :

(node:11676) DeprecationWarning: Mongoose: `findOneAndUpdate()` and `findOneAndDelete()` without the `useFindAndModify` option set to false are deprecated. See: https://mongoosejs.com/doc s/deprecations.html#findandmodify

a) node js에서 호출하는 부분에 옵션 추가

mongoose.connect("mongodb://localhost:27017/restful_blog_app", {useNewUrlParser: true, useUnifiedTopology: true, useFindAndModify: false}); 부분을 app.js에 추가한다.

<div class="description">
	<p><%- blog.body.substring(0, 100) %>...</p> <!-- This only shows 100 character of the body-->
</div>

#SHOW time 
* Add Show route 
* Add show template 
* Add links to show page 
* Style show template

1. Add /blogs/:id route to the app.js

app.get("/blogs/:id", (req, res) => {
	// 1) connection test
		// res.send("SHOW PAGE!");
	// 2) get Id of a particular item and respose, render "show" page for showing detail info of the item
	Blog.findById(req.params.id, (err, foundBlog) =>{
		if(err){
			console.log(err)
			res.redirect("/blogs");
		} else {
			res.render("show", {blog: foundBlog}) // send the particular item's info(name, body, id etc) to show page as name of the blog
		}
	  })	// take 2 arguments(id, callBack)
})

2. Add "More info" button on the index.ejs

: checkout lesson 322

3. Add getting Id info function to the app.get("blogs/:id")

: checkout 1

4. Create show page for showing more info for particular data and design

<%- include("./partials/header")%>

<div class="ui main text container segment">
    <div class="ui huge header"><%= blog.title %></div>
		<div class="ui top attached">
			<div class="item">
				<img class="ui centered rounded image" src="<%= blog.image %>">
				<div class="content">
					<span><%= blog.created.toDateString() %></span>
				</div>
				<div class="description">
					<p><%- blog.body %></p>
				</div>
				<a class="ui orange basic button" href="/blogs/<%= blog._id%>/edit">EDITE</a> <!-- <a> tag and <form> tag aren't inline block-->
				<form id="delete" action="/blogs/<%= blog._id %>?_method=DELETE" method="POST">
					<button class="ui red basic button">DELETE</button>
				</form>
		</div>
			
	</div>
		
</div>

<%- include("./partials/footer")%>

 

5. change index for showing only small preview as other websites do

<%= blog.body.substring(0, 100) %>...
<!-- DB에 저장된 blog.body의 일부(0~100번째 글자) 만 출력한다. 
미리보기 개념으로 사용하여 사용자에게 일부 내용을 보여준다.-->

6. <html> 태그가 blog.body(text content)에 사용될 수 있도록 하여 모든 글이 하나의 문단으로 출력되는 것을 방지

1) tag change this code

<p><%- blog.body.substring(0, 100) %>...</p> <!-- This only shows 100 character of the body-->

2) Issue of the allow to use <%- %>

<script>alert("I HACKED YOU")</script>
<!--
<html>태그를 사용할 수 있도록 하여 텍스트의 가독성을 높였지만, 반대로 <script>태그가
이용가능해짐에 따라 보안에 문제가 생긴다. 이는 expressSanitizer를 이용하여 방지한다(322강 참조)
-->​

 

 

Hi Everyone!
In the next lecture Colt will introduce a way to shorten text with the .substring() method.

Due to the way the app has been built thus far, this may cause an error for you.

If you get the following error: Cannot read property 'substring' of undefined then you have Blog post(s) in the database that don't have a body property. 

This can be fixed by removing the existing blogs from the database (mongo shell). 

You can also add client side validation to the form to ensure that the body property always gets added by adding the required attribute to the opening <textarea> tag.



Also, if you're confused on how to traverse folders using the following syntaxes: ./, ../, and /, then see below:

/ means go back to the root folder, then traverse forward/downward.

./ means begin in the folder we are currently in (current working directory) and traverse forward/downward in the tree.

../ means go up one directory, then begin the traverse.

--------
Cheers,
Ian

+ Recent posts