티스토리 뷰

프로그래밍 공부/TIL : Rails Tutorial

Chapter 1 : Getting Started with Rails

마음 따뜻한 개발자, 나른한 하루 2020. 6. 23. 18:00
이 글은 Rails 5.0 Guide 기준으로 작성됩니다.
https://guides.rubyonrails.org/v5.0/getting_started.html

해당 카테고리에서는 오늘의 이 글을 시작으로 rails guide에 있는 내용을 최대한 활용하여 글을 써나갈 예정입니다.

 

 

  • Ruby on Rails의 철학

Ruby on Rails는 빠른 개발력을 목적으로 개발된 웹프레임 워크로서, 프레임워크의 기반이 되는 언어인 Ruby를 모르더라도 빠르게 학습할 수 있다는 장점이 존재합니다. 언어를 모르더라도 프레임워크를 활용할 수 있다는 빠른 배움의 장점 덕분에 이 글을 쓰는 저 역시 Rails에 입문하기 시작한 것 같습니다.

 

Rails에서는 빠르게 배울 수 있다는 장점도 있지만, 빠르게 구현을 할 수 있다는 장점 또한 존재합니다.

Rails의 빠르고 효율적인 생산성을 지탱하는 2개의 철학을 가지고 있는데 이 두 개의 철학에 대해 한번 살펴보겠습니다.

 

1. Don't Repeat Your Self (DRY)

DRY는 말그대로 '코드를 반복적으로 쓰지 마라' 라는 일환으로서 코드의 재사용을 강조합니다.

아래 CRUD를 구현해내는 코드로 예를 들어서 DRY에 대해 설명을 해보겠습니다.

## app/controllers/bulletins_controller.rb

class BulletinsController < ApplicationController
  before_action :bulletin_params, :only => [:update]
  before_action :find_bulletin_id, :only => [:show, :edit, :update, :destroy]


  ... (Controller 내 일부 Action 생략) ...

  def show
    @bulletin = Bulletin.find(params[:id])
  end

  def edit
    @bulletin = Bulletin.find(params[:id])
  end

  def update
    data = Bulletin.find(@bulletinId)
    data.update(bulletin_params)
    redirect_to bulletin_path(@bulletinId)
  end

  def destroy
    data = Bulletin.find(@bulletinId)
    data.destroy
    redirect_to bulletins_path
  end

  private
  def bulletin_params
    params.require(:bulletin).permit(:title, :content)
  end

  def find_bulletin_id
    @bulletinId = params[:id]
  end
end

 

위 코드를 보면 다음 코드가 주기적으로 쓰이는게 확인이 됩니다 :

## bulletins#show, bulletins#edit, bulletins#update, bulletins#destroy

Bulletin.find(params[:id])

find 메소드 같은 경우는 테이블에서 특정 ID값의 데이터를 찾아내는 메소드인데,  똑같은 역할을 하는 메소드가 반복적으로 쓰인다는 것이 일단 DRY 철학의 위반  이라고 볼 수 있습니다.

 

그래서 위 코드를 DRY 철학을 지켜내어 코딩을 하면 아래와 같은 결과로 볼 수 있습니다. (Controller 및 Model)

## app/controllers/bulletins_controller.rb

class BulletinsController < ApplicationController
  before_action :bulletin_params, :only => [:update]
  before_action :find_bulletin_id, :only => [:show, :edit, :update, :destroy]

  ... (Controller 내 일부 Action 생략) ...

  def index
    @bulletins = Bulletin.first(10)
  end

  def new
    @bulletin = Bulletin.new
  end

  def show
    @bulletin = Bulletin.find_bulletin(@bulletinId)
  end

  def edit
    @bulletin = Bulletin.find_bulletin(@bulletinId)
  end

  def update
    data = Bulletin.find_bulletin(@bulletinId)
    data.update(bulletin_params)
    redirect_to bulletin_path(@bulletinId)
  end

  def destroy
    data = Bulletin.find_bulletin(@bulletinId)
    data.destroy
    redirect_to bulletins_path
  end

  private
  def bulletin_params
    params.require(:bulletin).permit(:title, :content)
  end

  def find_bulletin_id
    @bulletinId = params[:id]
  end
end
## app/models/bulletin.rb

class Bulletin < ApplicationRecord
  scope :find_bulletin, -> (bulletinId) { find(bulletinId) }
end

 참고1   app/models/bulletin.rb  코드에서 bulletinId 변수는 Controller로 부터 전달된 코드입니다.

 참고2  scope 문법은 위에 보시다싶이 뭔가 여러 코드에 있어 메소드(where, find_by 등)가 반복적으로 사용될 때, 하나로 모아주는 역할로서 쓰입니다. scope 문법에 대한 더욱 자세한 사항은 부록을 참고해주세요.

 부록  Active Record Query : Scope

 

2. Convention Over Configuration (COC)

COC는 '설정보단 규약' 이란 조건으로서, 최대한 Rails에서 정해진 규칙을 활용하는 것을 의미합니다.

 

가장 대표적인 예시로, MVC의 패턴에 있어 Model과 Controller의 이름을 정의함에 있어 다음 규칙이 (암묵적으로) Rails 내 지켜지고 있습니다 :

만일 bulletin이라는 이름의 Controller와 Model 명칭을 정한다면

 

1) Controller : bulletins_controller.rb

2) Model : bulletin.rb

 

위와같이 지어주면 됩니다.

 

위 예시를 지켜서 이름을 명칭 시, Controller에서는 알아서 class와 매칭이 이루어지고, model에서는 테이블과 매칭이 이루어집니다.

* 실제로 나중에 가면 알겠지만, Rails Project 환경에서 특별한 경우가 아니라면 Model 이름만을 가지고 알아서 테이블 이름을 찾아냅니다.

 

 

  • Ruby on Rails 시작 과정

Ruby on Rails 시작에 대해 들여다 보겠습니다.

일단 Rails를 시작하기 전에 앞서, Ruby를 설치해야 할 필요가 있습니다.

 

Ruby 설치에 있어선, 개인적으로는 루비의 다양한 버전을 관리해주는 rbenv 혹은 rvm 을 통해 설치할 것을 권유드립니다.

 rbenv 설명 및 설치법 가이드  Rails 초레가

* 개인적으로는 rvm보단, rbenv를 추천드립니다. 나중에 가면 ruby에서는 Gem이라고 불리는 라이브러리 version에 대한 dependency를 관리해야 할 일이 생기는데, rbenv는 dependency를 책임지는 라이브러리가 비생성 되다보니 이 덕분에 라이브러리 dependency도 함께 설치되는 rvm에 비해 가볍다는 장점이 있습니다. (어차피 후에 Rails에서 라이브러리를 관리하는 매니징이 따로 설치됩니다.; Bundler)

 rbenv VS rvm  Why choose rbenv over RVM?

 

1. 일단 Ruby가 깔려있는지 확인합니다.

ruby -v
# ruby 2.3.1p112 (2016-04-26 revision 54768) [x86_64-darwin19]

위와같이 루비 버전을 관리해주는 패키지 디렉토리 내에 ruby가 설치되어 있으면 됩니다.

 

2. Ruby가 있는 상태에서 Rails Gem을 설치해 보겠습니다.

# gem install rails --version=[version]
gem install rails --version=5.0.7.2

 참고  rails 설치에 있어 ruby와의 dependency 관계에 맞게 설치하세요.

뭔가 긴 설치과정을 보여드리고 싶었는데, 저는 이전에 이미 Rails Gem을 설치함으로 인해 이후에는 이미 설치된 Gem(라이브러리)에 대해선 생략된 채로 설치가 되었습니다. 여기서 알 수 있는 사실 한가지로서, 사실 Ruby on Rails는 Rails 라는 이름의 Gem(라이브러리)에서 파생되는 웹프레임워크라고 보면 됩니다.

 

3. 이제 본격적으로 Ruby on Rails 프레임워크를 생성 및 구경을 해 봅시다.

rails new kcm

 참고1  약에 Rails Gem 버전이 여러개가 깔려있는 상태에서, 특정 버전의 Ruby on Rails 프로젝트를 생성하고 싶을 경우, 다음과 같이 진행하면 됩니다.

# rails _[버전]_ new [프로젝트 이름] 
rails _5.2.3_ new kcm

 

 참고2  Database

Ruby on Rails에는 Gem 설치도중 기본적으로 SQLite3가 설치되고, Rails 프로젝트 초기 생성 때에는 별다른 Database adapter을 지정해주지 않을 시에는 SQLite3 가 설치 및 database adapter로서 채택이 됩니다.

SQLite3 역시 일반적인 RDB(RelationRelational Database)과 같이 SQL문을 사용할 수 있습니다. 하지만 실서비스에 널리 쓰이는 PostgreSQL, MySQL, Maria DB 등에 비해 기능이 부족한 감이 있다보니, SQLite3는 연습용으로만 쓰이는 것을 추천합니다.

 부록  SQLite를 사용해야 하는 이유

 

만약 SQLite3 말고 내가 원하는 DB를 활용해서 Ruby on Rails 프로젝트에서 쓰고싶다면, 다음 명령어를 통해 Rails 설치 및 Database Adapter을 선택해주세요 :

# rails new [프로젝트명] --database=[database adapter]
rails new kcm --database=postgresql

더불어 Database Adapter에 맞는 서버(ubuntu/linux) 패키지 모듈 및 Gem에 대한 설치도 필요합니다.

 

 참고3  이 외에도 rails의 프로젝트 생성에 있어, 프로젝트 설치 전 특별히 주고싶은 옵션에 대해선 터미널에  rails  명령어를 입력 후 확인해주시면 됩니다.

 

 

  • Rails 프로젝트 내 기본적인 파일구조 분석

Rails에는 다양한 파일들이 존재합니다. 파일에 대해 간단히 살펴보겠습니다.

 

1) app/

기본적으로 model, view, controller가 존재하고, 그 외에도 javascript(coffee script)와 css(scss), 웹소켓, Cron job(Active Job) 등을 구성하는 파일들이 있습니다. 이 부분은 먼 훗날에 알아가 볼 예정입니다.

 

2) bin/

rails에서 (향후) rake, bundle, rails 등 터미널에서 쓰이는 script 명령어 사용에 대해 지원합니다. 사실 대표적으로 서버를 여는데 활용되는 명령어인  rails s  명령어도 실제로는  bin/rails s  라고 쓰이는 것이라고 보면 됩니다.

 

 참고  사실 각각의 Gem 별로 shell에서 쓰이는 명령어 script가 있는데, 표면적으로는 드러나지 않습니다.

하지만 만약 아래 명령어를 입력하면 각각의 라이브러리(Gem)가 지원하는 script가 쓰여진 파일들이 나옵니다.

 부록  bundler docs : bundle binstubs

bundle install --binstubs

shell script에서 쓰이는 명령어들 지원에 대한 파일들 (bin/)

 

3) config/

Ruby on Rails의 전반적인 설정을 책임지는 파일들이 있습니다. 일단 서버가 시작되면 최초적으로  application.rb  파일에 쓰여진 내용이 먼저 시작되고, 그 후로 config에 구성된 파일들이 실행이 됩니다.

config 하위폴더에서 설정할 수 있는 것은 기본적으로 database 설정, i18n 국가설정 및 국가별 보여질 text script 작성, server/database Time Zone, Gem 라이브러리 개별 설정 등이 있습니다.

 참고  Configuring Rails Applications

 

4) config.ru

서버의 실행에 대한 script 내용이 적혀있는 파일입니다.

## Rails의 서버를 public IP로 개통, 포트는 3000번

rails s -b 0.0.0.0 -p 3000

위 명령어의 근본이 되는 파일이라고 보면 됩니다.

서버 및 요청/응답 통신에 있어 Rack 이라는 기술이 들어가는데, 이에 대한 내용은 후에 서술하겠습니다.

 

5) db/

Database의 전반적인 테이블 구조/규칙에 대한 정의, schema 파일, seeds 파일(더미데이터 생성 파일) 등이 들어있습니다.

 

6) Gemfile, Gemfile.lock

 Gemfile  파일에는 공통, 각 Environment 별 설치해야 하는 라이브러리(Gem)에 대해 기록이 되어있고,

 Gemflie.lock  은 Gem이 설치될 때 마다 설치 된 Gem의 버전 별로 Dependency 관계에 대해 정의가 되어있습니다.

 

7) lib/

다른 파일로 부터 require 을 통해 호출될 루비 객체파일(코드)들이 담겨져있는 폴더입니다.

 부록  Loading custom class from lib folder in controller

 

8) log

서버에서 일어나는 모든 상황에 대해(에러, 통신성공, 요청/응답, 홈페이지 접속 시 호출되는 파일/코드 등) 기록이 되며, log4j의 에러 레벨(debug, info, fetal, ...) 규칙을 기반으로 기록이 됩니다.

log파일에서 기록되고 있는 서버 이벤트

log 같은 경우는  config/environments/[환경파일].rb  에서 정의가 됩니다.

 부록  log4j 개념

 

9) public/

정적 데이터 저장, assets 폴더 속에 있은 css/js에 대해 compile 후 담겨질 파일들, robots.txt 등에 대한 storage 목적으로 쓰입니다.

해당 폴더에 담긴 파일에 대한 기본적인 외부 접근은  http://...  부터 시작이 됩니다.

* 다만, 해당 파일에 담겨진 파일들은 캐싱의 영향을 받는다는 점을 유의해야 합니다.

 

10) Rakefile

 lib/tasks  에 담긴 task 파일에 대한 수행, 터미널에서 명령어에 따른 작업 수행을 관리하는 파일입니다.

 참고  What is rake and how it is used in rails?

 

11) README.md

Rails 프로젝트를 github repository에 배포 될 시, Intro로 보여질 화면입니다.

보통 github repository Intro에는 application에 대한 설치법, 작동 process, 내부 파일 구조 등에 대한 설명이 담겨져 있습니다.

 

12) test/

단위 테스트 시 필요한 테스트 코드를 담아두는 폴더로서, 해당 폴더 안의 테스트파일은 model, controller, Active Job 등을  rails generate ...  와 같은 명령어로 생성 시, 자동으로 기본 양식이 담긴 테스트 파일도 생성됩니다.

 부록  Testing Rails Applications

 

13) tmp/

caching data, pid(puma server open 시 임시적으로 생성) 등 임시파일이 담겨져 있습니다.

 

14) vendor/

JavaScript 플러그인과 CSS asset들이 위치하는 디렉터리

 

 

  • Rack ??

이 전에  config.ru  개념을 설명하면서 잠깐 언급했던 개념입니다.

 config.ru  는 서버 실행에 대한 script 내용이 담겨져 있는 파일입니다.

 

그렇다면 서버는 어떻게 통신이 되느냐가 관건인데 저는 그 속에 'Rack' 이라는 기술이 쓰인다고 했습니다.

 

서버/클라이언트 통신에 있어 RACK이 동작되는 단위 (출처 : https://www.joinc.co.kr)

Ruby on Rails라는 Application 에서 서버에 요청을 하고, 응답을 받음에 있어 Rack은 Application과 서버의 중계인으로서 '미들웨어' 역할을 합니다. 이를 통해 Rack은 중간에 소통을 통해 요청/응답을 처리해서 서로에게 전해줄 수 있습니다.

 

 config/routes.rb  파일을 열어보면, 코드 맨 위에 Rails.application 를 볼 수 있는데 이 역시 Rack이 관여하는 하위 application 입니다.

config/routes.rb : Rails.application

즉, Rack은 라우터 연결에 대해서도 관여를 할 수 있습니다.

 

Ruby on Rails는 컨트롤러와 라우터와의 통신에 있어 내부적으로 Action Dispatcher 기술이 쓰이는데, Action Dispatcher 내부 구성에 있어서도 Rack에서 비롯되었습니다. 실제로 터미널에   rails middleware  라고 입력 시, 다음과 같은 결과를 얻어낼 수 있습니다. :

터미널에 rails middleware 입력 시 보여지는 하위 application

그래서 rack을 이용해서 다음과 같은 방법으로도 서버를 열 수 있고, application과 server(혹은 client)와의 통신도 가능합니다.

## 콘솔
Rack::Server.start

## 터미널
rackup config.ru

 부록 

1. What is ActionDispatch?

2. Rack에 대해서

 

 

  • Rails Generate / Destroy

1) 생성 (Generate)

Ruby on Rails에서는 뭔가 파일을 생성함에 있어

# rails generate [타입] [이름] [method / column / action / ...]

rails generate controller bulletins index new show edit create update destroy
rails generate model bulletin title content:text
rails generate scaffold bulletin title content:text

위와같은 명령어를 통해 일단 기본적으로는 MVC 패턴에 필요한 파일들을 만들어낼 수 있고, 자동으로 설정이 이루어집니다.

 

 

2) 제거 (Destroy)

하지만 만약에 이름을 잘못 지었거나, 잘못된 method 등을 생성한 사유로 지워야 할 경우에는 아래 명령어로 지워낼 수 있습니다.

# rails destroy [타입] [이름] [(일부는 선택사항; Option) method / column / action / ...]

rails destroy controller bulletins index new show edit create update destroy
rails destroy controller bulletins
rails destroy model bulletin title content:text
rails destroy scaffold bulletin

 

하지만 일부 destroy에 있어선, 대표적으로 Controller을 지울 시 살짝 차이점이 드러나는 부분이 있습니다.

rails destroy controller bulletins index new show edit create update destroy
rails destroy controller bulletins

대표적으로 위 두 부분인데요,

 

1) 만약 Action을 포함한 채로 삭제를 지울 시, 라우터에 정의되었던 기본 URI 컴포넌트들도 함께 삭제가 됩니다.

rails destroy controller bulletins index new show edit create update destroy

 

2) 반면, Action을 언급하지 않고 삭제를 할 시, 라우터 쪽은 건들지 않고 구성요소들을 삭제합니다.

rails destroy controller bulletins

 

 

3) Tip

사실 저희는 생성/제거에 대한 명령어를 full name(generate/destroy) 으로 작성했었는데, 사실 단축 명칭을 입력해도 됩니다.

rails generate controller bulletins index show
rails g controller bulletins index show

이를테면 generate 같은 경우에는 위와같은 방식으로 표현을 할 수 있습니다! (destroy도 동일)

 

 

  • Say "Hello", Rails!

Rails 내에서 Controller와 View 생성을 통해 바로 홈페이지에 "Hello, Rails!"를 띄어보는 과정을 봅니다.

일단 Rails 내에 홈페이지에 접속 시, 진행되는 내부 과정은 다음과 같습니다.

 

  Step 1 : 홈페이지에 접속을 한다.

  Step 2 : 미들웨어(Rack)에서 요청을 접수받는다.

  Step 3 : 라우터에서 요청에 대한 Controller#Action을 찾아낸다.

  Step 4 : Controller에서 내부적으로 요청을 처리하고, View에 결과를 전송한다.

  Step 5 : 요청에 대한 결과를 View에서 유저에게 보여준다.

 

우리눈에 홈페이지가 보여지기까지의 과정을 서술을 해봤는데, 아직 위 사항을 들어만 봐서는 뭐가 뭔지 모를겁니다.

직접 위 과정 하나하나를 살펴보겠습니다.

 

1. Rails 내 터미널에서 Controller와 View를 생성하는 shell script를 입력해줍니다.

# rails generate controller [이름] [controller에 종속되는 Action들...]
rails generate controller welcome index

 

위 명령어를 수행 시, 아래와 같은 결과물들이 나옵니다.

1) 기본적으로 controller와 view 파일들이 생성됩니다.

2)  config/routes.rb  에 자동으로 URI가 정의됩니다.

3) helper가 생성됩니다.

4) controller test 파일이 생성됩니다 : 테스트 코드 작성 시 사용됩니다.

5) assets(scss, coffee) 파일이 생성됩니다 : css(scss)/javascript(coffee script) 코드를 작성을 할 수 있습니다.

 

여기서 간단히  app/views/welcome/index.html.erb  에 아래 내용을 작성 후, 홈페이지 결과를 확인해봅시다.

## app/views/welcome/index.html.erb

<h1>Hello, Rails!</h1>

성공적으로 홈페이지 결과물이 나왔고,

 

서버에서 확인할 수 있는 응답 결과 및 내부 이벤트

서버에서도 결과를 보면 어떤 이벤트가 오갔는지에 대해 눈으로 확인이 가능합니다.

 

여기서 한가지 강조를 할 게 있다면, 홈페이지가 띄어지기까지의 큰 틀의 과정은 아래와 같습니다 :

라우터 → Controller 내 Action → View(만약 *API 모드로 Rails 프로젝트를 만들었을 경우, View는 생략)

 

* API 모드로 Ruby on Rails 프로젝트를 생성 시, 화면 렌더링에 필요한 요소(Gem, View 등)들이 배제된 채 설치가 되고, 기본으로 서버 응답 시 json 형식으로 응답

 

 

Controller#Action과 View 생성에 있어 주의할게 한가지가 있는데, 아무리 Controller와 View에서 코드를 다 짜서 개발을 해냈다고 해도,  config/routes.rb  에서 URI 정의를 내려주지 않으면 홈페이지 접속이 안됩니다.

No Route Error

 

 

  • 간단한 라우터 규칙

 config/routes.rb  파일에서 사용할 수 있는 기초적인 문법에 대해 알아보겠습니다.

Rails.application.routes.draw do
  root 'bulletins#index'
  get 'welcome/index'
  resources :bulletins
  # For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
end

1) root 처음에 루트도메인으로 웹사이트에 접속 시, 어떤 페이지를 보여줄지에 대한 정의를 합니다.

  * root 문법은 GET 메소드로 정의되며, URI 정의와는 다르게 Controller#Action 으로서 정의를 합니다.

 

2) get GET 메소드를 기반의 URI 정의문법으로서,  http://도메인/welcome/index  에 접속 시,  app/controllers/welcome_controller.rb  내의  index 액션 을 둘러본 후,  app/views/welcome/index.html.erb  의 결과물을 보여줍니다.

 

3) resources 자동으로 REST API 문법에 의거하여 Method/URI 정의가 이루어집니다.

resources :bulletins 정의 시, 라우터에 보여지는 문법

Restful API의 대표적인 예시로는 게시판(CRUD) 라고 볼 수 있습니다.

필자는 CRUD 혹은 Restful API를 짠다는게 만만해 보일 수 있겠지만, 정말 생각할게 많단걸 뼈저리게 느꼈습니다.

 부록  캐치딜 백엔드 개발이야기 : Restful API 설계의 다양한 고민

 

개인적으로 Resftul API 문법은 지금과 같이 MVC를 다 따지는 풀스택적인 성격의 프로젝트 보단, 온전히 백엔드 만(View를 제거한 MC)을 위한 Rails 프로젝트(서버↔클라이언트 통신)에서 빛을 발하는 문법이라고 생각합니다.

 

 

  • Controller ↔ View

" Controller와 View는 기본적으로 서로 종속관계로 되어있습니다. "

 

설명을 시작하기 전에 앞서, 간단히 Controller와 View를 생성해보겠습니다.

* 앞전에 말했지만 Controller 이름은 '복수명' 으로 지어주는게 좋습니다.

rails generate controller bulletins index show new edit update destroy

터미널에 위 명령어를 입력 후, Controller 코드에 정의된 class를 보면 다음과 같은 예시를 볼 수 있습니다.

class BulletinsController < ApplicationController
  def index
    ...
  end
  
  def show
    ...
  end
  
  def new
    ...
  end
  
  def edit
    ...
  end
  
  def update
    ...
  end
  
  def destroy
    ...
  end
end

 

이어서 View를 보면 다음과 같은 디렉터리/파일 구조를 봐보면, 아래와 같은 구조로 볼 수 있습니다.

위 사진에서 Controller 내 Action와 bulletins view 내의 파일들을 보면 Controller 내 Action == 파일이름 인걸 알 수 있습니다.

하지만 만약 이런다면 어떨까요 :

 

 

1. (빈 Rails 프로젝트 상태에서) Controller 생성 후, 다음과 같은 양식을 짭니다.

## app/controllers/bulletins_controller.rb

class BulletinsController < ApplicationController
  def search
    ...
  end
end

 

2. 라우터에 새로운 URI를 정의합니다.

 설명  http://루트페이지/bulletins/search 로 접근 시, bulletins_controller.rb 에서 search 액션에 명시된 작업을 한 후, view에 결과물을 보여줍니다.

config/routes.rb

 참고  사실 get URI 뒤에 명시되어있는 '=> 화살표 이하 내용(컨트롤러#액션)' 이 URI와 명칭(규칙)이 같을 경우, 자동으로 찾아내다 보니 따로 명시 안해줘도 됩니다.

## GOOD

Rails.application.routes.draw do
  get 'bulletins/search'
end

 

하지만 다음과 같이, URI가 Controller 내 다른 Action을 가리키고 싶다면, 따로 명시를 해줘야 합니다.

## app/controllers/bulletins_controller.rb

class BulletinsController < ApplicationController
  def index
    ...
  end
  
  def inquiry
    ...
  end
  
  def show
    @bulletinId = params[:id]
    ...
  end
end
## config/routes.rb

Rails.application.routes.draw do
  get 'bulletins/index'
  get 'bulletins/search' => 'bulletins#inquiry'
  get 'bulletins/:id' => 'bulletins#show'
  ... (이 외 URI 생략) ...
end

 

2. 홈페이지 접근을 시도합니다.

아 저런... 뭔가 에러가 발생합니다.

위와같이 에러가 발생한 이유는 화면에 띄어서 결과문을 보여줄 view 파일이 없기 때문입니다. (템플릿 에러)

 

3. 간단히 위 에러를 해결해보자면,

 app/views/welcome  폴더에  search.html.erb  라는 이름의 파일을 생성해주면 됩니다.

 

 

  • Model ↔ Database table 

과거까지는 백엔드 적으로 작업을 수행하는 Controller와, 백엔드의 결과를 표현할 View에 대해 알아봤다면, 이번에는 Database를 제어할 Model에 대해 알아보겠습니다.

 

1) Model 생성 및 Migrate 개념

일단, Ruby on Rails에서는 아래 명령어를 통해 Model을 생성해낼 수 있습니다 :

* 앞전에 말했지만 Model 이름은 '단수명' 으로 지어주는게 좋습니다.

# rails generate model [모델이름] [Attributes(Default: String)]
rails generate model bulletin title content:text

모델을 생성을 해내면 위와같이 데이터베이스를 제어 및 관계를 정의하는 Model, Migrate, 테스트코드 파일이 생성됩니다.

 

그리고 저는 Migrate 파일 속에 아래와 같은 내용의 테이블 및 컬럼 명세서를 만들어냈습니다.

테이블 이름은 Model 이름을 지을 때 당시의 '복수'표기로 명칭이 바뀌었고, 각 컬럼별로 데이터 타입이 정의되어 되어있습니다.

 

 참고 1  Migrate 파일에 별다른 설정이 없을 시, 기본으로 id, created_at, updated_at 컬럼이 자동으로 추가됩니다.

 참고 2  데이터 타입을 따로 명시하지 않을 경우 기본적으로 String 으로 정의가 됩니다.

 참고 3  일부 테이블 이름은 단순히 s가 붙지 않고, 아예 변형이 되곤 합니다. (generate 한 Model 이름이 mouse인 경우, 테이블 이름은 mice로 변경)

 

그리고 생성된 Migrate 파일을 보면 아래와 같이 생성되어 있습니다.

## app/db/migrate/버전_create_bulletins.rb

class CreateBulletins < ActiveRecord::Migration[5.0]
  def change
    create_table :bulletins do |t|
      t.string :title
      t.text :content

      t.timestamps
    end
  end
end

본 서버에 반영되기 전의 Table 명세서로서 Table 내 Column의 규칙 등을 해당 Migrate 파일을 통해 설정해낼 수 있습니다.

## app/db/migrate/버전_create_bulletins.rb

create_table :bulletins do |t|
  t.string :title, null: false, comment: "bulletin 제목"
  t.text :content, null: false, comment: "bulletin 내용"

  t.timestamps
end

 

하지만 단순히 Model 파일을 Generate를 했다 해서 바로 쓸 수 있는 것은 아닙니다.

rake db:migrate

 

위 명령어를 통해 Rails 프로젝트→Database 에게 '명세서' 라는 것을 넘김으로서, Database Table을 관리하는 스키마를 최신화를 시켜야 비로소 Migrate 파일의 내용이 Database 서버에 적용이 됩니다.

 참고 1  이미 Migrate가 된 상태에서 기존의 migrate 파일을 수정 후,  rake db:migrate  시에는 Migrate 파일에 쓰여진 내용들이 Database에 반영되지 않습니다.

 

 참고 2  혹시 모르고 Table 내 속성(Column)을 깜빡하고 수정하지 않은 채 Database에 Migrate를 해버렸다고 해서 당황하지 마세요!

Rails 내 명령어를 통해 수정하고자 하는 Table 내 Column에 대한 Migrate 파일을 생성하고 정의를 내린 후, 다시 본 서버에 반영시킬 수 있습니다.

 부록  Adding a column to an existing table in a Rails migration

 

2) Active Record

* 이번 글에서는 Deep 하게 다루지는 않겠으나, 그래도 해당 개념은 간단하게라도 알아두면 좋을 것 같아서 짧게 언급해보겠습니다.

위 터미널의 Generate 결과에 있어, 한 가지 눈여겨 볼 부분이 있는데 "Active Record" 이 부분 입니다.

 

Actice Record는 Ruby on Rails에서 지원되는 모듈 중 하나로서, Database의 전반적인 부분을 담당합니다.

 

공식문서에서는 Active Record에 대해 '객체 관계 맵핑(Active Relational mapping System)' 이라고 정의를 내렸는데, 나중에 나아가서 알게되겠지만 Ruby on Rails에서 데이터를 다룰 때 있어서는 SQL을 직접적으로 써서 데이터베이스를 제어하지 않습니다.

## SQL
SELECT * FROM bulletins

## Active Record 지원 기능 : ORM을 통한 표현
Bulletin.all

 

Ruby on Rails에서는 기본적으로 ORM 문법을 통해 위와같이 데이터베이스를 제어합니다.

어떻게보면 사람에게 친숙한 언어를 활용하는 ORM 만으로도 데이터베이스를 제어할 수 있다는게 Rails의 매력이라고 볼 수 있습니다.

 

그리고 Rails 공식 가이드에서 Active Record 정의 중 'mapping System' 이라고 정의가 내려졌는데 그 이유는 다음과 같습니다 :

Rails에서는 ORM을 활용해서 데이터베이스를 조작한다지만, 실제로는 SQL 언어를 기반으로 제어를 하고 있기 때문입니다.

어떻게보면 Active Record가 ORM ↔ 데이터베이스 간에 있어 언어를 해석해주고 서로를 연결시켜주는 연결고리(맵핑)이라고 보면 됩니다.

 

3) Model과 Table

Model을 생성 후, 이전에 소개했던 ORM을 통해 테이블을 조작함에 있어 신기한 점이 한가지 있다면 '단순히 Model 이름만을 가지고 Table을 조작해낸다' 라는 점 입니다.

 

물론 이게 가능한건 Active Record의 공이 큽니다 :

Migrate를 할 때에 있어 Rails 프로젝트 내의 Migrate 자료를 기반으로 Database에 테이블을 생성하면서 레일즈 내에서 Model 이름이 Table을 가리키도록 맵핑화 합니다.

 부록  ActiveRecord는 어떻게 Database의 컬럼과 매핑할까?

 

하지만 ActiveRecord의 맵핑에 있어 이런 이슈가 있습니다 :

" 만약 Migrate 파일이 존재하지 않는 또 다른 Rails Application에서 원격접속을 통해 Database 서버에 접속 후, ORM을 사용한다면??? "

 

위 이슈는 저도 과거에 생각만 해오다가 후에 이 문제를 겪게 되어 많은 고초를 겪곤 했는데요,

결과적으로는 Migrate를 진행하지 않은 또다른 Rails Application에서는 초반에는 ORM 사용이 안됩니다.

 

왜냐하면 또 다른 Application은  rake db:migrate  라는 명령어를 통해 스키마에 Database 정보를 동기화 하지 않았고, 그 결과 ActiveRecord 내에서도 Model ↔ Database table 에 있어 맵핑화를 하지 않았던 겁니다.

 

하지만 그렇다고 아예 맵핑을 못하는건 아닙니다.

강제로 맵핑 후 ORM을 쓰게할 수 있는 방법이 있는데, Model 파일을 생성 후 해당 Model이 Remote Database의 Table을 가리키게 하면 됩니다.

## 또다른 Rails Application에서 서버와 원격접속 후, Database 내 테이블과 맵핑하는 작업
## app/models/bulletin.rb

class Bulletin < ApplicationRecord
  self.table_name = "bulletins"
end

 부록 1  How do I explicitly specify a Model's table-name mapping in Rails?

 부록 2  Ruby on Rails : 다른 AWS EC2 서버 내의 Database와 Remote Connect 하기

 

위와같은 표현을 통해 테이블과 Model 간 맵핑화 작업을 해주면 됩니다.

위 부록에서는 table 이름과 class 이름이 전혀 다르게 답변이 되어있는데, 웬만하면 위와같이 명칭을 통일시키는 것을 추천합니다.

 

 

  • 간단한 View/Form Helper 및 Model : 테이블 관계 정의

Model의 또다른 역할은 타 테이블과의 관계에 있어 정의를 내릴 때 쓰입니다.

예를들어 현재의 게시판에 댓글기능 만든다고 가정해보겠습니다.

첫 시작은 위와같이 이미  bulletins  라고 지어진 이름의 CRUD가 완성되었다는 가정 하에서 진행됩니다.

 부록  Ruby on Rails : MVC 마스터를 위한 노가다 CRUD(게시판 제작)

 

1. comment 모델을 생성합니다.

해당 모델의 테이블 구조는 bulletin_id:integer, body:string 입니다. (기본적으로 생성되는 id, created_at, updated_at 언급은 생략)

rails g model comment bulletin:references body

 참고  과거에 Model을 설명할 때 당시에, 컬럼별로 타입이 있다고 언급을 하긴 했는데, 터미널에서 낯선 문법인 'references' 라는게 보입니다. 하지만 이 문법은 앞전에 봐왔던 integer, string 과 같은 데이터 타입은 아닌 것 같아 보이는데... 뭐지?

해당 문법은 후에 설명하겠습니다.


2. Model을 생성해줬으니 Migrate 파일이 생성된 만큼, Database에 반영을 시켜줘야 합니다.

Migrate 작업을 해주세요.

rake db:migrate

 

3. 이어서 Controller을 생성해보겠습니다.

터미널에 아래 명령어를 입력해주세요.

rails g controller comments create destroy

Comment에 대해서 생성과 삭제를 담당하는 Action 및 View가 추가되었습니다.

(이번 Comment 예제에서는 실제로는 View 파일은 필요가 없습니다.)

 

4. 다음 과정을 시작하기 전에 앞서, 제 view에 대한 디렉터리 상태를 보고 설명을 이어나가겠습니다.

(저와 똑같은 상태가 아니어도 됩니다. 앞으로의 설명 때 제 view의 구조를 유의하여 설명을 볼 때 참고하면 됩니다.)

 

5.  config/routes.rb  파일을 열람 후, 다음과 같이 URI 경로를 정의해주세요.

## config/routes.rb


Rails.application.routes.draw do
  ... (내용 생략) ...
  
  resources :bulletins do
    resources :comments, :only => [:create, :destroy]
  end
end

1) 라우터에서 URI 정의를 내릴 때 있어 저는 REST API를 한번에 정의해주는 resources 문법을 활용했습니다.

2) 그리고 바깥 bulletins의 resources 문법 내부에 또 comments에 대한 REST API를 정의내렸습니다.

3) 하지만 comments에 대한 정의는 create, destroy Action 및 URI에 대해서만 정의를 내렸습니다.

4) 최종적인 URI 정의는 다음과 같습니다.

5) 위 URI 규칙에서 보면 :bulletin_id 혹은 :id 와 같이 어떤 매개변수를 받아내는게 보이는데 저 양식 잘 염두해서 보세요. (훗날 많이 활용됩니다.)

 

6.  app/views/bulletins/show.html.erb  파일로 이동 후, 아래 코드를 추가해서 Comment 작성 및 조회란을 만들어주세요.

... (내용 생략) ...

<%= form_for Bulletin.find(@bulletin.id).comments.build, url: bulletin_comments_path(@bulletin.id) do |f| %>
  <%= f.text_field :body, placeholder: "댓글 내용" %>
  <%= f.submit('댓글 작성', style: "margin-left: 10px") %>
<% end %>

 문법  form_for

- form_for 문법은 HTML에서 흔히 쓰이는 form 태그를 Rails 방식으로 표현하는 문법입니다, 이와같이 HTML 문법을 Rails 방식으로 쓰는 것을 View Helper 라고 합니다.

- form_for은 View Helper에서 지원되는 폼헬퍼(Form Helper) 라고도 합니다.

- form 태그와 관련된 폼헬퍼는 form_for 외에도 form_tag도 존재하는데, Rails 5.1 버전 이상에서는 form_tag와 form_for 문법의 기능이 합쳐진 form_with 문법도 존재합니다. (참고 : Rails 5.1 패치노트)

- form_for에서 Model 혹은 URI path 등 다양한 방법을 통해 정의를 내리면 자동으로 form 태그 내 태그들이 다음과 같이 작성됩니다.

- 폼헬퍼에서는 일반적인 HTML 태그와는 다르게 자동으로 authenticity_token을 생성해내는 특징이 있습니다, 이러한 이유는 Rails Action에서 동작 처리에 있어 create 등과 같이 DB를 작업하는 액션에서는 POST 등과 같은 Method가 쓰이는데, Token(난수) 없이는 작업처리가 안되도록 방지됩니다. (이는 CSRF 공격을 방지하기 위한 수단입니다.)

 

간단히 CSRF 공격에 대해 소개를 하자면, 타 사이트로 부터 form 양식 제출이 나의 홈페이지 서버로 요청이 들어왔을 때, 별다른 의심없이 처리를 함으로서 데이터베이스 서버를 건들이는 공격이라고 보면 됩니다.

 부록  CSRF 해킹 개념

 

참고로 Ruby on Rails에서는 POST/PATCH/DELETE 요청 메소드를 처리함에 있어 Application(Rails Project) 자체가 가지고 있는 난수(새로고침 할 때 마다 매번 변함)와 요청이 들어온 authenticity_token 토큰과 비교를 해서 이 둘이 매칭이 될 때에만 작업이 수행됩니다.

 

- 제 코드에서는 form_for을 다음과 같이 적어냈는데

<%= form_for bulletin_comments_path(@bulletin.id) do |f| %>
  ...
<% end %>

위 코드의 실체는 아래와 같다고 보면 됩니다.

## 새로운 데이터 작성
<%= form_for Bulletin.find(@bulletin.id).comments.build, as: :comment, url: bulletin_comments_path(@bulletin), method: :post, html: { class: "new_comment", id: "edit_comment" } do |f| %>
  ...
<% end %>


## 데이터 수정
<%= form_for Bulletin.find(@bulletin.id).comments.build, as: :comment, url: bulletin_comments_path(@bulletin), method: :post, html: { class: "edit_bullletin", id: "edit_bulletin_54" } do |f| %>
  ...
<% end %>


- 이번 폼헬퍼에서는 다루진 않겠으나, form_for와 form_with는 작성(new)/수정(update)에 따라 데이터가 미리 form태그에 입력될지 안될지를 스스로 판단할 수 있는 능력이 있습니다.

* 이 능력을 이용해서 폼헬퍼 코드 하나만으로 작성(new)/수정(update) 페이지를 동시에 만들어낼 수 있습니다.

 

7. Comment Controller에 다음과 같이 작성해줍니다.

class CommentsController < ApplicationController
  ## 댓글 생성
  def create
    Comment.create(bulletin_id: params[:bulletin_id],body: params[:comment][:body])
    redirect_to "/bulletins/#{params[:bulletin_id]}"
  end

  ## 댓글 제거
  def destroy
    Comment.find(params[:id]).destroy
    redirect_to "/bulletins/#{params[:bulletin_id]}"
  end
end

 참고  5번 설명 때 마지막에 언급했던 :bulletin_id 혹은 :id 를 기억하시나요?

위 코드에 있어 :bulletin_id가 params[:bulletin_id]를, :id는 params[:id]를 가리킵니다.

 

5번 과정 때 봤던 URI 양식을 토대로 댓글이 작성/삭제가 될 시 어떤 bulletin ID에서 비롯되어 작성이 되었는지, 혹은 어떤 댓글 ID값에서 비롯되어 삭제가 요청되는지를 알아볼 수 있습니다.

 

8. 이제 마지막으로 comments 테이블과 bulletins 테이블과의 연관관계를 정의를 해줘야 합니다.

사람은 당연히 위 두 테이블은 서로 관계가 있는 사이라는 것을 상식으로 알고있지만, 컴퓨터는 그 상식 조차를 모르는 바보입니다.

 

테이블 간 관계 설정은  app/models  파일에 있는 Model 파일에서 설정합니다.

1) comment 모델을 열람합니다.

## app/models/comment.rb

class Comment < ApplicationRecord
  belongs_to :bulletin
end

Comment 모델 파일에는 재밌게도 bulletins 테이블과의 관계가 이미 정의되어 있습니다.

 

rails g model comment bulletin:references body

과거 1번 과정에서 Model 파일을 생성할 때 당시 위와같이 입력했던 상황을 기억하세요?

그리고 저는 그 때 당시에는 references에 대한 설명을 건너뛰었었습니다.

 

어떻게 보면 저 references 라는 단어 자체에 이미 답이 있는데요, 저 references의 역할이 '타 테이블과의 연관관계에 대해 정의를 내리는 역할' 이라고 보면 됩니다.

## db/migrate/[버전]_create_comments.rb

class CreateComments < ActiveRecord::Migration[5.0]
  def change
    create_table :comments do |t|
      t.references :bulletin, foreign_key: true
      t.string :body

      t.timestamps
    end
  end
end


테이블에는 외래키(FK, Foreign Key)라고 해서 해당 Key가 가리키는 번호(ID)를 참고해서 연관관계가 있는 타 테이블의 데이터를 찾아내는 키가 존재하는데, references 문법을 활용 시, 외래키의 역할로 쓰일 컬럼이 자동으로 생성되는 것 또한 볼 수 있습니다.

 

그리고 그와 동시에  foreign_key: true  라는 옵션도 자동으로 붙는게 확인이 됩니다. 이로써 해당 컬럼이 외래키로 쓰인다는 규칙이 자동으로 명시됩니다.

 

comments 테이블과 bulletins 테이블의 관계에 있어 comments 테이블은 bulletin 모델 하나만을 바라보고 있는 1:M 관계이므로,  belongs :comment  라고 작성함으로서, 복수개의 comments는 bulletin에 속해있다고 정의되어 있습니다.

 참고  belongs_to 는 테이블 이름 언급 시, '단수 이름'으로 언급합니다.

 

belongs_to 정의 유무에 따른 코드의 결과 (왼쪽 : belongs_to 정의 / 오른쪽 : belongs_to 정의 안함)

belongs_to를 활용하여 위와같이 코드로 표현을 할 수 있으며, 만약 belongs_to를 Model 파일에 언급하지 않을 시, 외래키를 통한 데이터 탐색이 안됩니다.

* 보시다 싶이 comment 데이터를 기반으로 bulletin에 접근하려 하면 No Method Error가 발생합니다.

 

2) bulletin 모델을 열람합니다.

앞서 설명했던 comment 모델파일과는 다르게 테이블의 관계가 정의되어 있지 않습니다.

 

저희는 comment 모델의 belongs 관계에 대한 정의는 이번 실습에는 쓰일 일이 없고, 오히려 bulletin 모델에 쓰여질 테이블 관계에 대한 정의가 필요한 상황입니다.

 

bulletin 모델에 다음과 같이 작성해주세요.

## app/models/bulletin.rb

class Bulletin < ApplicationRecord
  .. (코드 생략) ..

  has_many :comments
end

 

아까와는 다르게 이번에는 bulletin 모델에는 has_many 라는 문법이 쓰여져 있습니다.

 참고  has_many 는 테이블 이름 언급 시, '복수 이름'으로 언급합니다.

 

위 코드의 표현에 대한 해석을 해보자면 'bulletins 테이블에는 많은 comments를 가지고 있다.' 라고 보면 됩니다.

has_many 정의 유무에 따른 코드의 결과 (왼쪽 : has_many 정의 / 오른쪽 : has_many 정의 안함)

has_many를 활용하여 위와같이 코드로 표현을 할 수 있으며, 만약 has_many를 Model 파일에 언급하지 않을 시, 외래키를 통한 데이터 탐색이 안됩니다.

* 보시다 싶이 bulletin 데이터를 기반으로 comments에 접근하려 하면 No Method Error가 발생합니다.

 

9. 이제 마지막으로, 댓글을 작성해냈다면 유저들에게 댓글 내용을 보여주고, 삭제 버튼이 보여지게 해줘야 합니다.

 app/views/bulletins/show.html.erb  파일에 다음 내용을 추가해주세요.

## app/views/bulletins/show.html.erb

... (내용 생략) ...

... (댓글작성 부분 코드) ...

<div style="margin-top: 40px"></div>
<% Bulletin.find(@bulletin.id).comments.each do |comment| %>
  <%= comment.body %> <%= link_to "삭제", bulletin_comment_path(@bulletin.id, comment.id), method: :delete, data: { confirm: '댓글을 삭제하시겠습니까?' } %><hr/>
<% end %>

 문법  link_to

- link_to 문법은 앞전의 form_for에서 봤다싶이 기존의 HTML 문법이 Ruby on Rails 문법으로 재해석 되는 View Helper 에서 지원되는 문법입니다.

- Rails에서 link_to는 HTML의 앵커태그(a)와 유사합니다.

- link_to의 작성 양식은 다음과 같습니다.

link_to TEXT, URI 혹은 Path

<%= link_to "네이버로 이동", "https://naver.com" %>
<%= link_to "댓글 삭제", bulletin_comment_path(@bulletin.id, comment.id), method: :delete %>

 

 개념  Data-method 지원

1) 사실 HTML상에 있어 원래 Method는 GET, POST 2개의 Method밖에 존재하지 않습니다.

그럼 게시글 삭제 때 있어 Delete Method는 어디선가 지원을 받는다는건데... 그게 어디일까요?

 

2) 이 궁금증을 해결해보기 위해 HTML 태그를 개발자도구로 까봤습니다.

delete Method.. 넌 어느 별에서 왔니!

HTML 태그 상에서 Method를 어떻게 제어하나 봤더나 data-method 속성을 통해 제어를 하고 있었습니다.

 

3) 사실 원래 HTML 에서는 data-method 라는 속성은 존재하지 않습니다.

그럼 Rails 내 어딘가에서 data-method 속성을 지원을 하고 있다는 건데 흠...

 

4) 저는 이 부분을 더 파보고자 의심이 되는  app/assets/javascripts/application.js  코드를 조회해봤습니다.

## app/assets/javascripts/application.js

// This is a manifest file that'll be compiled into application.js, which will include all the files
// listed below.
//
// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
// or any plugin's vendor/assets/javascripts directory can be referenced here using a relative path.
//
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
// compiled file. JavaScript code in this file should be added after the last require_* statement.
//
// Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details
// about supported directives.
//
//= require jquery
//= require jquery_ujs
//= require turbolinks
//= require_tree .

코드를 확인해보니 위와같이 require 로서 뭔가가 정의되어 있었습니다. (참고로 require 앞의 //= 는 주석이 아닙니다.)

저기서 저는 jquery_ujs 모듈을 한번 파보기로 했습니다.

 

5) jquery-ujs 모듈을 제공하는 Github 공식문서의 위키를 한번 확인해보기로 했습니다.

jquery-ujs가 지원하는 HTML 속성 리스트

6) 정답은 여기에 있었습니다.

jquery-ujs가 지원하는 속성중에 data-method 가 있었고, 이 덕분에 GET, POST Method 외의 메소드도 쓸 수 있었습니다.

 

7) 하지만  data-*  속성 자체는 jQuery(jquery-ujs)에서 지원을 해주는 것은 아닙니다. jQuery는 이를 좀 더 편하게 사용할 수 있도록 기능을 구현해준 것일 뿐, 실제로  data-*  속성은 DOM에서 비롯된거라고 보면 됩니다.

 부록  jQuery: data() 이해와 활용

 

 참고  show.html.erb 파일 내 link_to에서 가리키는  bulletin_comment_path(@bulletin.id, comment.id)  는 아래 URI 경로와 동일하다고 보면 됩니다.

더불어 괄호 속의 @bulletin.id는 :bulletin_id를, comment.id는 :id를 가리킵니다.

 

10. 여기까지 무사히 해냈다면, 결과적으로 댓글이 잘 작성되는게 확인될겁니다.

bulletins에서 댓글을 작성하는 모습

 

11. comments에 대한 데이터 상태를 보면 다음과 같이 저장되어 있는걸 볼 수 있습니다.

 참고  아래와 같이 테이블 내 데이터를 조회할 수 있도록 보여주는 기능을 지원해주는 Gem 이름은 rails_db 입니다.

 부록   Ruby on Rails : DB 구조를 한눈에 [Gem : rails_db]

 

 

  • 데이터 검증

간혹 form에 입력된 양식을 내부 Controller Action에 보내고, 테이블에 데이터가 쓰여져야 할 때에 있어 데이터 검증을 해야하는 경우가 있습니다 :

  1) 중복 내용인가?

  2) 최소 n글자 이상 작성 되었는가?

  3) 글자가 쓰여졌는가? (NULL 혹은 Empty 상태가 아닌지?)

  4) boolean형 데이터에 있어 true 상태인가?

  5) 동일하게 내용을 작성했는가? (예시 : 비밀번호, 비밀번호 재확인 입력 form)

  6) 유일한 데이터인가?

 

위와같은 데이터 검증을 담당하는 곳은 Model 파일입니다.

만약에 댓글(comments) 작성에 있어, 내용이 쓰여졌는지 + 최소 3글자 이상인지 검사를 하고자 할 때에는 다음과 같이 작성하면 됩니다.

## app/models/comment.rb

class Comment < ApplicationRecord
  ... (belongs_to) ...
  
  validates :body, presence: true,
            length: { minimum: 3 }
end

 

Model 파일에 위와같이 작성 후, 댓글 작성 때에 있어 아예 빈 내용을 보내거나 혹은 3글자 미만의 글을 작성 시, 데이터 작성이 Rollback 처리 되며 댓글이 등록되지 않습니다.

 

validates를 통해 제약조건을 명시 후, 제약조건에 걸리는 text를 작성할 경우의 상황 [좌측 : 3글자 미만, 우측 : 내용을 아무것도 안 쓴 상태(empty)]

 

이 외, 더 자세한 내용은 Rails Guide : Active Record Validations 에서 참고해주세요.

 

 

  • 자료 참고

1. Rails variable controller to model scope

2. SQLite를 사용해야 하는 이유

3. deliver_now vs deliver_later

4. Rails Tutorial : Rails on Rack

5. RackRack 응용 - Joinc

6. Rails Guide : Active Record Basic 

7. Model 중첩 상황에 있어 form_for에 Model을 정의하는 방법

8. Rails Guide : scopes

9. Github : jquery-ujs

10. Ruby on Rails 5.1 Release Note

 

 

 

댓글
댓글쓰기 폼
공지사항
Total
33,249
Today
32
Yesterday
141
링크
TAG more
«   2020/07   »
      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  
글 보관함