들어가기 앞서
개발 환경
- OS: macOS Big Sur 11.5.2
- IDE: Visual Studio Code, RubyMine를 혼용하여 사용
(책에서는 AWS Cloud9 IDE 환경에서 사용) - Ruby: ruby 2.6.9p207 (2021-11-24 revision 67954) [x86_64-darwin20]
- Ruby on Rails: Rails 5.1.6
- SCM: GitHub
AWS Cloud9 환경이 아닌 로컬환경에서 실행하였기 때문에 루비와 레일즈 설치는 가이드 문서를 보고 진행하였다.
클라우드 IDE를 사용할 경우 책의 내용을 따라 하면 된다.
지난 글
지난 장에서 배운 내용을 토대로 학습을 진행하고 있기 때문에 앞의 내용을 모르면 이해가 어렵게 느껴질 수 있다. 이전 글을 읽고 해당 글을 읽기를 추천한다.
목표
이번 장에서 만들 Toy 애플리케이션에서는 사용자와 짧은 Micropost(Twitter로 치면 트윗)만을 표현하는 microblog를 작성한다. 전체적인 뼈대가 세워진 애플리케이션을 토대로 레일즈에서 권장하는 REST 아키텍처에 대해 알아보는 것이 목표이기 때문에 scaffold 스크립트를 사용한다. scaffold는 많은 기능을 자동으로 생성해 주는 스크립트이다. scaffold 기능으로 코드를 자동 생성하면 간단하게 웹의 어지간한 부분부터 모델 데이터 접근까지 조작할 수 있지만 입문자가 레일즈를 이해하기에는 적합하지 않다. 때문에 다음 장부터는 scaffold 명령어를 사용하지 않고 애플리케이션을 작성할 것이다.
애플리케이션 작성
프로젝트 생성 및 Gem 설정
rails new 커맨드를 사용하여 프로젝트를 생성한다. 이때 버전은 5.1.6으로 고정한다.
$ cd ~/workspace #작업 폴더로 이동
$ rails _5.1.6_ new toy_app
$ cd toy_app/
아래와 같이 Gemfile을 수정하고 bundle install 명령어를 사용하여 실제 배포환경의 gem을 제외한 로컬 gem을 설치한다. 그 후 원한다면 소스 코드를 Git에 올려준다.
# Gemfile
source 'https://rubygems.org'
gem 'rails', '5.1.6'
gem 'puma', '3.9.1'
gem 'sass-rails', '5.0.6'
gem 'uglifier', '3.2.0'
gem 'coffee-rails', '4.2.2'
gem 'jquery-rails', '4.3.1'
gem 'turbolinks', '5.0.1'
gem 'jbuilder', '2.7.0'
group :development, :test do
gem 'sqlite3', '1.3.13'
gem 'byebug', '9.0.6', platform: :mri
end
group :development do
gem 'web-console', '3.5.1'
gem 'listen', '3.1.5'
gem 'spring', '2.0.2'
gem 'spring-watcher-listen', '2.0.1'
end
group :production do
gem 'pg', '0.20.0'
end
# Windows 환경에서는 tzinfo-data 라고 하는 gem을 포함 시킬 필요가 있습니다.
gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby]
$ bundle install --without production
Hello world 표시하기
앞장에서 배운 내용을 토대로 기본 페이지에 Hello, world! 가 표시되도록 수정한다.
# app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
protect_from_forgery with: :exception
def hello
render html: 'hello, world!'
end
end
# config/routes.rb
Rails.application.routes.draw do
root 'application#hello'
end
User 리소스 생성
애플리케이션별로 사용자에 대한 표현은 다양하지만 튜토리얼에서는 최소한의 값들만 넣어서 표현한다. 각 사용자는 중복되지 않는 integer형의 id를 가지고 string형의 이름(name), string 형태의 이메일주소(email)를 가진다. 사용자의 데이터모델은 아래와 같다.
위 그림의 users는 데이터베이스의 테이블에 해당되며 id, name, email 속성은 테이블 컬럼에 해당된다. 해당 내용에 대해서는 6장에서 더욱 자세히 다뤄질 예정이다. 설명한 데이터모델과 이를 표시하기 위한 웹 인터페이스를 만들 것이다. 이때 사용자 데이터 모델과 웹 인터페이스를 합쳐 User 리소스라고 부른다.
지금은 앞에서 언급한 scaffold 스크립트로 이 리소스를 생성한다. 레일즈의 scaffold는 rails generate 스크립트에 scaffold 커맨드를 입력하는 것으로 작성할 수 있다. 이때 파라미터로는 단수형태의 리소스명과 속성을 사용하기 때문에 아래와 같이 name:string과 email:string을 추가하여 위에서의 데이터모델과 같게 작성한다. (id는 레일즈에 의해 자동적으로 Primary Key로 데이터베이스에 추가되기 때문에 별도로 입력하지 않아도 된다.)
$ rails generate scaffold User name:string email:string
invoke active_record
create db/migrate/20160515001017_create_users.rb
create app/models/user.rb
invoke test_unit
create test/models/user_test.rb
create test/fixtures/users.yml
invoke resource_route
route resources :users
invoke scaffold_controller
create app/controllers/users_controller.rb
invoke erb
create app/views/users
create app/views/users/index.html.erb
create app/views/users/edit.html.erb
create app/views/users/show.html.erb
create app/views/users/new.html.erb
create app/views/users/_form.html.erb
invoke test_unit
create test/controllers/users_controller_test.rb
invoke helper
create app/helpers/users_helper.rb
invoke test_unit
invoke jbuilder
create app/views/users/index.json.jbuilder
create app/views/users/show.json.jbuilder
invoke assets
invoke coffee
create app/assets/javascripts/users.coffee
invoke scss
create app/assets/stylesheets/users.scss
invoke scss
create app/assets/stylesheets/scaffolds.scss
계속해서 사용자 데이터모델 사용을 위해 데이터베이스를 갱신한다. 이때 명령어는 rails db:migrate이다.
$ rails db:migrate
== CreateUsers: migrating =================================
— create_table(:users)
-> 0.0017s
== CreateUsers: migrated (0.0018s) ========================
브라우저에서 루트 URL(/)로 접속해보면 기존과 동일하게 hello world! 페이지가 표시되겠지만 User 리소스를 scaffold로 생성하였기 때문에 사용자 관련 화면이 많이 추가되어 있는 점이 이전과 달라졌을 것이다. 아래와 같이 페이지에 접속하면 각 페이지에 해당하는 화면이 표시될 것이다.
URL | Acation | Remarks |
/users | index | 모든 사용자를 나열하는 페이지 |
/users/1 | show | id=1인 사용자를 표시하는 페이지 |
/users/new | new | 새 사용자를 만드는 페이지 |
/users/1/edit | edit | id=1인 사용자 편집 페이지 |
위 URL을 참고하여 각 화면에서 사용자 생성 및 수정, 삭제를 진행한다.
현재는 브라우저에서 루트 URL(/)로 접속해보면 hello world! 페이지가 표시되겠지만 사용자 목록을 표시하도록 수정해 보도록 하겠다. 사용자 요청 URL을 컨트롤러와 액션에 할당하는 코드는 레일즈의 라우팅 설정 파일인 config/routes.rb에 있다. 현재 루트 접속 시 Application 컨트롤러 내 hello 액션에 접속되도록 되어 있는 코드를 Users 컨트롤러의 index 액션으로 접속하도록 아래와 같이 수정하였다.
# config/routes.rb
Rails.application.routes.draw do
resources :users
# root 'application#hello'
root 'users#index'
end
코드 수정 후 루트 URL 접속 시 사용자 목록이 표시되는 것을 확인할 수 있다. 그렇다면 생성된 컨트롤러를 자세히 살펴보도록 하겠다. 아래와 같은 형태는 scaffold로 생성된 컨트롤러의 기본 형태이다. 하지만 조금 이상한 점을 발견할 수 있다. 바로 위에서 소개된 4개의 페이지(index, show, new, edit) 개수보다 더 많은 액션(create, update, destroy)이 존재한다는 것이다. 보통 이렇게 페이지와 매핑되지 않는 액션들은 단순히 데이터베이스 상의 사용자 정보를 조작하는 데 사용한다.
class UsersController < ApplicationController
.
.
.
def index
.
.
.
end
def show
.
.
.
end
def new
.
.
.
end
def edit
.
.
.
end
def create
.
.
.
end
def update
.
.
.
end
def destroy
.
.
.
end
end
다음 표는 레일즈에서 REST 아키텍처를 구성하는 모든 액션의 목록이다. 아래 표를 보면 URL이 중복되는 경우가 있지만 HTTP Method가 다르기 때문에 구분될 수 있다.
Http Method | URL | Action | 용도 |
GET | /users | index | 모든 사용자를 나열하는 페이지 |
GET | /users/1 | show | id=1인 사용자 표시 페이지 |
GET | /users/new | new | 새 사용자 작성 페이지 |
POST | /users | create | 사용자 작성 작업 |
GET | /users/1/edit | edit | id=1인 사용자 편집 페이지 |
PATCH | /users/1 | update | id=1인 사용자 갱신 작업 |
DELETE | /users/1 | destroy | id=1인 사용자 삭제 작업 |
💡 REST
컴퓨터과학자 Roy Fielding 에 의해 제창된 REpresentational State Transfer라고 하는 개념의 줄임말로 URL로 자원을 명시하고 자원에 대한 행위를 Http Method로 정의하는 스타일이다. 레일즈에서의 REST는 애플리케이션을 만들 때 컴포넌트(사용자나 마이크로포스트)를 "리소스"로 모델링하는 것을 칭한다. 이 리소스는 관계형 데이터베이스의 등록, 조회, 편집, 삭제(Create/Read/Update/Delete: CRUD) 조작과 4개의 기본적인 HTTP request메서드 (Post/Get/Patch/Delete)에 대응한다. 레일즈 개발자는 RESTful 스타일을 구현함으로써 컨트롤러나 액션 작성에 대한 결정이 용이해진다.
scaffold에서 작성된 User 리소스는 레일즈의 개념을 간단하게 설명하기에는 좋지만 다음과 같은 문제들이 있다.
- 데이터 검증이 이루어지지 않는다.
scaffold의 기본 상태로는 사용자 이름이나 빈칸이거나 이메일이 유효하지 않아도 데이터가 등록된다. - 사용자 인증이 이루어지지 않는다.
로그인, 로그아웃이 이루어지지 않기 때문에 누구든 제한없이 조작할 수 있다. - 테스트 처리가 미흡하다.
scaffold로 작성된 코드에도 매우 간단한 테스트 코드가 포함되어 있지만 데이터 검증이나 사용자 인증 그 외 필수적인 테스트 요구사항이 구현되어있지 않다. - 레이아웃이나 스타일이 제대로 되어있지 않다.
사이트 디자인이나 조작방법이 대중적이지 않다. - 이해하기 어렵다.
scaffold의 코드를 이해할 정도면 애당초 본 튜토리얼을 읽을 필요가 없다.
Micropost 리소스 생성
마이크로포스트의 데이터모델은 사용자보다 더 심플하게 작성한다. 중복되지 않는 integer형의 id와 내용을 기록하는 text형의 context로 구성한다. 여기에 사용자와 관계성을 표현하기 위해 작성자를 저장할 user_id를 추가한다.
위 그림의 microposts는 데이터베이스의 테이블에 해당되며 각 속성은 테이블 컬럼에 해당된다. 해당 내용에 대해서는 6장에서 더욱 자세히 다뤄질 예정이다.
레일즈의 RESTful 구조를 이해하기 위해서는 반복 학습이 효과적이기 때문에 Micropost 리소스를 이해할 때는 위에서 먼저 진행한 User 리소스와 비교하면서 학습하는 것을 추천한다. User 리소스와 마찬가지로 Micropost 리소스도 아래와 같이 scaffold로 코드를 작성하고 데이터베이스를 갱신해 보겠다.
$ rails generate scaffold Micropost content:text user_id:integer
invoke active_record
create db/migrate/20160515211229_create_microposts.rb
create app/models/micropost.rb
invoke test_unit
create test/models/micropost_test.rb
create test/fixtures/microposts.yml
invoke resource_route
route resources :microposts
invoke scaffold_controller
create app/controllers/microposts_controller.rb
invoke erb
create app/views/microposts
create app/views/microposts/index.html.erb
create app/views/microposts/edit.html.erb
create app/views/microposts/show.html.erb
create app/views/microposts/new.html.erb
create app/views/microposts/_form.html.erb
invoke test_unit
create test/controllers/microposts_controller_test.rb
invoke helper
create app/helpers/microposts_helper.rb
invoke test_unit
invoke jbuilder
create app/views/microposts/index.json.jbuilder
create app/views/microposts/show.json.jbuilder
invoke assets
invoke coffee
create app/assets/javascripts/microposts.coffee
invoke scss
create app/assets/stylesheets/microposts.scss
invoke scss
identical app/assets/stylesheets/scaffolds.scss
$ rails db:migrate
== CreateMicroposts: migrating =============================
— create_table(:microposts)
-> 0.0023s
== CreateMicroposts: migrated (0.0026s) ======================
scaffold 제너레이터에 의해 레일즈의 라우팅 설정 파일에 Micropost 리소스용 라우팅 규약이 추가됐다. User와 마찬가지로 resource :microposts이라고 하는 라우팅규약은 Micropost용의 URI를 Micropost 컨트롤러 내부 액션에 할당해 준다.
# config/routes.rb
Rails.application.routes.draw do
resources :microposts
resources :users
root 'users#index'
end
생성된 Micropost 컨트롤러의 구조는 아래와 같다. 이름만 바뀌었을 뿐 그 외 구성은 User 컨트롤러와 동일하다. 이를 통해 REST 아키텍처가 2개의 리소스에 동일하게 적용됐다는 것을 알 수 있다.
Http Method | URL | Action | 용도 |
GET | /microposts | index | 모든 마이크로포스트 보기 페이지 |
GET | /microposts/1 | show | id=1인 마이크로포스트 표시 페이지 |
GET | /microposts/new | new | 새 마이크로포스트 작성 페이지 |
POST | /microposts | create | 마이크로포스트 작성 작업 |
GET | /microposts/1/edit | edit | id=1인 마이크로포스트 편집 페이지 |
PATCH | /microposts/1 | update | id=1인 마이크로포스트 갱신 작업 |
DELETE | /microposts/1 | destroy | id=1인 마이크로포스트 삭제 작업 |
class MicropostsController < ApplicationController
.
.
.
def index
.
.
.
end
def show
.
.
.
end
def new
.
.
.
end
def edit
.
.
.
end
def create
.
.
.
end
def update
.
.
.
end
def destroy
.
.
.
end
end
위 URL을 참고하여 각 마이크로포스트 생성 및 수정, 삭제를 진행한다. 이때 user_id가 존재하는 사용자가 되도록 입력한다.
조금 더 micro라는 이름에 걸맞은 마이크로포스트를 만들어보자. 가장 쉬운 방법으로 문자 수 제한을 생각해 볼 수 있다. 레일즈에서는 validation을 사용하여 간단하게 제한할 수 있다. app/models/micropost.rb를 아래와 같이 수정해 보자.
# app/models/micropost.rb
class Micropost < ApplicationRecord
validates :content, length: { maximum: 140 }
end
위와 같이 수정한 후 140자가 넘는 마이크로포스트를 작성하면 아래와 같이 경고 메시지가 표시된다.
사용자와 마이크로포스트의 관계 표현
여러 가지 데이터 모델 간의 관계를 만드는 것은 레일즈의 강력한 기능 중 하나이다. 여기서는 한 명의 사용자가 여러 개의 마이크로 포스트를 작성한다고 가정한다. User 모델과 Micropost 모델을 각각 아래처럼 수정하는 것으로 관계를 표현할 수 있다.
# app/models/user.rb
class User < ApplicationRecord
has_many :microposts
end
# app/models/micropost.rb
class Micropost < ApplicationRecord
belongs_to :user
validates :content, length: { maximum: 140 }
end
아래 그림은 데이터 모델 간의 관계를 그림으로 나타낸 것이다. microposts 테이블에는 user_id 컬럼을 선언해 놓았기 때문에 레일즈와 Active Record가 두 테이블 간의 관계를 생성해 주는 것이다.
두 데이터를 동시에 표시하는 처리는 다음에 진행하고 여기서는 레일즈의 console을 이용하여 두 테이블의 관계를 확인해 보겠다. 레일즈의 console은 레일즈 애플리케이션과 커뮤니케이션할 수 있는 일종의 프로그램이다. 종료를 위해서는 마지막 줄처럼 exit를 입력하거나 Ctrl + d를 누르면 된다.
일단 rails console 명령어를 입력하고 User.first라고 입력하여 데이터베이스에서 제일 앞 사용자 정보를 조회하여 first_user 변수에 저장한다. first_user.microposts 코드를 실행하면 그 사용자와 관련된 마이크로포스트에 액세스 할 수 있다. 이때 Active Record는 user_id가 first_user의 id와 같은 마이크로포스트를 자동적으로 조회한다.
$ rails console
>> first_user = User.first
=> #<User id: 1, name: "Michael Hartl", email: "michael@example.org",
created_at: "2016-05-15 02:01:31", updated_at: "2016-05-15 02:01:31">
>> first_user.microposts
=> [#<Micropost id: 1, content: "First micropost!", user_id: 1,
created_at: "2011-11-03 02:37:37", updated_at: "2011-11-03 02:37:37">,
"2016-05-15 02:37:37", updated_at: "2016-05-15 02:37:37">,
#<Micropost id: 2, content: "Second micropost", user_id: 1,
created_at: "2016-05-15 02:38:54", updated_at: "2016-05-15 02:38:54">]
>> micropost = first_user.microposts.first
=> #<Micropost id: 1, content: "First micropost!", user_id: 1, created_at:
"2016-05-15 02:37:37", updated_at: "2016-05-15 02:37:37">
>> micropost.user
=> #<User id: 1, name: "Michael Hartl", email: "michael@example.org",
created_at: "2016-05-15 02:01:31", updated_at: "2016-05-15 02:01:31">
>> exit
MVC의 처리
1장에서 간단하게 MVC 패턴에 대해 설명했었다. 그때 배운 내용을 바탕으로 지금까지 작성한 코드를 살펴보겠다.
/users 페이지에 접속해 보자
/users의 index 페이지에 접속한다면 위와 같이 사용자 목록을 조회할 수 있는 화면이 표시될 것이다. 이 화면을 보여주기 위해서 내부에서는 어떤 처리가 일어나고 있는지 MVC 관점에서 살펴보자.
- 브라우저로부터 /users라고 하는 URL의 요청을 레일즈 서버로 송신한다.
- /users 요청은 레일즈의 라우팅 처리에 의해 Users 컨트롤러 내부의 index 액션에 할당된다.
- index 액션이 실행되고 User 모델에게 모든 사용자 출력을 의미하는 User.all 명령을 지시한다.
- User 모델은 쿼리를 실행하여 모든 사용자 정보를 데이터베이스로부터 출력한다.
- 데이테베이스로부터 획득한 사용자 정보를 User 모델에서 컨트롤러로 전달한다.
- User 컨트롤러는 사용자 정보를 @users 변수에 저장 후 index 뷰에 전달한다.
(Ruby는 인스턴스 변수를 @로 표현) - index 뷰가 실행되어 ERB를 실행하여 HTML을 생성(렌더링)한다.
여기서 ERB란 Embedded Ruby의 약자로 HTML과 함께 기술되어 있는 루비 코드이다. - 컨트롤러는 뷰에서 생성된 HTML을 받아 브라우저에 응답한다.
지금부터 User 리소스를 통해 위와 같은 처리에 대해 조금 더 자세하게 알아보도록 하겠다.
1. 브라우저로부터 /users 라고하는 URL의 요청을 레일즈 서버로 송신한다.
이 요청은 주소창에 URL을 입력한다거나 링크를 클릭했을 때 발생한다.
2. /users 요청은 레일즈의 라우팅 처리에 의해 Users 컨트롤러 내부의 index 액션에 할당된다.
해당 요청은 레일즈 라우팅에 도착하고 여기서 URL과 Http Method를 기반으로 적절한 컨트롤러의 액션에 할당된다. 이 과정을 dispatch라고도 한다. URL과 Http Method를 컨트롤러의 액션에 할당하는 코드는 레일즈의 라우팅 설정 파일인 config/routes.rb에 위치한다.
# config/routes.rb
Rails.application.routes.draw do
resources :users
# root 'application#hello'
root 'users#index'
end
3. index 액션이 실행되고 User 모델에게 모든 사용자 출력을 의미하는 User.all 명령을 지시한다.
/users의 요청에 실행되는 액션은 User 컨트롤러의 index 액션이다. @users = User.all 라인에서 User 모델에게 사용자 출력을 의미하는 User.all 명령을 지시한다.
# app/controllers/users_controller.rb
class UsersController < ApplicationController
.
.
.
def index
@users = User.all
end
.
.
.
end
4. User 모델은 쿼리를 실행하여 모든 사용자 정보를 데이터베이스로부터 출력한다.
User 모델에 별도로 정의된 메서드는 없지만 상속에 의해 많은 기능을 갖추고 있다. 특히 Active Record라고 하는 Ruby 라이브러리 덕분에 User.all이라는 요청에 대해 모든 사용자를 조회할 수 있다.
# app/models/user.rb
class User < ApplicationRecord
end
5. 데이테베이스로부터 획득한 사용자 정보를 User 모델에서 컨트롤러로 전달한다.
@users = User.all 라인에서 User 모델로부터 모든 사용자의 정보를 받아 @users라는 변수에 저장한다.
# app/controllers/users_controller.rb
class UsersController < ApplicationController
.
.
.
def index
@users = User.all
end
.
.
.
end
6. User 컨트롤러는 사용자 정보를 @users 변수에 저장 후 index 뷰에 전달한다.
@users 변수에 사용자 목록이 저장되면 컨트롤러는 아래의 뷰를 호출한다. @로 시작하는 변수는 Ruby에서는 인스턴스 변수로 불리며 레일즈의 컨트롤러 내부에서 선언한 인스턴스 변수는 뷰에서도 사용할 수 있다.
# app/views/users/index.html.erb
<p id="notice"><%= notice %></p>
<h1>Users</h1>
<table>
<thead>
<tr>
<th>Name</th>
<th>Email</th>
<th colspan="3"></th>
</tr>
</thead>
<tbody>
<% @users.each do |user| %>
<tr>
<td><%= user.name %></td>
<td><%= user.email %></td>
<td><%= link_to 'Show', user %></td>
<td><%= link_to 'Edit', edit_user_path(user) %></td>
<td><%= link_to 'Destroy', user, method: :delete, data: { confirm: 'Are you sure?' } %></td>
</tr>
<% end %>
</tbody>
</table>
<br>
<%= link_to 'New User', new_user_path %>
뷰는 이 내용을 HTML로 변환하고(7번) 컨트롤러가 브라우저에게 HTML을 송신하여 브라우저에게 HTML이 출력되도록 한다.(8번)
상속의 계층
Toy 애플리케이션에서 사용하고 있는 레일즈의 컨트롤러와 모델의 클래스 계층에 대해 간단하게 정리해보고자 한다. 기존에 객체지향에 대한 이해가 있다면 조금 더 수월할 테지만 그렇지 않아도 읽어본다는 것에 의의를 두자. 참고로 루비에서는 상속관계를 < 로 표기한다.
컨트롤러 상속 구조
아래 코드에서 보면 두 리소스의 컨트롤러 모두 ApplicationController를 상속받고 있다. 또한 ApplicationController 또한 ActionController::Base라는 클래스를 상속받고 있다는 것을 알 수 있다. 이 클래스는 레일즈의 Action Pack이라고 하는 라이브러리가 제공하는 컨트롤러의 기본 클래스이다.
# app/controllers/users_controller.rb
class UsersController < ApplicationController
.
.
.
end
# app/controllers/microposts_controller.rb
class MicropostsController < ApplicationController
.
.
.
end
# app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
.
.
.
end
두 컨트롤러와 같이 레일즈 컨트롤러는 반드시 ApplicationController를 상속하고 있다. 이는 결국 ActionController::Base 또한 상속받는다는 것을 의미한다. 덕분에 어떤 컨트롤러라도 오브젝트의 조종이나 HTTP request 필터링, 뷰를 HTML로 변환하여 출력하는 등의 다채로운 기능을 실행할 수 있다. 추가로 모든 액션에 반영되어야 하는 규칙이 있다면 ApplicationController에 정의하면 된다.
모델 상속 구조
모델의 상속 구조도 컨트롤러의 상속 구조와 비슷하다. 두 모델 모두 ApplicationRecord라는 클래스를 상속받고 있으며 이 클래스는 Active Record가 제공하는 기본 클래스인 ActiveRecord::Base를 상속받고 있다. 이를 통해 작성한 모델 오브젝트는 데이터베이스에 접근할 수 있게 되고 데이터베이스의 컬럼을 Ruby 속성처럼 다룰 수 있다
# app/models/user.rb
class User < ApplicationRecord
.
.
.
end
# app/models/micropost.rb
class Micropost < ApplicationRecord
.
.
.
end
# app/models/application_record.rb
class ApplicationRecord < ActiveRecord::Base
self.abstract_class = true
end
글을 마치며
2장에서는 아래와 같은 내용을 배울 수 있었다.
- Scaffold 기능에서 코드를 자동 생성하면 웹의 기본적인 부분부터 모델 데이터에 접근하여 조작까지 할 수 있다.
- Scaffold는 무엇보다도 간단하고 손쉽지만 이것을 바탕으로 레일즈를 이해하기에는 적절하지 않다.
- 레일즈에서는 웹 애플리케이션의 구성에 MVC (Model - View - Controller)라고 하는 모델을 채용하고 있다.
- 레일즈가 해석하는 REST에는 표준적인 URL 세트와 데이터모델을 조작하기 위한 컨트롤러 액션이 포함되어 있다.
- 레일즈는 데이터의 Validation(유효성) 검사 기능을 제공하고 있으며 데이터모델의 속성값을 제한하는 것이 가능하다.
- 레일즈에서는 여러 가지 데이터 모델 간의 관계를 정의할 수 있으며 이를 위한 많은 함수가 준비되어 있다.
- 레일즈 콘솔을 사용하면 커맨드 라인을 이용하여 Rails 애플리케이션을 조작할 수 있다.
확실히 애플리케이션을 작성하며 구조를 분석하니 레일즈의 구조가 더 잘 이해되는 느낌이다. 굉장히 편리한 언어라는 것은 확실하지만 아직 적응이 안 된 상태라 편하면서도 불편하다. 하루빨리 적응되길 기원한다.
오늘 작성한 코드 또한 아래 GitHub에서 확인할 수 있으니 참고 바란다.
참고 자료 및 사이트