티스토리 뷰

해당 글은 https://blog.naver.com/kbs4674/220989837464 로 부터 게시글이 이전되었습니다.

 

이번 시간에는 과거의 VC만을 활용한 것 과는 다르게 MVC를 활용해서 CRUD를 제작해보겠습니다.

이번 게시판을 제작할 때 부트스트랩과 연계해서 아주 간단하게 만들어 보겠습니다.

 

CRUD는 Create · Read · Update · Destroy 의 줄임말로서, 이를 응용한 예시가 게시판 입니다.

CRUD는 MVC 패턴을 아주 잘 활용한 좋은 예시이면서도 처음에 배움에 있어 많이 혼동이 있고, 어려울 수 있습니다.

다들 맨탈 꽉 잡고 잘 따라오길 빌게요!

 


 실습 유의사항 

  • 해당 글은 Rails 5.2 환경에서 글이 작성됩니다.

  • 나중에 해당 글 따라서 게시판 만들지 마세요! 더 간단한 방법이 있을 뿐 더러 현재 이 방법은 보안에 취약합니다.

 목차 


 
  • 공통 준비 : 디자인 및 MVC 생성

1. IDE를 키신 후, 터미널에 다음명령어를 입력해서 View/Controller을 생성합니다.

rails g controller posts index new create show edit update destroy

 Tip  generate를 g로 줄여서 사용할 수 있습니다.

  • Controller 이름 : Posts

  • 터미널에서 posts 다음으로 쓰는 것은 Controller Action 및 View를 자동으로 생성.

  • index, new, create, … 다양한 이름의 Controller 및 Action을 쓰는 이유는 게시글 삭제/수정/생성 등을 각자 따로 담당하는 액션들이기 때문입니다.

2. Model을 생성합니다.

rails g model Post title content:text
  • title : 게시글 제목이 입력될 컬럼(에트리뷰트), string 형식 (256자 제한)
  • content : 게시글 내용이 입력될 컬럼(에트리뷰트), text 형식 (string 보다 문자를 더 많이 받을 수 있습니다.)

모델을 생성해줬으니, Migrate 해줍니다.

rake db:migrate

 

3. 전체 공통적인 view를 담당하는  app/views/layouts/application.html.erb  파일을 열람해주세요.

 

4. 부트스트랩 사이트(https://getbootstrap.com/)로 이동합니다.

부트스트랩은 버튼, 반응형 디자인 등에 대한 템플릿이라고 보시면 됩니다.

트위터에서 만들어진 오픈소스이며, 상업적으로 이용해도 됩니다.

 

부트스트랩을 이용하면 버튼 등 디자인에 대한 고민을 덜을 수 있다는 장점이 큽니다.

그래서 해커톤 대회같은데에서 보면 부트스트랩을 활용한 작품이 눈에 띄게 보입니다.

 

메인 홈페이지에서  Get Started  버튼을 클릭해주세요.

 

5. 페이지를 이동 후, Quick Start 아래에 보면 CSS 및 javascript 코드가 보일겁니다.

해당 코드들을 Ctrl+C 로 복사 후,  app/views/layouts/application.html.erb  파일의 <head> 태그 내에 붙여넣기를 해주세요.

<%# app/views/layouts/application.html.erb %>
<head>
	...
	<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
	<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
	<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>
	<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>
</head>

 

6.  config  폴더에 있는  routes.rb  에 가서 파일을 열람 후, 일단 처음에 홈페이지 방문 시 보여질 홈페이지를 설정하기 위해 root를 설정합니다.

## config/routes.rb
Rails.application.routes.draw do
	root 'posts#index'
	
	get 'posts/index'
	get 'posts/new'
	get 'posts/create'
	get 'posts/show'
	get 'posts/edit'
	get 'posts/update'
	get 'posts/delete'
end

 참고  get으로 정의된 URI 규칙들은 Controller을 생성하면서 자동적으로 생성된 것 들입니다!

 

7.  app/controllers/posts_controller.rb  파일을 열람 후, index 액션 내 코드를 다음과 같이 작성합니다.

class PostsController < ApplicationController
	def index
		@posts = Post.all
	end
	... (코드 생략) ...
end

이제 index View에서는 @posts 변수를 이용해서 모든 게시글들을 보여줄 것 입니다.

 

8.  app/views/posts  안에 있는  index.html.erb  을 더블클릭해서 편집을 하겠습니다.

 index.html.erb  는 게시판의 '글 목록' 페이지가 될 곳입니다.

 

Bootstrap 사용 디자인

https://getbootstrap.com/docs/4.3/components/buttons/#examples

<%# app/views/posts/index.html.erb %>

<h1 align="center">게시판 리스트</h1><br/>

<!-- 게시글 제목과 내용이 여기에 표출될 것임. -->
<% @posts.each do |t| %>
	제목 : <%= t.title %><br/>
	내용 : <%= t.content %><br/>
	<hr/>
<% end %>

<div style="text-align: right">
	<a href="/posts/new" class="btn btn-primary">글쓰기</a>
</div>

현재 아무런 데이터가 없어서 비어있는 상태입니다.


 개념 설명  each do

1) @posts는 Post 모델(posts 테이블)의 모든 정보를 다 가지고 있습니다.

설명을 위해 아래 사진과 같은 정보를 가지고 있다고 가정해보겠습니다.

2) @posts 변수를 each do를 통해 반복순회를 합니다.

* 반복문과 비슷한 개념으로 이해해도 되나, 그렇다고 반복문은 아닙니다.

 

3) row(줄) 하나하나씩 성질을 t 라는 상속변수가 물려받습니다.

 

4) 현재 Posts 데이터는 총 2개를 소유하고 있으니 2번의 반복이 이루어집니다.

 

5) 첫 번째로 id=1 에 대한 순회를 시작합니다.

<%= t.title %> 에는 1번 id값에 대한 Title을,

<%= t.content %> 에는 1번 id값에 대한 Content을 보여줍니다.

 

6) id=1 에 대한 순회가 종료가 되고 id=2 역시 똑같은 과정을 밟습니다.

 

7) .. 이를 마지막 데이터에 다다를 때 까지 반복을 합니다. (그리고 마지막 데이터를 순회 후 종료)


* 여기서 저희는 부트스트랩 디자인을 쓰긴 했지만 이에 대한 자세한 언급은 다음 설명 때 하겠습니다.

 

 

 
  • CREATE

1. 게시글 작성 뷰를 보여주는  app/views/posts  안에 있는  new.html.erb  을 구현해보겠습니다!

 app/views/posts/new.html.erb  파일을 열람해주세요!

 

여기서! 저희는 input 및 글쓰기 버튼을 부트스트랩 디자인을 입혀서 평범하지 않게 만들어 볼겁니다.

 

Bootstrap 사용 디자인

https://getbootstrap.com/docs/4.3/components/forms/#sizing

https://getbootstrap.com/docs/4.3/components/forms/#form-controls

https://getbootstrap.com/docs/4.3/components/buttons/#examples

<%# app/views/posts/new.html.erb %>

<!-- 단순한 제목 (align 태그를 통한 제목 가운데 정렬) -->
<h1 align="center">자유게시판</h1><br/>

<!-- container 선택자는 Bootstrap에서 제공하는 class 선택자로서, 해당 div 내의 내용들이 가운데 정렬이 되게 합니다. -->
<div class="container">

	<!-- 게시판 영역 내 Form -->
	<form action="/posts/create" method="POST">
		<%= hidden_field_tag :authenticity_token, form_authenticity_token %>
		<div>
			<div>제목</div>
			<input name="post_title" type="text" class="form-control" placeholder="제목"> <!-- placeholder이 아무 글을 적지 않은 input란에 미리 내용을 작성함으로서 안내메세지 효과를 줌. -->
			<small>미풍양속을 해치는 글을 작성 시 제재가 이루어지니 주의바랍니다.</small> 
		</div>

		<div class="form-group">
			<div>내용</div>
			<textarea name="post_content" class="form-control" rows="3"></textarea>
		</div>

		<button type="submit" class="btn btn-primary">글쓰기</button>
	</form>
	
</div>

좌 : 부트스트랩 활용한 디자인 / 우 : 부트스트랩 활용을 안한 디자인

부트스트랩을 활용하니까 깔끔해 보이죠?

그리고 부트스트랩 디자인을 적용하는 방법은 그냥 태그 내 class 선택자에 부트스트랩에서 사전에 정의한 class 선택자 이름을 쓰면 됩니다!

(form-control, containber, btn btn-primary 이름들이 부트스트랩에서 정의한 class 선택자 이름입니다!)


코드리뷰

<form action="/posts/create" method="POST">
	...
</form>

form 태그 내에 있는 <input> 태그에 작성된 내용들을  글쓰기  버튼을 클릭 시, 해당 내용들이 action에서 지정한 위치로 전달이 됩니다. 덧붙여서 POST 방식으로 내용이 전달되므로 내용들은 URL에 노출되지 않습니다.

 

<%= hidden_field_tag :authenticity_token, form_authenticity_token %>

레일즈 문법으로서, CSRF(요청 위조) 취약점을 방지하고자 토큰값(난수)이 생성이 됩니다.

해당 토큰을 받는 액션에서는 액션에서 가지고 있는 토큰과 new.html.erb로부터 건너온 토큰과 값을 비교해서 위변조 체크를 합니다.

레일즈에서는 Get 방식을 제외한 Method로 데이터를 전송할 땐 반드시 CSRF 방지토큰도 함께 전송이 되어야 합니다.

 

 참고  다른 유사글에서 보면  app/controllers/application_controller.rb  파일에

protect_from_forgery with: :exception

위 코드를 추가하라는 설명이 덧붙여져 있습니다.

위 코드는 CSRF 토큰 없이도 Post 등 메소드 처리에 대해 잘 동작이 이루어지게 하라는 옵션입니다.

 

하지만 위 코드는 Rails 5.2 버전 이후로는 더이상 지원을 안하는 코드이다 보니 해당 설명에서는 이 과정을 생략했습니다.


2. 데이터를 건네받았으면 데이터가 DB에 쓰여져야 겠죠?

미리 Controller에서 작업을 잠깐 해볼게요.

 

new에서 전달되는 데이터는 create에서 받을테니,

create 액션에서 데이터를 건네받고, DB가 쓰여질 수 있도록 다음 코드를 작성해보겠습니다.

class PostsController < ApplicationController
	def create
		Post.create(title: params[:post_title], content: params[:post_content])
	end
	... (코드 생략) ...
end

 참고 

  • params는 parameters의 줄임말입니다. 이 전 뷰로부터 건너온 객체들 중, 특정 객체에 대한 요청을 받을 때 쓰입니다.
  • params[:post_title] 에서 post_title은 input 태그 내 name에 정의된 이름입니다.
  • create에서는 new로부터 다음 구성으로 parameter 객체가 넘어오는게 확인이 됩니다.

create 가 건네받은 Parameters

 

3. 10번까지 했으면 잠깐 한번 글쓰기를 해보세요!

하지만 위와같이 빨간 에러를 경험하게 됩니다 :(

그 이유는  config/routes.rb  에서 URI 정의를 안내렸기 때문입니다.

 

잠깐 에러창은 건들지 말고

 config/routes.rb  파일을 열람 후, URI Method를 재정의 합니다.

## config/routes.rb
Rails.application.routes.draw do
	... (내용 생략) ...
	post 'posts/create'
    ... (내용 생략) ...
end

 

그리고 다시 냅뒀던 에러페이지를 새로고침 해보세요!

뭔가 성공..은 한 것 같은데  create.html.erb  페이지로 왔네요.

사실 이 페이지는 필요가 없어요. Controller 내 create 액션에 대한 결과는 화면으로 안보여줘도 되기 때문이니까요.

 

Controller 내 create 액션을 redirect_to 코드를 추가해서 다음과 같이 수정해주세요.

class PostsController < ApplicationController
	def create
		Post.create(title: params[:post_title], content: params[:post_content])
		redirect_to "/"
	end
	... (코드 생략) ...
end

 

그리고 다시  http://.../posts/new  페이지로 가서 글을 다시 써보세요!

글을 쓰고 위와같이 메인으로 이동하면 성공입니다!

 

 

 
  • READ

1. 게시글 열람을 한번 구현해볼게요!

게시판 목록을 의미하는  app/views/posts/index.html.erb  파일을 열람 후, 코드를 다음과 같이 수정해주세요.

<%# app/views/posts/index.html.erb %>

<h1 align="center">게시판 리스트</h1><br/>

<!-- 게시글 제목과 내용이 여기에 표출될 것임. -->
<% @posts.each do |t| %>
	제목 : <%= t.title %><br/>
	내용 : <%= t.content %><br/>
	<a href="/posts/show/<%= t.id %>">열람</a>
	<hr/>
<% end %>

<div style="text-align: right">
	<a href="/posts/new" class="btn btn-primary">글쓰기</a>
</div>

 

2. 잠깐 코딩을 멈추고, 한번 홈페이지로 돌아가서 가서  열람  버튼을 클릭해보세요!

아, 또 오류네요!

 routes.rb  URI 규칙 설정 해야하죠!

 

 config/routes.rb  파일로 이동 후, URI 규칙을 수정할건데 이번엔 과거와는 다르게도 ID값이 있어야 하는 상황이에요!

get 'posts/show/:id'

위의 답이 정답..일까요?

아니에요! URI에서 뒤에 인자가 붙을 경우 단순히 위의 정의로는 에러를 겪게 됩니다.

이런 상황에서는 해당 페이지에 접근 후, 작업이 연동될 controller 및 액션까지 가르쳐줘야 합니다!

 

get 'posts/show/:id' => "posts#show"

위와같이 코드를 수정해주세요!

 

3. 다시  열람  버튼을 클릭하면 이제는 무사히 show 페이지에 id값과 함께 넘어온게 확인됩니다!

4. show 페이지에 가게되면 View가 작동되기 전에 앞서 뭔가 작업의 Base가 있어야 겠죠?

Controller을 열람 후, show 액션을 다음과 같이 수정해주세요!

class PostsController < ApplicationController
	def show
		@post = Post.find(params[:id])
	end
	... (코드 생략) ...
end

 

5. 이어서 Show View 역시 다음과 같이 코드를 수정해주면 됩니다!

<%# app/views/posts/show.html.erb %>

<h1>게시글 내용</h1>
 
제목 : <%= @post.title %><br/>
내용 : <%= @post.content %><br/><br/>
<div><a href="/posts/index">목록</a></div>

 

6. 이제 show 페이지가 잘 보이는게 확인이 됩니다!

 

 

 
  • Update

1. 여기까지 오느라 고생하셨어요! 이제 좀 과정이 쉬워질거에요!

 

2. 이제 게시판 수정 페이지를 구현해볼게요!

 app/views/new.html.erb  파일의 전체 내용을 복사(Ctrl+C) 후,  app/views/edit.html.erb  파일에 붙여넣기(Ctrl+V) 해주세요!

 

3. 코드를 조금 수정할거에요!

1) form 태그 내 action을 다음과 같이 바꿔주세요!

<form action="/posts/update/<%= @post.id %>" method="POST">

 

2) input 및 textarea 태그를 다음과 같이 추가해주세요!

과거에 작성되었던 내용이 input Form 안에 자동으로 담겨질 거에요!

<input name="post_title" type="text" class="form-control" value="<%= @post.title %>">
<textarea name="post_content" class="form-control" rows="3"><%= @post.content %></textarea>

 참고  value 속성은 input태그 안에 사전에 내용을 담아넣는 속성 입니다.

 

4. Controller 역시 수정해보겠습니다!

class PostsController < ApplicationController
	def edit
		@post = Post.find(params[:id])
	end
    
	def update
		@post = Post.find(params[:id])
		@post.update(title: params[:post_title], content: params[:post_content])
        
		redirect_to "/"
	end
	... (코드 생략) ...
end

 

5.  app/views/posts/index.html  파일을 열람 후, 코드를 조금 수정할거에요!

수정하기 버튼을 추가해보겠습니다.

<%# app/views/posts/index.html.erb %>

<h1 align="center">게시판 리스트</h1><br/>

<!-- 게시글 제목과 내용이 여기에 표출될 것임. -->
<% @posts.each do |t| %>
	제목 : <%= t.title %><br/>
	내용 : <%= t.content %><br/>
	<a href="/posts/show/<%= t.id %>">열람</a> / <a href="/posts/edit/<%= t.id %>">수정</a>
	<hr/>
<% end %>

<div style="text-align: right">
	<a href="/posts/new" class="btn btn-primary">글쓰기</a>
</div>

 

6. 이제 잠깐 코드에서 손 떼시고, 메인 홈페이지로 가서  수정  버튼을 클릭해보세요!

아, 맞다! 저희  routes.rb  URI 규칙 설정 해야하죠!

 config/routes.rb  파일로 이동 후, show 코드를 스리슬쩍 배껴서 다음과 같이 수정해주세요.

## config/routes.rb
Rails.application.routes.draw do
	... (내용 생략) ...
	get 'posts/edit/:id' => "posts#edit"
	post 'posts/update/:id' => "posts#update"
end

더불어 코드 수정하는 김에 update에 대한 코드도 함께 수정할게요!

왜 update를 위와같이 수정하는지 이해가 안가면 Create 부터 다시 공부해야 합니다!

 

7. 이제 직접 홈페이지에서 게시글을 수정해보세요!

아주 잘 될거에요~!

 

 

 
  • Destroy

게시글 삭제는 진짜 여태 한것 들 중에서 가장 쉬워요!!

특정 ID값의 데이터를 가리키고, 삭제시키고 끝!

 

1.  app/views/posts/index.html  파일을 열람 후, 삭제 링크를 추가해볼게요!

<%# app/views/posts/index.html.erb %>

<h1 align="center">게시판 리스트</h1><br/>

<!-- 게시글 제목과 내용이 여기에 표출될 것임. -->
<% @posts.each do |t| %>
	제목 : <%= t.title %><br/>
	내용 : <%= t.content %><br/>
	<a href="/posts/show/<%= t.id %>">열람</a> / <a href="/posts/edit/<%= t.id %>">수정</a> / <a href="/posts/destroy/<%= t.id %>">삭제</a>
	<hr/>
<% end %>

<div style="text-align: right">
	<a href="/posts/new" class="btn btn-primary">글쓰기</a>
</div>

 

2. Controller로 돌아가서 destroy 액션을 다음과 같이 수정해보겠습니다.

class PostsController < ApplicationController    
	... (코드 생략) ...
	def destroy
		@post = Post.find(params[:id])
		@post.destroy
        
		redirect_to "/"
	end	
end

 

3. 마지막으로 라우터 URI 규칙을 정의해주세요!

## config/routes.rb
Rails.application.routes.draw do
	... (내용 생략) ...
	get 'posts/destroy/:id' => "posts#destroy"
end

 

4. 끝입니다! 홈페이지에서 게시글을 삭제해보세요!

 

 

  • 해당 예제를 그대로 게시판을 만들지 마세요.

해당 예제는 보안이슈가 있습니다.

바로 삭제(Destroy) 부분인데요, 삭제는 현재 Get 방식으로 이루어져 있다보니

단순히 URL 접속만으로 게시글을 삭제할 수 있는 문제가 있습니다.

 

그리고 지금은 노가다로 CRUD를 만들고 있지만, 레일즈에서는 단 1줄의 터미널 명령어 만으로 CRUD를 만들 수 있는 기능을 제공합니다!

 

 

  • 헐?

CRUD 1초컷 제작

rails g scaffold post title content:text

 Scaffold 개념 살펴보기 [클릭]

 

루비온 레일즈 Ruby on Rails ROR

댓글
댓글쓰기 폼
공지사항
Total
168,727
Today
25
Yesterday
264
링크
«   2022/01   »
            1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31          
글 보관함