The Web Developer - (Udemy)_ YelpCamp: 재구성 및 플래시

‍정진철·2022년 8월 16일
0

web devloper (udemy)

목록 보기
24/34
post-thumbnail

1) 캠프그라운드 경로 빠져나오기

app.js 파일을 간소화 시키기 위해 campground 경로를 사용하는 메소드만 별도로 저장

  • 주의점: routes 폴더 기준 밑에 호출된 변수들은 두번에 걸쳐 해당 파일들에 접근해야하므로 ' .. / ' 등의 방식으로 '.' 을 두번 입력해줘야함.
const express = require('express');
const router = express.Router();
const catchAsync = require('../utils/catchAsync')
const { campgroundSchema } = require('../schemas.js')
const ExpressError = require('../utils/ExpressError')
const Campground = require('../models/campground');



const validateCampground = (req,res,next) => {
    //스키마가 정의되면 스키마에 데이터를 전달해야함.
    const { error } = campgroundSchema.validate(req.body)
    if(error){
        // join : 메시지가 한개 이상이면 콤마로 연결시킴.
        const msg = error.details.map(el => el.message).join(',');
        throw new ExpressError(msg, 400)
    } else {
        //next를 해야 catchAsync에서 오류 잡아냄.
        next();

        
    }
}


//index page
router.get('/', catchAsync(async (req, res) => {
    const campgrounds = await Campground.find({});
    res.render('campgrounds/index', { campgrounds })
}));

//중요!!! 바로 밑 코드에서 router.get('/campgrounds:/id') 밑에 해당 코드를 적어주면 
//new를 id로 인지해서  new라는 id의 캠핑장을 찾게됨
// 따라서 id 가 적혀진 코드보다 위에 적어줘야함.
//Add Campground
router.get('/new', (req, res)=> {
    res.render('campgrounds/new');
})

//Add button Click 
//validateCampground : 폼 제출시 규칙을 지켜가며 제출했는지에 대한 점검
//catchAsync : 
router.post('/', validateCampground , catchAsync(async(req, res, next)=> {
    //if(!req.body.campground) throw new ExpressError('Invalid Campground Data', 400)
    //Campground의 새로운 객체 (폼에 입력된 새로운 캠프장 정보)

    //mongoose스키마는 아님. 몽구스로 저장하기 전에 데이터 유효성 검사 진행.
    const campground = new Campground(req.body.campground);
    await campground.save();
    res.redirect(`/campgrounds/${campground._id}`)
 
}))

//when Click one of the Campground (Information)
router.get('/:id' , catchAsync(async (req, res,next) => {
    const { id } = req.params;
    const campground = await Campground.findById(id).populate('reviews')
    res.render('campgrounds/show', { campground });
}));


//Edit Campground
router.get('/:id/edit', catchAsync(async(req,res,next)=>{
    //해당 id로 캠핑장 찾기.
    const campground = await Campground.findById(req.params.id);
    res.render('campgrounds/edit', { campground })
}));


// Update button Click 
router.put('/:id', catchAsync(async(req, res, next)=> {
    const { id } = req.params;
    // 두번째 인수는 실제로 업데이트 할 쿼리, '...'을 붙이는 이유는 업데이트된 정보를 전체 객체에 전달하기위해
    const campground = await Campground.findByIdAndUpdate(id, {...req.body.campground});
    res.redirect(`/campgrounds/${campground._id}`)
}))

router.delete('/:id', catchAsync(async (req,res,next)=> {
    const { id } = req.params;
    const campground =  await Campground.findByIdAndDelete(id);
    res.redirect('/campgrounds')
}));

module.exports = router;

  • app.js에서 라우터 사용하기


2) 리뷰 경로 빠져나오기

app.js


<review.js>
const express = require('express');
const router = express.Router({ mergeParams = true });
const catchAsync = require('../utils/catchAsync')
const { reviewSchema } = require('../schemas.js')
const ExpressError = require('../utils/ExpressError')
const Campground = require('../models/campground');
const Review = require('../models/review')


const validateReview = (req,res,next) => {
    const { error } = reviewSchema.validate(req.body)
    if(error) {
        const msg = error.details.map(el => el.message).join(',');
        throw new ExpressError(msg, 400)
    } else {
        next();
    }
}


router.post('/' , validateReview , catchAsync(async(req,res) => {
    const { id } = req.params;
    const campground = await Campground.findById(id);
    const review = new Review(req.body.review);
    campground.reviews.push(review);
    await review.save();
    await campground.save();
    res.redirect(`/campgrounds/${campground._id}`)

}))

router.delete('/:reviewId', catchAsync(async(req,res,next)=> {
    const {id, reviewId} = req.params;
    //두번쨰 인자는 객체 전달
    //$pull : 배열에 있는 모든 인스턴스 중 특정 조건에 만족하는 값을 지움
    // reviews 객체들 중 reviewId가 있는걸 모두 지움.
    await Campground.findByIdAndDelete(id, { $pull: {reviews: reviewId }})
    await Review.findByIdAndDelete(reviewId);
    res.redirect(`/campgrounds/${id}`);

}))


module.exports = router;

app.js 와 reviews.js의 분리된 id 매개변수 병합시키기

const router = express.Router({ mergeParams = true });


3) 정적 Assets 서비스

  • boilerplate.js 에 있는 하단의 클라이언트 측 유효성 검사 코드를 validateForms.js로 이동
<validateFomrs.js>
      // Example starter JavaScript for disabling form submissions if there are invalid fields
      (function () {
        "use strict";
    
        // Fetch all the forms we want to apply custom Bootstrap validation styles to
        const forms = document.querySelectorAll(".validated-form");
    
        // Loop over them and prevent submission
        Array.from(forms).forEach((form) => {
          form.addEventListener(
            "submit",
            (event) => {
              if (!form.checkValidity()) {
                event.preventDefault();
                event.stopPropagation();
              }
    
              form.classList.add("was-validated");
            },
            false
          );
        });
      })();

boilerplate.js


app.js에 public 폴더 내 파일들을 사용할거라고 알려주기.


4) 세션 구성하기

  • 세션 추가 이유 : 1) 플래시 메시지 생성 2) 인증 추가

  • 세션 만료기한 설정 (밀리세컨드 기준이므로 곱하기 1000, 그 뒤 숫자는 60초 , 60분, 24시간, 7일로 잡음)


5) 플래시 설정하기

npm i connect-flash (터미널 설치 명령어)


<app.js>
const flash = require('connect-flash')
app.use(flash());

  • req.flash에 키-값 쌍을 전달해 플래시 생성

  • success, error 메시지 사용하기 위해 res.locals 사용

  • boilerplate.js 에 success 메시지 호출.


5) Flash_Success 파셜

req.flash

<flash.ejs>

<% if(success && success.length) %>
<div class="alert alert-success alert-dismissible fade show" role="alert">
  <%= success %>
  <button
    type="button"
    class="btn-close"
    data-bs-dismiss="alert"
    aria-label="Close"
  >
    <span aria-hidden="true">&times;</span>
  </button>
</div>
<% } %>


boilerplate.ejs에 flash.ejs 사용 알리기.


router 파일에 req.flash 설정


6) Flash_Error 파셜

boilerpalte.ejs


해당 캠핑장 삭제 후 url 입력시 정보를 불러 올 수 없을 때


profile
WILL is ALL

0개의 댓글