게시판 - Post-User 관계(relationship) 만들기

소스코드

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

이 게시물의 소스코드는 게시판 만들기 / 게시판 - Post Error 처리에서 이어집니다.

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

git reset --hard
git pull
git reset --hard 9d00684
git reset --soft 0a4b23b
npm install
atom .

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

git clone https://github.com/a-mean-blogger/board.git
cd board
git reset --hard 9d00684
git reset --soft 0a4b23b
npm install
atom .

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


게시물과 사용자 사이에 관계(relationship)을 만들어 봅시다. 게시물 document에 작성자 document id를 기록하여 글 작성자 정보를 알 수 있게 됩니다.

이게 왜 중요한가 하면, 로그인 기능으로 현재 사이트에 로그인 한 유저가 누군지 알 수 있게 됐고, 여기에 작성자가 기록되면 자신이 작성한 글, 다른 사람이 작성한 글의 구분이 가능해 집니다. 즉 자신의 글은 삭제가 가능/남의 글은 삭제가 불가능하게 할 수 있습니다. 이번 게시물에서는 일단 게시물에 작성자를 만드는 법만 알아보겠습니다.

폴더구조

코드 - js

// models/Post.js

...

// schema
var postSchema = mongoose.Schema({
  title:{type:String, required:[true,'Title is required!']},
  body:{type:String, required:[true,'Body is required!']},
  author:{type:mongoose.Schema.Types.ObjectId, ref:'user', required:true}, // 1
  createdAt:{type:Date, default:Date.now},
  updatedAt:{type:Date},
});

...

1. post schema에 author를 추가해 줍니다. 또한 ref:'user'를 통해 이 항목의 데이터가 user collection의 id와 연결됨을 mongoose에 알립니다. 이렇게 하여 user의 user.id와 post의 post.author가 연결되어 user와 post의 relationship이 형성되었습니다.

// routes/posts.js

...

// Index
router.get('/', function(req, res){
  Post.find({})
    .populate('author') // 1
    .sort('-createdAt')
    .exec(function(err, posts){
      if(err) return res.json(err);
      res.render('posts/index', {posts:posts});
    });
});

...

// create
router.post('/', function(req, res){
  req.body.author = req.user._id; // 2
  Post.create(req.body, function(err, post){
    if(err){
      req.flash('post', req.body);
      req.flash('errors', util.parseError(err));
      return res.redirect('/posts/new');
    }
    res.redirect('/posts');
  });
});

// show
router.get('/:id', function(req, res){
  Post.findOne({_id:req.params.id}) // 3
    .populate('author')             // 3
    .exec(function(err, post){      // 3
      if(err) return res.json(err);
      res.render('posts/show', {post:post});
    });
});

...

1. Model.populate()함수는 relationship이 형성되어 있는 항목의 값을 생성해 줍니다. 현재 post의 author에는 user의 id가 기록되어 있는데, 이 값을 바탕으로 실제 user의 값을 author에 생성하게 됩니다.

2. 글을 작성할때는 req.user._id를 가져와서 post의 author에 기록합니다.
(req.user는 로그인을 하면 passport에서 자동으로 생성해 줍니다.. 기억하죠?)

3. index와 마찬가지로 show에도 .populate()함수를 추가하였습니다.

코드 - ejs

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

...
      <table class="board-table table table-sm border-bottom">

        <thead class="thead-light">
          <tr>
            <th scope="col">Title</th>
            <th scope="col" class="author">Author</th> <!-- 1 -->
            <th scope="col" class="date">Date</th>
          </tr>
        </thead>

        <tbody>
          <% if(posts == null || posts.length == 0){ %>
            <tr>
              <td colspan=100> There is no data to show :( </td>
            </tr>
          <% } %>
          <% posts.forEach(function(post) { %>
            <tr>
              <td>
                <a href="/posts/<%= post._id %>"><div class="ellipsis"><%= post.title %></div></a>
              </td>
              <td class="author"> <!-- 2 -->
                <div class="ellipsis"><%= post.author ? post.author.username : "" %></div>
              </td>
              <td class="date">
                <span data-date="<%= post.createdAt %>"><%= post.createdAt %></span>
              </td>
            </tr>
          <% }) %>
        </tbody>

      </table>

...

1. tabletheader에 author 항목을 추가합니다.

2. tabletbody에 author 항목을 추가하고 author가 있는 경우 author의 username을 표시합니다.

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

...
            <div class="post-info card m-2 p-2">
              <div class="border-bottom pb-1 mb-1"> <!-- 1 -->
                <span>Author</span> : <%= post.author ? post.author.username : "" %>
              </div>
              <div><span>Created</span> : <span data-date-time="<%= post.createdAt %>"><%= post.createdAt %></span></div>
              <% if(post.updatedAt) { %>
                <div><span>Updated</span> : <span data-date-time="<%= post.updatedAt %>"><%= post.updatedAt %></span></div>
              <% } %>
            </div>
...

1. index와 마찬가지로 show에도 author 항목을 추가하고 author가 있는 경우 author의 username을 표시합니다.

코드 - css

/* pulbic/css/master.css */

...

.board-table {
  table-layout: fixed;
}
.board-table .author,
.board-table .date {
  width: 100px;
}

...

실행결과

로그인을 한 후에 글을 작성해 봅시다.

post index 페이지에 author가 표시됩니다.

post show에서도 표시가 됩니다.

마치며...

이제 게시판에 누가 글을 썼는지 알 수 있습니다!

다음 강의에서는 로그인 유무, 글 작성자 본인 확인을 통해 사이트의 기능을 제한하는 방법을 알아보겠습니다.

댓글

꽃선생 2020.04.08
강좌에서 도움 많이 받았습니다. 감사합니다. 질문이 하나 있습니다. 관리자페이지에서 게시글 앞에 체크박스를 통한 전체/선택 삭제 기능은 어떻게 구현하나요?
I
Ian H 2020.04.09
@꽃선생,
1. user 모델에 admin 항목을 추가하여 누가 admin인 유저를 추가 2. post의 index view파일에 체크박스들을 심고, 삭제 버튼을 만든 후에 관리자에게만 보이게 설정 3. 삭제버튼 클릭시 체크박스가 체크된 post들의 id들을 모아서 submit하는 form을 만듦  4. 삭제버튼 클릭시에 이 요청을 처리할 route을 만듦
이렇게 만들면 됩니다!
댓글쓰기

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

UP