게시판 - 접근제한

소스코드

이 게시물에는 코드작성이 포함되어 있습니다. 소스코드를 받으신 후 진행해 주세요. MEAN Stack/개발 환경 구축에서 설명된 프로그램들(git, npm, atom editor)이 있어야 아래의 명령어들을 실행할 수 있습니다.

이 게시물의 소스코드는 게시판 만들기 / 게시판 - Post-User 관계(relationship) 만들기에서 이어집니다.

board.git 을 clone 한 적이 있는 경우: 터미널에서 해당 폴더로 이동 후 아래 명령어들을 붙여넣기합니다. 폴더 내 모든 코드가 이 게시물의 코드로 교체됩니다. 이를 원치 않으시면 이 방법을 선택하지 마세요.

git reset --hard
git pull
git reset --hard 92c43d3
git reset --soft 19d8720
npm install
atom .

board.git 을 clone 한 적이 없는 경우: 터미널에서 코드를 다운 받을 폴더로 이동한 후 아래 명령어들을 붙여넣기하여 board.git 을 clone 합니다.

git clone https://github.com/a-mean-blogger/board.git
cd board
git reset --hard 92c43d3
git reset --soft 19d8720
npm install
atom .

- Github에서 소스코드 보기: https://github.com/a-mean-blogger/board/tree/92c43d33481edbdb223eba41d3405d4cb161c46f


이제까지의 강의로 웹사이트가 현재 로그인된 사용자를 기억하며, 게시물 작성시 작성자를 기록하게 되었습니다.

이번 강의에서는 로그인을 하지 않았을 경우 글 작성을 제한하고, 자신이 작성한 글이 아닌 경우에는 글의 수정 및 삭제를 제한하며, 마지막으로 자신이 아닌 사용자 정보의 수정을 제한하도록 합니다.

접근제한은 두가지 단계로 이루어 지는데, 첫번째로 front-end에서의 해당 버튼들이 보이지 않게하여 아예 접근이 불가능하도록 해야 하며, 두번째로 back-end에서 해당 요청이 오는 경우 사용자를 비교하여 error를 return하도록 해야 합니다.

폴더구조

코드 - js

// util.js

util.isLoggedin = function(req, res, next){
 if(req.isAuthenticated()){
  next();
 } else {
  req.flash("errors", {login:"Please login first"});
  res.redirect("/login");
 }
}

util.noPermission = function(req, res){
 req.flash("errors", {login:"You don't have permission"});
 req.logout();
 res.redirect("/login");
}

모든 route에서 공용으로 사용될isLoggedinnoPermission함수를 util.js에 만듭니다.

isLoggedin은 사용자가 로그인이 되었는지 아닌지를 판단하여 로그인이 되지 않은 경우 사용자를 에러 메세지("Please login first")와 함께 로그인 페이지로 보내는 함수입니다.

route에서 callback으로 사용될 함수이므로reqresnext를 받습니다. 로그인이 된 상태라면 다음 callback함수를 호출하게 되고, 로그인이 안된 상태라면 로그인 페이지로 redirect합니다.

noPermission은 어떠한 route에 접근권한이 없다고 판단된 경우에 호출되어 에러 메세지("You don't have permission")와 함께 로그인 페이지로 보내는 함수입니다.reqres가 있지만 callback으로 사용하지는 않고 일반 함수로 사용할 예정입니다. isLoggedin과 다르게 접근권한이 있는지 없는지를 판단하지는 않는데, 상황에 따라서 판단 방법이 다르기 때문입니다.

// routes/posts.js

var express = require("express");
var router = express.Router();
var Post  = require("../models/Post");
var util  = require("../util");

// Index ...

// New
router.get("/new", util.isLoggedin, function(req, res){ // 2
 // ...
});

// create
router.post("/", util.isLoggedin, function(req, res){ // 2
 // ...
});

// show ...

// edit
router.get("/:id/edit", util.isLoggedin, checkPermission, function(req, res){ // 2, 3
 // ...
});

// update
router.put("/:id", util.isLoggedin, checkPermission, function(req, res){ // 2, 3
 // ...
});

// destroy
router.delete("/:id", util.isLoggedin, checkPermission, function(req, res){ // 2, 3
 // ...
});

module.exports = router;

// private functions // 1
function checkPermission(req, res, next){
 Post.findOne({_id:req.params.id}, function(err, post){
  if(err) return res.json(err);
  if(post.author != req.user.id) return util.noPermission(req, res);

  next();
 });
}

1. Post에서checkPermission함수는 해당 게시물에 기록된 author와 로그인된 user.id를 비교해서 같은 경우 통과, 만약 다르다면 util.noPermission함수를 호출합니다.

2. new, create, edit, update, destroy에 util.isLoggedin를 사용해서 로그인이 된 경우에만 다음 callback을 호출합니다.

3. edit, update, destroy에 checkPermission를 사용해서 본인이 작성한 글에만 다음 callback을 호출합니다.

// routes/users.js

var express = require("express");
var router = express.Router();
var User  = require("../models/User");
var util  = require("../util");

// Index
router.get("/", util.isLoggedin, function(req, res){ // 1
 // ...
});

// New ...
// create ...

// show
router.get("/:username", util.isLoggedin, function(req, res){ // 1
 // ...
});

// edit
router.get("/:username/edit", util.isLoggedin, checkPermission, function(req, res){ // 1, 3
 // ...
});

// update
router.put("/:username", util.isLoggedin, checkPermission, function(req, res, next){ // 1, 3
 // ...
});

module.exports = router;

// private functions // 2
function checkPermission(req, res, next){
 User.findOne({username:req.params.username}, function(err, user){
  if(err) return res.json(err);
  if(user.id != req.user.id) return util.noPermission(req, res);

  next();
 });
}

1. User에서checkPermission함수는 해당 user의 id와 로그인된 user.id를 비교해서 같은 경우 통과, 만약 다르다면 util.noPermission함수를 호출합니다.

2. index, show, edit, update에util.isLoggedin를 사용해서 로그인이 된 경우에만 다음 callback을 호출합니다.

3. edit, update에 checkPermission를 사용해서 본인의 정보에만 다음 callback을 호출합니다.

코드 - ejs

<!-- views/posts/index.ejs -->

   <div class="buttons">
    <% if(isAuthenticated){ %> <!-- 1 -->
     <a class="btn btn-default" href="/posts/new">New</a>
    <% } %> <!-- 1 -->
   </div>

1. index.ejs에서 new 버튼은 로그인된 경우에만 보이게 됩니다. 참고로isAuthenticated는 게시판 - Login 기능 추가강좌에서 index.js속에 만들었던 함수입니다. req.locals에 들어있어서 ejs에서 바로 사용할 수 있습니다.

<!-- views/posts/show.ejs -->

   <div class="buttons">
    <a class="btn btn-default" href="/posts">Back</a
    <% if(isAuthenticated && currentUser.id == post.author.id){ %> <!-- 1 -->
     <a class="btn btn-default" href="/posts/<%= post._id %>/edit">Edit</a>
     <form action="/posts/<%= post._id %>?_method=delete" method="post">
      <a class="btn btn-default" href="#" onclick="confirm('Do you want to delete this?')?this.parentElement.submit():null;">Delete</a>
     </form>
    <% } %> <!-- 1 -->
   </div>

1. 로그인이 된 상태이고, 게시물의 작성자 id(post.author.id)와 현재 로그인된 사용자의 id(currentUser.id)가 일치하는 경우에만 edit, delete 버튼을 보여줍니다. currentUser 역시 req.locals에 들어있어서 ejs에서 바로 사용할 수 있습니다.

<!-- views/users/show.ejs -->

   <div class="buttons">
    <a class="btn btn-default" href="/users">Back</a>
    <% if(isAuthenticated && currentUser.id == user.id){ %> <!-- 1 -->
     <a class="btn btn-default" href="/users/<%= user.username %>/edit">Edit</a>
    <% } %> <!-- 1 -->
   </div>

1. 로그인이 된 상태이고, 해당 user id(user.id)와 현재 로그인된 사용자의 id(currentUser.id)가 일치하는 경우에만 edit 버튼을 보여줍니다.

실행결과

로그인 전

index view에 new 버튼이 없습니다.

show view에 edit, delete 버튼이 없습니다.

로그인 후

new 버튼이 보입니다.

자신이 작성한 게시물의 경우 edit, delete 버튼이 보입니다.

로그인 하지 않은 상태에서 강제로 /posts/new로 가려고 하는 경우,

에러메세지와 함께 로그인화면으로 redirect됩니다.

마치며...

이제 1. data의 CRUD 구현, 2. data 간의 관계 형성, 3. 로그인 구현, 4. 접근 제한까지 웹사이트 제작의 큰 틀은 모두 익히셨습니다!
나머지는 위의 내용의 확장 혹은 일반적인 문제해결 들입니다.(예를 들어 댓글기능, 검색기능, 관리자 기능 등등.. 지금까지 배운 내용을 응용하고 일반적인 프로그래밍 방법을 활용하면 구현가능합니다.)

게시판이 완벽하진 않지만 이 강좌는 위 4가지 주제를 익히기 위한 것으로 게시판 강좌는 여기까지 입니다. 나중에 기회가 있다면 게시판을 완전히 완성하는 강좌를 따로 해보도록 하겠습니다.

수고하셨습니다!

댓글

성준영 2017.01.17
좋은강좌 잘 보고 있습니다!! 후...mean stack 이라는걸 알게되고 접하면서 공부해보면서 조금 혼란이 오기 시작하네요...ㅠㅠ 서버, DB, Back-End 까지는 제가 다루고있는 java와 비교했을때 프레임워크를 씌워서 복잡한 xml 설정을 다 하지 않고도 간단하게 만들수 있다는걸 느끼게 되었는데 Front-End 쪽이 조금 복잡하네요..ㅎㅎ jsp의 el태그 혹은 jstl같은 플러그인에 적응되어서 그런지 좀 많이 복잡해보여집니다..ㅠ_ㅠ
I
Ian H 2017.02.17
@성준영,
front-end 쪽이 복잡한 것은 제 강의 실력이 부족하기 때문이죠 ㅠ 요점만 콕콕 찝어서 강의용 코드를 만들어야 되는데.. 그게 쉽지 않더라구요.
진짜 MEAN stack은 ejs를 사용하지 않으므로 걱정 하지 마시라고 말씀드리고 싶지만.. 생각해 보니 Angular 를 쓰는군요. 음..  Angular 도 좀 복잡한데, 익숙해 지면 괜찮습니다..!
K
Kyowon Im 2017.02.16
정말 잘 보고 있습니다.
위에 routes 코드에서 posts와 users인데 둘다 주석이 // routes/posts.js 로 되어있습니다.
I
Ian H 2017.02.17
@Kyowon Im,
앗, 수정하겠습니다. 감사합니다.
안암치킨 2017.06.06
안녕하세요 강좌 잘 봤습니다. 정말 감사드립니다! 혹시 질문 하나 드려도 될까요. 저는 MEAN 스택이라는 걸 알기전에는 A2Hosting이라는 웹호스팅 업체의  shared hosting 서버를 통해 웹사이트 개발을 연습하고 있었습니다. 제가 이용하는 웹호스팅 업체로도 Node 서버 구현이 가능하긴 하더라구요. 그렇지만 MEAN 스택으로 웹 어플리케이션 개발시 선호되거나, 추천하시는 서버가 있으신가요??
I
Ian H 2017.06.06
@안암치킨,
사용하려는 용도에 따라 다르시겠지만 저는 현재 heroku를 사용중입니다. 이 a-mean-blog.com이 올라와 있는 서버도 heroku입니다.(무료버전이라 종종 응답이 늦습니다) 그 외 amazon web service에서도 쓸 수 있고, Angular만 돌릴려면 node서버 쓸 필요 없이 static 파일만 서버에 올려도 돌아갑니다. heroku 서버에 node.js 올리는 법도 따로 강의를 만들 예정입니다.
안암치킨 2017.06.07
@Ian H,
아 넵 친절한 답변 감사드립니다~!
n
nodejs222222222222 2017.07.18
궁금한게있는데 글쓰기부분은  WYSIWYG 모듈을 쓰신건가요? 
I
Ian H 2017.07.19
@nodejs222222222222,
이 블로그 사이트 말씀하시는건가요? summer note 사용해서 글작성하고 있습니다.
n
nodejs222222222222 2017.08.15
@Ian H,
아 글쿤요 !
오늘도너를 2017.10.06
안녕하세요 소스 코드를 다운받아서 작동 시켜보니까 new.ejs 에서 <div>errors.passwordConfirmation)</div> 이쪽 부분이 안나오는데 왜 그런걸까요? ㅜㅜ
I
Ian H 2017.10.06
@오늘도너를,
/users/new 페이지에 errors.passwordConfirmation 에러가 표시되어야 하는 상황에 에러가 표시되지 않는다는 말인가요?
오늘도너를 2017.10.07
@Ian H,
아이디를 새로 만들때요~ 아이디가 중복 되는 경우 그냥 아래에 빨간 창만 뜨고 메세지는 뜨지 않네요 ㅜㅜ  그래서 어제 이렇게 저렇게 해보니까되더라고요 자세히는 기억이 ㅜㅜ
오늘도너를 2017.10.07
@Ian H,
또 여쭈어볼게... 그 아이디를 edit할때요 잘못되면 redirect를 하잖아요~ 근데 페이지를 res.redirect를 하면 edit.ejs에서 <%= user.email %> ,<%= user.name %> 이 부분이 출력이 안되는데 어떻게 하면 될까요? 세션은 디비에 저장해서 유지가 될텐데도 그러네요 ㅜㅜ  
I
Ian H 2017.10.08
@오늘도너를,
1. 빨간 창만 뜨고 메세지는 뜨지 않는 경우 : 코드에 문제가 있었네요. 수정하였습니다. 소스코드를 다시 받아주세요
2. user edit은 저는 잘 되는데, 혹시 상황을 좀 더 자세히 설명해 주실 수 있으신가요? 정확히 뭘 어떻게 잘못했을 때 그러는지?
오늘도너를 2017.10.26
@Ian H,
고쳐주셔서 감사합니다 ! edit 는 굉장히 잘되고요! 문제가 생길시에 redirect를 하잖아요 그럼 ejs에서 페이지 로딩할때 가져온 데이터들은 로딩이 되지 않고 빈 박스로만  남아 있는데 그 부분을 어떻게 해결해야할지 잘 모르겠습니다ㅜㅜ
I
Ian H 2017.10.27
@오늘도너를,
어떤 문제가 있을때인지 구체적인 예시로 알 수 있을까요? 제가 할 때는 잘 되거든요.. user edit page 말씀하시는거 맞죠?
오늘도너를 2017.11.13
@Ian H,
질문해놓고 답이 늦어서 죄송해요 ㅜㅜ  덕분에 맡은 프로젝트 끝냈습니다 정말 너무 감사드립니다.
제가 질문드린부분은 이 부분입니다.
router.put("/:id", util.isLoggedin, checkPermission, function(req, res, next){   User.findOne({'id':req.params.id})   .select({password:1})   .exec(function(err, user){     if(err) return res.json(err);
    // update user object     user.originalPassword = user.password;     user.password = req.body.currentPassword? req.body.newPassword : user.password;     for(var p in req.body){       user[p] = req.body[p];     }     // save updated user     if(user.password = req.body.currentPassword){     user.save(function(err, user){       if(err){         req.flash("user", req.body);         req.flash("errors", util.parseError(err));         return res.redirect("/users/"+req.params.id+"/edit");       }       res.redirect("/users/"+req.user.id);     });     } else {       req.flash("user", req.body);       req.flash("errors", util.parseError(err));       return res.redirect("/users/"+req.params.id+"/edit");     }   }); });
edit 화면에서 마지막코드보시면 현재 패스워드가 일치하지 않을경우 redirect를 하는데요 그렇게 redirect를 할경우 저희가 view페이지에 적용했던 <%= user.name %> 이라던가 <%= user.email %>같은 정보가 사라지게 되는데요
이러한 현상(?)을 어떻게 해결해야할지 궁금합니다~
I
Ian H 2017.11.15
@오늘도너를,
이번 강의의 코드를 heroku에 올려봤습니다. https://lit-falls-48510.herokuapp.com/ 에서 한번 테스트 해보세요.
edit에서 현재 비밀번호가 일치하지 않는 경우 입력한 정보가 다시 돌아옵니다.
혹시 이 강의의 코드가 아니라 직접 작성하신 코드에서 해당 현상이 발생하는 것이라면, 해당 코드를 github에 올리시면 제가 체크해 보겠습니다.
오늘도너를 2017.12.21
@Ian H,
신경써주셔서 감사합니다~ 
오늘도너를 2017.10.06
그리고 이 댓글 기능은 어떻게구현하셨나요 궁금해여~
I
Ian H 2017.10.06
@오늘도너를,
comment model을 만들고 post id를 넣어 관계를 만들어 준 후 post를 불러올 때 관련된 comment들을 읽어오면 됩니다. 대댓글도 마찬가지로 comment와 comment간에 관계를 만들어 주면 되요
오늘도너를 2017.10.07
@Ian H,
아하아하! 감사합니다.
김남현 2017.11.13
- 참고로isAuthenticated는 게시판 - Login 기능 추가강좌에서 index.js속에 만들었던 함수입니다. req.locals에 들어있어서 ejs에서 바로 사용할 수 있습니다. - currentUser 역시 req.locals에 들어있어서 ejs에서 바로 사용할 수 있습니다.
이런 변수들이 req.locals에 들어있다 라는 것은 어떻게 알 수 있나요? 또한 어디에 들어있으면 ejs에서 바로 쓸 수 있다는 것은 어떤 부분을 공부해야 알 수 있는 것인가요?
I
Ian H 2017.11.13
@김남현,
다른 express 문제에 관해 구글링하다가 stackoverflow에서 req.locals 관련 내용을 읽었습니다. 그리고 express 공식 문서 http://expressjs.com/en/4x/api.html#app.locals 에서 확인하였죠.
김남현 2017.11.17
@Ian H,
음, 그렇군요. 링크를 따라 가보았는데, 저는 아직 문서를 볼 줄 모르는 것 같습니다. 우선 익숙해 져야겠네요. 
김남현 2017.11.17
그런데, https://lit-falls-48510.herokuapp.com/  를 모바일로 들어가면 '반응형 웹'이 아닌 듯 하네요? 맥북에서 크롬으로 들어갔을 때는 화면의 크기가 줄면 자동으로 변했는데, 모바일에서는 변화가 거의 없는 것 같습니다.
I
Ian H 2017.11.17
@김남현,
아, 요즘 폰 브라우져들은 자동으로 웹페이지의 해상도를 조절하기 때문에 header에 <meta name="viewport" content="width=device-width,initial-scale=1"> 를 넣어줘야 폰 브라우저가 임의로 해상도를 바꾸지 않습니다. 아마 강의 코드에 이부분을 넣어버려야겠어요.
H
Hyunsung Kim 2017.11.29
너무너무 감사합니다! 결국 완주했네요! 댓글 부분은 언제쯤 하실까요? 하하핫;;; 제가 욕심이 과하네요
I
Ian H 2017.11.30
@Hyunsung Kim,
사실 node 게시판은 Angular로 넘어가기 전에 맛보기로 하는 거라 댓글까지는 안만들려고 했는데.. 나중에 시간이 되면 만들어 보겠습니다^^
요즘은 실제 웹개발에서 node.js/ejs로 전체 웹사이트를 개발하는 경우는 드물고 node.js로 API를 만들고 Angular나 React등으로 프론트엔드를 구성합니다.
Angular도 반드시 공부하시기 바랍니다~~
H
Hyunsung Kim 2017.11.30
@Ian H,
넵 알겠습니다 우선 네이버 블로그 보면서 댓글부분과 페이징 기능도 같이 맞춰 해보고 있는데 오류 해결이 쉽지가 않네요 하하;; 앵귤러는 ..... 무섭네요 ㅜㅜ
I
Ian H 2017.12.03
@Hyunsung Kim,
오류를 많이 고치면 실력이 쑥쑥 늡니다 ㅋㅋ 그리고 프론트엔드 프레임워크 한 두개 알아놓으면 좋습니다^^
H
Hyunsung Kim 2017.12.23
@Ian H,
하핫... 드디어 댓글과 페이징 기능까지 완료했습니다!! 자바스크립트도 잘 모르는 제가 이렇게까지 만들 수 있게 가이드 써주셔서 너무너무 감사합니다 ㅜㅜ 이제 앵귤러 들어가야겠네요! 사실 이 홈페이지 정도 만들 때까지 귀찮게 질문할겁니다!!! 하하하하하......
I
Ian H 2018.01.03
@Hyunsung Kim,
축하드립니다! 댓글과 페이징까지 혼자서 만드신걸 보면 앵귤러도 잘할 수 있을거에요^^ 질문도 많이 해주세요~~!
쮸리맨 2018.02.24
항상감사드립니다 ㅠ 한가지만 질문해도될까요? 만약에  partials부분에서 nav 즉 
모든페이지에 보이게되는부분 로그인 로그아웃 게시판카테고리 있는부분에 
예를들면 로그인되면 그 사용자의 닉네임이나,총방문자등등을 nav부분에 표시하고 싶다고 하면 모든페이지 라우터에 render할때 디비를찾아서 넘겨줘야하나요? 
I
Ian H 2018.02.25
@쮸리맨,
"res.locals.변수명"에 넣은 정보는 view에 따로 전달하지 않아도 자동으로 사용가능한데요, 일일이 모든 라우터에 넘겨줄 필요 없이 "res.locals.변수명"에 해당 정보를 넣은 후, view에서 "<%= 변수명 % >"으로 호출하여 보여줄 수 있습니다!
쮸리맨 2018.02.25
@Ian H,
아하 역시 그런방법이있었군요!! 감사합니다  
쮸리맨 2018.02.24
아그리고 방금위에 쓴 댓글이랑 저번에 댓글쓴거 사라져서.. 지우셨나? 어디갔나했는데 이게  크롬으로 작성한 댓글이 익스에서는 안보여서 사라진거였네요ㅋㅋㅋㅋㅋ 크롬에서 쓰고 익스로 들어왔는데 제가쓴 댓글이 사라져서 뭐지?? 찾다가  알아챘네요..
I
Ian H 2018.02.25
@쮸리맨,
아이고 저런. 지금은 익스에서도 보이시죠?
쮸리맨 2018.02.25
@Ian H,
넵 감사합니다!
쮸리맨 2018.02.26
몽고디비에는 <h1>안녕하세요<h1>  이렇게 바디가 저장이되는데  이것을 홈페이지에 출력할때  <%= post.body %> 하면  태그가 이스케이프처리가 되어서 태그도그대로 출력되서 몇가지 찾아보니 이스케이프 처리를 안할려면 <%- post.body%> 이런식으로 하면 된다고해서 해결을 하긴했는데
데이터베이스에 html태그를 저장하는건 좋지않다는 말도 있는것같고 그러면   또 <%- 이걸사용하면 보안상 xss 위험에 노출이된다고하는데 
summernote같은 웹에디터를 사용하는경우에는 디비저장할때 태그 원문자랑 필터해서  디비에는 원문자만 따로저장하게하는건가요? 엄청번거로워질것같아서..ㅠ
어떤방법이 좋은방법인가궁금합니다.   
I
Ian H 2018.02.26
@쮸리맨,
오. 저도 블로그 본문 글은 summernote로 작성하고 있습니다. 관리자가 작성하는 게시판이라면 html을 그대로 DB에 저장해도 괜찮습니다. 저도 모든 블로그 글 html그대로 저장하고 있습니다. 
방문자가 작성하는 게시판이라면 html을 작성을 허용하는 것은 권장되지 않습니다.
깝스도깝스 2018.04.17
강의 정말 감사합니다. 한가지 여쭤볼게 있는데요 로그인 후 login페이지를 접근하려고할 때 메인 페이지로 가게하려면 어떻게 해야 할까요 ?
I
Ian H 2018.04.21
@깝스도깝스,
login url 라우터에서 로그인 상태를 확인한 후 로그인된 상태라면 main페이지 url로 redirect하면 되겠습니다^^
칠동이 2019.02.18
만약 A라는 사람이 글을 남기면 B라는 사람이 댓글을 달 수 있는 구조는 어떻게 만들수 있을까요?
I
Ian H 2019.02.18
@칠동이,
지금 post에 user를 달아서 그 글을 누가 작성했는지를 나타내잖아요? user, body, createdAt 등을 가진 comment를 만들고, 이 comment를 post에서 배열로 호출하면 댓글이 됩니다.
칠동이 2019.02.18
일단 /model/Post.js의 스키마에 comments 하나 더 집어넣었는데
var postSchema = mongoose.Schema({   title:{type:String, required:true},   body:{type:String},   createdAt:{type:Date, default:Date.now},   updatedAt:{type:Date},   comments:{type:String},
이렇게 넣으라는 말씀 맞나요?
이 다음에  routes/post.js 에서 reply 단을 만들려는데 이렇게 만드는게 맞는지 모르겠네요
//reply router.put("/:id/show", function(req, res){   Post.findOne({_id:req.params.id}, function(err, post){     if(err) return res.json(err);     res.render("posts/edit", {post:post});   }); });
그리고 마지막으로  /posts/show.ejs 에서 <!-- 댓글달기 -->   <form action="/posts/<%= post._id %>?_method=comments_insert" method="post">
            <button type="submit">reply</button>             <input type="text" id="comments"></input>           </form>
요런식으로 만들어봤는데 제 실력이 미천하여 어떻게 고쳐야할지 모르겠네요 ㅠㅠ  도와주시면 감사하겠습니다. 
칠동이 2019.02.18
//reply 를 어떻게 짜야할지 모르겠어요
I
Ian H 2019.02.19
@칠동이,
Commnet.js 파일 생성후 commentSchema 따로 만드시고 postId: {type:mongoose.Schema.Types.ObjectId, ref:'post'}를 넣어서 post와 관계(relation)를 만들어 줍니다.
칠동이 2019.02.19
routes/posts.js   //reply
router.get("/post/show", function(req, res) {   Post.findOne({_id:req.param.id}, function(err, post){     if(err) return res.json(err);     res.redirect("/posts/"+req.params.id);   }); });
<!-- show.ejs--> //reply            <form action="/posts/<%= post._id%>?_method=comments_insert" method="post">
            <input type="text" id=comments name="comments" value="">             <button type="submit" href="/posts/<%= post._id%>" onclick="this.parentElement.submit():null;">reply</button>             </input>           </form>
요렇게 두개  만들어봐도 안되네용... 어디가 잘못된걸까요
I
Ian H 2019.02.19
@칠동이,
comment는 자신만의 route를 가지는 것이 좋습니다. <form action="/comments?post_id=<%= post._id%>" method="post">
post를 출력할 때 해당 post id를 가지는 comments들을 같이 db에서 가져와서 출력하시면 됩니다.
칠동이 2019.02.20
@Ian H,
혹시 괜찮으시면 이메일로 제 코드 한번만 봐주시겠어요?
칠동이 2019.02.20
post/:id 에서 바로 댓글이 보여야 되는데 자신만의 route을 가지고 /comments?post_id로 어떻게 direct 될수 있는지 모르겠어서요
I
Ian H 2019.02.20
@칠동이,
아. 제가 말한 route은 댓글 작성, 생성을 위한, POST를 위한 route이였구요, 물론 댓글을 보여주는 것은 게시물 route에서 게시물을 출력할 때 Comment.Find({postId:postId})로 찾아서 같이 보여줍니다.
[email protected] 로 이메일 보내주시면 제가 한번 봐 볼게요
칠동이 2019.02.21
@Ian H,
메일 보냈습니다.
댓글쓰기

이 글에 댓글을 다시려면 SNS 계정으로 로그인하세요. 자세히 알아보기

UP