생각을 개발하자, 박진형

[rails] 레일즈 기본편 - 모델 본문

Likelion/rails

[rails] 레일즈 기본편 - 모델

imjinbro imjinbro 2017.02.04 14:53


[레일즈 모델]


- 도서관 예시 
우리가 도서 대여/반납 서비스를 이용하기위해 도서관을 간다. 도서관에 들어가 도서 대여/반납대로 간다. 우리에게 도서 대여/반납대는 V(뷰)에 해당한다. 여기 도서관은 빌리고 싶은 도서를 예약해놓고 도서관을 찾아가서 사서에게 요청을 하면 사서가 책들이 꽂힌 책장에서 책을 찾아와 책을 대여해주는 방식이다. 그래서 사서에게 우리가 예약한 도서를 대여해달라고 요청을 한다. 사서는 요청을 받고 책장으로 찾아가 예약된 책을 찾고 다시 돌아와 우리에게 책을 건네준다. 여기서 사서는 C(컨트롤러)역할을 하고, 책들이 꽂힌 책장은 데이터베이스(DB)이다. M(모델)은 데이터베이스 관계도를 짜는 곳으로서, 이 책은 몇번 책장, 몇번째 줄 몇번째에 꽂혀있는지 정보를 기술하는 곳이다. 엄밀히 말하면 데이터베이스를 쉽게 관리하기위해 필요한 개념이 M(모델)이다.


- 모델의 특징
1) SQL문이라는 데이터베이스 속에서 특정 자료를 찾거나, 자료를 등록하거나, 수정하거나, 삭제하거나 하는 동작들을 실행하는 명령어 없이 쉬운 명령어를 통해서 실행할 수 있다.

2) 1번과 마찬가지인 설명인데, 데이터베이스를 클래스처럼 만들어서(M 모델) 객체화하여 사용할 수 있음 => Active Record(O/R맵퍼, 객체/관계 매핑 모듈)
도서관 예시에서 보자면 책 정보가 모두 들어가있는 데이터베이스가 있다. 데이터베이스에서 검색, 생성, 수정, 삭제 등의 명령을 하려면 어려운 SQL 명령어를 사용해야하는데, 레일즈는 SQL 명령어: 쿼리문 대신 객체처럼 데이터베이스명.메소드 형태로 사용할 수 있다는 이야기다.

3) 데이터베이스 환경설정은 config > database.yml에 있다. yml파일은 구조화된 데이터를 작성하기위한 확장자라고한다. 파일에 들어가보면 development, test, production 각각 세개의 환경설정 공간이 나오는데, 개발환경/테스트환경/배포환경 순으로 기술되어있다. 각각의 환경에 맞게 데이터베이스 설정(사용 데이터베이스 종류, 접속데이터베이스 이름, 접속 주소 IP, 포트번호, 접속 타임아웃시간, 사용자 이름, 비밀번호 등)을 할 수 있음
=> 각각 따로 설정해야하는 이유가 개발과 테스트 그리고 배포는 같이 할 수 없기 때문이다. 각각 따로 데이터베이스를 둬야…… 불상사가 생기는걸 막을 수 있지 않을까?


- 모델 역할
    모델은 데이터베이스에 접근하기 위한 클래스다. 도서관 예시를 다시 들어보자면 사서가 학생이 예약한 책을 찾기위해 그 책이 꽂힌 책장으로 가야한다. 무작정 가야하나? 효율적인 처리방법이 아닐 것이다. 도서관 책장에 가보면 분류가 다되어져있다. 이러한 분류를 보고 사서가 책을 찾기위해 특정 책장으로 갈 것이다. 레일즈의 모델이 아니라면 책장의 분류가 이해하기 어렵고 복잡해보이는 말로 되어있을 것이지만, 레일즈의 모델 클래스 덕분에 우리나라 말로 쉽게 표현된 분류를 보고 사서가 쉽게 책을 찾을 수 있다.


- 모델 만들기(모델을 만들면 데이터베이스 테이블을 만들 수 있는 파일이 만들어짐)
1) rails g model 모델이름(데이터베이스이름) db에저장될이름1:db에저장될데이터타입1 db에저장될이름2:db에저장될데이터타입2, …….


=> db에 저장될 데이터 타입으로는 string, text, integer 등이 있음, 어떤 데이터를 저장할 것인지 구성하고  맞는 데이터타입을 지정하면됨
=> 도서관 예시에 대입해보면 책 정보를 저장하는 데이터베이스를 만들 것이다. 데이터베이스를 직접 설계하지않아도 모델 클래스를 만들면(정해진 구조에 맞춰 db에 저장될 데이터 입력하면됨) 데이터베이스가 알아서 설계된다
책 데이터베이스에 들어갈 정보(간단히) : 책 분류, 책 이름 => book_category:string book_name:string 으로 정의하면 된다. 책이 데이터베이스에 쌓이면 번호는 자동으로 부여되기때문에 따로 지정하지않아도된다.

2) 1번을 통해 레일즈 웹어플리케이션 구조 아래 폴더들에 파일들이 생겼을 것이다. 자세한 것은 다음 메뉴에서 알아보기로하고 여기서 짚어야할 점은 db > migrate 폴더 아래에 숫자_create_모델이름(1번에서 지정한이름).rb 파일이 있을 것이다. 


그 파일의 명칭은 마이그레이션 파일이라고 하는데, 마이그레이션 파일은 데이터베이스를 만들기 전 데이터베이스를 만들 때 필요한 정보와 구조(table 이라고 한다)를 담는 곳이다. rails g model 명령어를 통해서 데이터베이스가 만들어진다고 설명했지만 아직까지 100% 만들어진 것이 아니라 마이그레이션 파일이라는 데이터베이스 설계도가 만들어졌고 레일즈의 또다른 명령어를 통해서 마이그레이션 파일에 대한 확정을 지어주면 그때 데이터베이스가 생성된다.

3) 마이그레이션 파일을 확정짓기위한 레일즈 명령어 실행 : rake db:migrate



마이그레이션 결과) schema.rb(데이터베이스 테이블 정보를 담은 파일) 생성

=> rake 명령어는 레일즈 내에서 실행되는 build프로그램으로 구조 이외에 필요한 환경작업에 쓰여지는 것으로 파악됨
=> 중간에 마이그레이션 파일(db 설계파일)이 변경될 경우 다시 rake db:migrate를 해줘야하며, rake db:drop을 통해 데이터베이스를 날려버릴 수도 있음

결론) rails g model 모델이름(데이터베이스이름) -> 마이그레이션 파일 확인 및 수정(추가적으로 저장되어야할 정보가 있다면) -> 레일즈 명령어를 통해 마이그레이트(데이터베이스를 만들어주세요)를 명령하면 데이터베이스 생성


- 모델 구조알기
1) models > 모델이름.rb : 해당 모델과 관련한 내용들을 기입한다, 내용들이라하면 어떤 정보가 데이터베이스 테이블에 입력되기 전 조건(유효성 검사 : 빈 데이터는 안되고, 어떤 조건의 데이터는 안되고) 그리고 모델과 모델(데이터베이스 테이블과 테이블) 간의 관계도 설정이 기입되는 것이다. 관계도 설정 내용은 추후 배울 것이다. 잠깐 예를 들어보자면 페이스북의 타임라인에 있는 어떤 글 하나와 글에 달려있는 댓글과의 관계이다. 페이스북이라는 웹어플리케이션이 있다. 그 안을 들여다보면 페이스북 타임라인에 쓰여진 글을 저장하는 데이터베이스, 모델이 있고, 댓글 내용을 저장하는 데이터베이스, 모델이 있다. 1개의 글에 여러가지 댓글이 있을 것이다. 이 댓글들은 꼭 저기 1개의 글에 대한 댓글이여야한다. 이때의 관계를 해당 파일에 기입하는 것이다. 또한 해당 모델이름.rb 파일은 루비에서 배웠듯이 클래스파일이다. 이 클래스파일은 ActiveRecord::Base 라는 파일을 상속받는 자식클래스이다. ActiveRecord::Base는 데이터베이스 접근을 위한 기본적인 기능을 제공하는 클래스로서, 상속받는 모델.rb 클래스는 모델 클래스의 객체를 이용하여 데이터베이스 테이블에 접근하고 데이터를 가져올 수 있다. 

2) db > .. : db 폴더 하위에 있는 파일 혹은 폴더들은 데이터베이스 테이블과 관련된 파일, 폴더들이다. migrate 폴더는 데이터베이스 테이블을 만들어내기 전 구조를 짜는 파일(마이그레이션 파일)이 들어있는 폴더이고, schema.rb는 마이그레이션 파일을 통해 데이터베이스 테이블로 만들어진 테이블 구조가 기술되어진 파일(해당 웹어플리케이션에서 작동되는 테이블의 정보가 모두 있음)이다. 


- 모델 사용 이외 데이터베이스에 직접 접근하기
1) rails dbconsole 을 이용하면 데이터베이스 클라이언트에 직접 실행할 수 있다. 데이터베이스 클라이언트란 레일즈 웹어플리케이션에서 쓰기로 정한 데이터베이스를 말한다(config > database.yml 내용, 위에 기술되어있음)

2) .tables => 테이블(예를 들어 책 정보를 모아놓은 책 모델 - 데이터베이스) 목록 표시
   .schema books => 책 정보를 모아놓은 데이터베이스 테이블 구조확인 (어떤 정보들이 저장되고 어떤 순서로 저장되는지 알 수 있음), schema(스키마)는 데이터베이스 테이블 구조를 뜻한다.
   .SELECT * FROM books => books 테이블 내용 확인(책 정보가 몇개 등록되어있으면 순서대로 저장된 내용들이 출력됨)
   .quit => 데이터베이스 접근 해제


- 모델 그리고 레일즈 컨트롤러, 뷰 특징을 활용하여 데이터베이스 테이블 데이터뽑기(도서관홈페이지 예를 들어)
1) rails g controller librarian list 
=> 도서관홈페이지에 사서 기능을 넣을 것이다. 사서가 할 수 있는 액션(def list)은 도서 목록을 학생들이 요청하면 도서 목록을 페이지에 표시해주는 것이다.
=> controller, controller 액션, config > routes.rb 한번에 생성되었다.

2) rails g model book category:string title:string 
=> 도서관 책들을 데이터베이스에 저장하기위해 book 이라는 model을 만들었다. 그리고 자동으로 데이터베이스 테이블을 만들기위한 전 단계 파일인 migrate 파일도 생성되었다
=> db > 숫자_create_books.rb 파일을 확인하고 생성하려는 데이터베이스 테이블의 구조가 맞으면(확정되면) rake db:migrate를 사용해서 데이터베이스 테이블을 생성한다.

3) 1, 2번 단계를 통해 학생들이 도서관 홈페이지에 들어와서 사서가 할 수 있는 액션 중 도서 목록을 조회하는 페이지까지 접근이 가능하다. 하지만 아직까지는 사서가 데이터베이스에 접근하여 도서 목록을 받아온 후 학생들이 보는 페이지에 뿌려주는 작업까지는 하지 않았다. 이후 단계부터 해당 작업들을 할 것이다.
4) controller 액션(도서목록을 조회할 def action)이 담긴 controller(controllers > librarian_controller.rb)를 켠다. def list 코드를 수정한다. 
=> 학생들이 list라는 액션을 실행시키면(list 액션이 라우팅된 페이지에 접근하면) librarian_controller 내의 def list가 동작을 한다.
=> 학생들이 페이지를 접근하는 이유는 도서관에 있는 도서목록을 조회하기위해서이다.
=> 도서목록을 학생들에게 보여주려면 list에서 데이터베이스의 책 목록이 저장된 테이블에 접근하여 목록을 다 받아와야한다.
=> book 테이블에 접근을 하자 : 레일즈는 복잡한 SQL 명령어(쿼리문)을 날리지 않고 모델 클래스를 통해 데이터베이스에 접근가능하다, 모델 클래스를 객체화시켜 데이터베이스 테이블에 접근해서 테이블 데이터를 받아오는 메서드를 써서 데이터를 받아온 후 변수(기억나지 않는다면 레일즈 뷰에서 @이름에 등록하는 과정을 다시보자)에 저장하고 뷰에 등록하면 된다.
=> 모델 객체를 통해 book 데이터베이스 테이블 접근하고 모든 데이터 목록 받아오기 : book.all (말은 복잡한 것 같은데 굉장히 쉽다. 직관적이다. book이라는 모델클래스가 생성될 때 데이터베이스 이름도 똑같이 설계된다)
5) def list 액션 메서드에서 모델 객체를 통한 book 데이터베이스 테이블 접근하여 데이터를 얻어왔다. 이를 @이름 즉, 템플릿변수에 저장해두었다. 템플릿변수에 저장해두었다는 것은 뷰 파일(.erb)에서 사용할 수 있다는 뜻이다.
6) 보통 routes.rb 파일을 건드리지 않았으면 def list 액션메서드의 이름과 뷰 파일(.erb) 이름은 같다. 찾아서 수정하자
=> 템플릿변수(@이름)을 뷰 파일에 표시하자 : 왜? 학생들은 도서목록 조회를 눌렀고 그에 대한 결과를 이제 표시해주는 것이다.
=> 템플릿변수를 뷰 파일에 표시할 때에는 레일즈의 약속된 코드가 필요하다( <% %> 혹은 <%= %>)
=> 도서목록은 한 개의 데이터가 아니다. 한 묶음의 데이터이다. 도서 목록이기 때문에 데이터 한 개가 조회되더라도 결국 한 묶음의 단위로 나온다. 즉, 루비 코드 배움 단계에서 배운 배열 형태이다.
=> 하나의 데이터였더라면 <%= @템플릿변수이름 %> 을 통해서 그대로 표시 시켜도 됐을 것이나 안타깝게도 배열(도서 목록이라는 한 묶음의 데이터)이다. 
=> 도서 목록 조회 페이지에 조회한 도서목록을 모두 펼쳐서 보여줄 것이기때문에 배열을 하나씩 꺼내는 작업이 필요하다. 이때 필요한 개념이 루비에서의 반복문이다. (이래서 루비 기초 공부가 필요하다)
=> 그렇다면 약속된 레일즈 코드 중 <% %> 를 사용한다. <% %> 의미는 뷰 파일에서 어떠한 연산 처리를 하겠다는 것이다. 도서 목록 페이지에서는 배열에 들어있는 요소들을 하나씩 빼는 작업이 연산 처리이다.
=> 한가지 팁이 있다면, .erb 파일에 들어가는 루비 코드는 모두 <% %> 혹은 <%= %> 처리가 되어야한다. 뷰에 직접적으로 표시되는 값들은 <%= %> 처리를 해주고, 그외 나머지 것들은 <% %>를 처리한다.
             어렵지않다. 코드는 그대로 옮기는데 코드 한 줄 한 줄 마다 저 약속된 코드를 함께 써줘야하는 것이다.
7) 배열 요소를 하나씩 꺼냈다면 끝이다. 원하는 사서의 기능 중 도서 목록 조회 기능을 하는 페이지를 만들어냈다.
결론) MVC 그리고 데이터베이스는 따로따로 저장되지만 결국 유기적으로 동작한다. 모든 웹어플리케이션이 그렇다. MVC 패턴을 사용해 코드를 분리함으로서 쉽게 편집하고 코드가 깔끔해졌다는 점은 꼭 기억하자.


- 참고자료

    1) 액티브레코드 : https://goo.gl/x7eTkH