Post 모델에 Fillable 정의 후 새 글 저장 기능 구현

포스트 썸네일 이미지

이전 포스트에서는 web.php 라우팅 설정과 함께 글을 작성하는 페이지를 만들어 보았다.

이제는 사용자가 작성한 글을 실제로 데이터베이스에 저장해 볼 차례다.

라라벨 13의 최신 문법을 활용해 Post 모델에 Fillable 속성을 선언하고, 회원과 글 사이의 일대다(HasMany) 관계 정의를 거쳐 실제 저장(Store) 로직까지 완성해 보겠다.




이전 포스트




회원과 글의 관계 정의


app/Models/User.php에 추가할 코드

public function posts(): HasMany
{
    return $this->hasMany(Post::class);
}

class 내부의 제일 아래쪽에 이 코드를 추가하자.


  • public function posts(): HasMany: User 모델에서 posts()라는 이름으로 관계 메서드를 정의하며, 이 메서드는 라라벨의 일대다(HasMany) 관계 객체를 반환한다는 뜻이다.
  • return $this->hasMany(Post::class);: '한 명의 회원(User)은 여러 개의 글(Post)을 가질 수 있다'라는 일대다(1:N) 관계를 선언하는 것이다. 이 코드가 있으면 컨트롤러에서 $request->user()->posts()와 같은 문법으로 로그인한 유저의 글에 접근할 수 있다.




app/Models/User.php에 추가할 코드

use Illuminate\Database\Eloquent\Relations\HasMany;

마지막으로 상단에 이 코드도 추가해야 한다.

이전 포스트에서 이야기했던 것처럼 PHP Namespace Resolver라는 익스텐션을 VSCode에 설치했다면, public function posts(): HasMany에서 HasMany 부분에 마우스 오른쪽 클릭을 한 후 'Import Class'를 선택하면 자동으로 임포트Import 하는 코드가 생성된다.





Post 모델에 Fillable 정의


app/Models/Post.php에 추가할 코드

#[Fillable(['message'])]

class 위쪽에 이 코드를 넣도록 하자.


데이터베이스의 posts 테이블 컬럼 중에서, 사용자가 입력한 값을 대량 할당Mass Assignment 방식으로 한 번에 안전하게 저장할 수 있도록 허용(화이트리스트)하는 설정이다.

다르게 말하면, 모델의 대량 할당를 허용할 컬럼들을 정의하는 데 사용하는 코드다.


Mass Assignment는 여러 컬럼에 대한 값을 한 번에 모델에 할당하는 기능을 의미한다.

만약 이 설정을 하지 않으면 기본적으로 모든 속성이 대량 할당에 참여할 수 있기 때문에 보안상 좋지 않다.

그러나 #[Fillable([ ... ])]을 사용하여 어떤 컬럼들만이 대량 할당에 참여할 수 있는지 명시적으로 지정할 수 있다.


쉽게 설명하자면, 해커가 악의적으로 다른 컬럼을 조작해 데이터를 집어넣는 공격을 방어하기 위해, 오직 message 컬럼만 한 번에 저장될 수 있도록 락을 걸어둔 것이다.




app/Models/Post.php에 추가할 코드

use Illuminate\Database\Eloquent\Attributes\Fillable;

이것도 역시 Import 해야 한다.

방법은 위에서 설명했었으니 생략한다.




참고로 원래 Fillable을 정의하는 코드는 이전에는 다른 방식으로 작성했었는데, 올해의 최신 버전인 Laravel 13부터 이렇게 바뀌게 되었다.

이전 버전에서는 어떤 방식으로 작성했었는지는 그냥 넘어가도록 하겠다.





PostController의 store 메서드


PostController.php

public function store(Request $request)
{
    $validated = $request->validate([
        'message' => 'required|string|max:300',
    ]);

    $request->user()->posts()->create($validated);

    return redirect(route('posts.index'));
}

비어있던 store 메서드에 이렇게 코드를 추가한다.

이 저장 로직을 아래에서 나눠서 설명하겠다.




$validated = $request->validate([
    'message' => 'required|string|max:300',
]);
  • 유효성 검사Validation를 수행한다. 사용자가 보낸 데이터 중 message라는 값이 필수 입력(required)이며, 문자열(string)이어야 하고, 최대 300자(max:300) 이하여야 한다는 규칙을 적용했다.
  • 만약 이 조건에 맞지 않으면 더 이상 아래 코드로 내려가지 않고, 이전 포스트에서 말한 것처럼 에러 메시지($errors)를 들고 글쓰기 폼 화면으로 다시 되돌아간다.




$request->user()->posts()->create($validated);
  • $request->user(): 현재 이 글쓰기 요청을 보낸 '로그인한 사용자 정보'를 가져온다.
  • ->posts(): 아까 User.php 모델에 정의해 둔 일대다 관계를 호출한다. 라라벨은 이때 자동으로 이 유저의 고유 ID 값을 찾아내어 외래 키 파트너로 준비시킨다.
  • ->create($validated);: 유효성 검사를 마친 안전한 데이터($validated)를 활용해 posts 테이블에 데이터를 인서트Insert한다. 이때, user_id 컬럼에 현재 로그인한 유저의 ID가 자동으로 매핑되어 저장된다. 라라벨의 강점이 발휘되는 구간이다.




return redirect(route('posts.index'));

데이터 저장이 끝나면 마지막으로 브라우저에게 "이제 글 작성이 완료되었으니 posts.index 이름으로 정의된 라우트 주소(즉, /posts 글 목록 화면)로 이동Redirect해." 하고 명령을 내려 화면을 전환한다.





여기까지 코드를 수정하고 나면 이제 글을 저장할 수 있게 된다.

하지만 저장한 글을 표시하는 로직은 아직 구현하지 않은 상태라서 저장 후에도 화면에는 아무런 변화가 없다.




VSCode의 SQLTools 익스텐션으로 DB에 데이터가 잘 저장된 것을 확인

하지만 DB에는 이렇게 저장한 글이 제대로 남아있는 것을 확인할 수 있다.




캡처한 이미지 속의 익스텐션은 여기서 확인할 수 있다.




이렇게 유효성 검사를 통해 악성 데이터의 유입을 필터링하고, 최신 #[Fillable] 속성으로 대량 할당 공격까지 막아낸 안전한 글 저장 기능이 완성되었다.

아직 브라우저 화면에서는 리다이렉트된 후 아직 아무런 변화가 보이지 않지만, 데이터베이스 내부에는 사용자가 쓴 글들이 유저 ID와 매핑되어 저장되고 있는 것을 볼 수 있었다.


백엔드에서 데이터를 안전하게 받고 저장하는 과정을 마쳤으니, 다음 포스트에서는 이렇게 DB에 저장된 글들을 불러와 화면에 표시하는 글 목록 출력 기능을 구현해 보겠다.

이 글이 도움이 됐거나 유익했다면 스크롤을 조금만 더 내려서 댓글을 남겨주세요. (비로그인도 가능합니다!)
응원이나 피드백이 담긴 댓글은 제가 계속 블로그를 해나갈 수 있는 원동력이 됩니다. 😊

지인에게 보여주고 싶은 글이었다면 URL을 복사해서 메신저나 소셜 미디어에 공유해 주세요.
이전 포스트

댓글 쓰기

0 Comments

문의하기 양식