들어가기 앞서
개발 환경
- 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를 사용할 경우 책의 내용을 따라 하면 된다.
지난 글
이번 장에서는 3장에서 만든 Sample 애플리케이션에 레이아웃을 추가하거나 수정하는 등의 부분을 중점적으로 소개할 것이다. 따라서 이전 글을 먼저 읽고 오길 권장한다.
목표
이번 장에서는 Sample 애플리케이션에 Bootstrap 프레임워크와 커스텀 스타일을 적용해 볼 것이고 지금까지 작성한 페이지에 링크를 추가해 볼 계획이다. 해당 과정 중간에 파셜(Partial), 레일즈의 라우팅, Asset Pipeline에 대해 언급할 예정이며 Sass에 대해서도 간단히 소개할 것이다. 특히 마지막 부분에서는 사용자를 사이트에 로그인시키기 위한 작업을 진행해 볼 예정이니 끝까지 함께 진행하길 바란다.
구조 수정
레일즈 튜토리얼은 웹 개발을 위한 책이지 웹 디자인을 위한 책은 아니지만 최소한의 디자인은 필요하다. 때문에 이번 장에서는 몇 가지 레이아웃 구조와 CSS를 추가하여 최소한의 스타일을 추가해 볼 것이다. 커스텀 CSS 이외에도 Twitter에 의한 오픈소스 웹 디자인 프레임워크로 공개되어 있는 Bootstrap을 이용해 볼 것이다.
※ Bootstrap 버전 변경 등의 이유로 일부 디자인은 튜토리얼 원문과 다를 수 있습니다.
브랜치 생성
이번 장에서는 별도로 프로젝트를 생성하지 않고 3장에서 만든 Sample App에 계속해서 작업을 이어갈 것이다. Git에서 버전을 관리하고 있다면 master 브랜치에서 작업하는 것이 아닌 작업 당시의 토픽 브랜치를 작성하여 작업하는 것이 좋다. 다음 명령어를 이용하여 루비 학습 용 브랜치를 생성하겠다.
$ git checkout -b filling-in-layout
Navigation 생성
가장 먼저 링크와 스타일을 추가하기 위해 사이트 레이아웃 파일인 application.html.erb의 HTML구조를 다음과 같이 수정해 보겠다.
<!-- app/views/layouts/application.html.erb -->
<!DOCTYPE html>
<html>
<head>
<title><%= full_title(yield(:title)) %></title>
<%= csrf_meta_tags %>
<%= stylesheet_link_tag 'application', media: 'all',
'data-turbolinks-track': 'reload' %>
<%= javascript_include_tag 'application',
'data-turbolinks-track': 'reload' %>
<!--[if lt IE 9]>
<script src="//cdnjs.cloudflare.com/ajax/libs/html5shiv/r29/html5.min.js">
</script>
<![endif]-->
</head>
<body>
<header class="navbar navbar-dark bg-dark">
<div class="container">
<%= link_to "sample app", '#', id: "logo" %>
<nav>
<ul class="nav justify-content-end">
<li class="nav-item"><%= link_to "Home", '#', class: "nav-link" %></li>
<li class="nav-item"><%= link_to "Help", '#', class: "nav-link" %></li>
<li class="nav-item"><%= link_to "Log in", '#', class: "nav-link" %></li>
</ul>
</nav>
</div>
</header>
<div class="container">
<%= yield %>
</div>
</body>
</html>
레일즈는 기본으로 HTML5를 지원하고 있으며 여기서도 <!DOCTYPE html>를 통해 HTML5를 선언하고 있다. 그러나 HTML5은 비교적 새로운 기술로 일부 브라우저에서는 HTML5가 잘 지원되지 않을 수도 있고 특히 Internet Explorer 지원이 안 되는 경우가 많다. 그 때문에 다음과 같은 JavaScript 코드를 사용하여 문제를 해결한다. <!--[if lt IE 9]> 코드는 IE 버전이 9보다 낮을 경우 실행되는 코드로 조건 코멘트라고 불리며 IE에서 특별하게 지원해주고 있다. Firefox, Chrome, Safari 등의 다른 브라우저에는 영향을 주지 않으면서도 IE의 버전 9 미만일 경우만 HTML5 shim을 읽어 들이는 매우 편리한 기능이다. 레일즈의 기능은 아니지만 알아두도록 하자.
<!--[if lt IE 9]>
<script src="//cdnjs.cloudflare.com/ajax/libs/html5shiv/r29/html5.min.js">
</script>
<![endif]-->
다음으로 header 태그 영역은 페이지 윗부분에 표시되어야 할 요소를 포함하고 있다.
<header class="navbar navbar-dark bg-dark">
<div class="container">
<%= link_to "sample app", '#', id: "logo" %>
<nav>
<ul class="nav justify-content-end">
<li class="nav-item"><%= link_to "Home", '#', class: "nav-link" %></li>
<li class="nav-item"><%= link_to "Help", '#', class: "nav-link" %></li>
<li class="nav-item"><%= link_to "Log in", '#', class: "nav-link" %></li>
</ul>
</nav>
</div>
</header>
자세히 살펴보면 먼저 heade 태그에는 navbar, navbar-dark, bg-dark라고 하는 세 가지 CSS 클래스가 스페이스로 구분 지어져 적용되고 있다. 모든 HTML 태그는 아이디(id)와 클래스(class)를 지정할 수 있고 이는 CSS에서 스타일을 지정하기 위한 선택자로 사용할 수 있다. 둘의 차이점으로는 클래스는 페이지 내부에서 몇 번이고 중복해서 사용할 수 있는 것에 반해 아이디는 단 한 번만 사용할 수 있다. 현재의 경우 모든 navbar 클래스에는 향후 설정하는 Bootstrap 프레임워크에 의해 특별한 의미가 부여된다.
<header class="navbar navbar-dark bg-dark">
header 태그 안쪽에는 div 태그가 있고 마찬가지로 Bootstrap을 위한 클래스가 적용되어 있다. div 태그는 일반적으로 표시영역(범위)을 나타내며 세부 요소(태그)를 개별 부품으로 나눌 때도 사용한다. 특히 조금 오래된 스타일의 HTML에서는 div 태그가 거의 모든 범위에서 사용되어 왔다. 그러나 HTML5부터는 태그로 의미를 추측할 수 있는 header, nav, section 등의 시멘틱 태그가 새롭게 추가되었다.
<div class="container">
다음에는 ERB 코드가 등장하는데 링크를 생성하기 위해 레일즈 헬퍼의 link_to 메서드를 사용하고 있다. link_to의 첫 번째 매개수로는 표시될 텍스트, 두 번째 매개변수로는 URL이 입력된다. 지금은 더미링크인 #을 입력하고 향후에 변경하도록 하자. 세 번째 매개변수는 옵션 해시로 필수값은 아니기 때문에 생략이 가능하지만 여기서는 id를 지정하고 있다. 이처럼 레일즈 헬퍼를 사용하면 임의의 HTML 옵션을 유연하게 추가할 수 있다.
<%= link_to "sample app", '#', id: "logo" %>
div의 안쪽 태그 2번째 요소는 ul(순번이 없는 리스트 태그)과 li(리스트 아이템 태그)로 이루어진 nav 태그이다. nav 태그는 해당 내용이 내비게이션 링크를 포함하고 있다고 명시적으로 나타내는 시멘틱 태그이다. ul 태그와 li 태그에 적용되어 있는 클래스도 Bootstrap에서 의미를 가진다. 따라서 이번 장에서 Bootstrap의 CSS를 추가했을 때 위 태그에 스타일이 자동적으로 적용될 것이다.
<nav>
<ul class="nav justify-content-end">
<li class="nav-item"><%= link_to "Home", '#', class: "nav-link" %></li>
<li class="nav-item"><%= link_to "Help", '#', class: "nav-link" %></li>
<li class="nav-item"><%= link_to "Log in", '#', class: "nav-link" %></li>
</ul>
</nav>
레일즈가 ERB 코드를 확인하고 레이아웃을 출력한다면 위 코드는 아래와 같이 바뀔 것이다. 이것이 레일즈에서 브라우저에게 최종적으로 전달되는 HTML이다.
<nav>
<ul class="nav justify-content-end">
<li class="nav-item"><a class="nav-link" href="#">Home</a></li>
<li class="nav-item"><a class="nav-link" href="#">Help</a></li>
<li class="nav-item"><a class="nav-link" href="#">Log in</a></li>
</ul>
</nav>
마지막 부분에는 메인 콘텐츠용의 div 태그가 있다. 마찬가지로 container 클래스도 Bootstrap에서 동작한다. <%= yield %>은 앞장에서 확인한 것과 마찬가지로 웹 사이트 레이아웃에 각각의 페이지 내용을 출력한다. 이것으로 기본적인 레이아웃은 완성하였다.
<div class="container">
<%= yield %>
</div>
추가로 향후 작업을 위해 home.html.erb 뷰 파일에 특별한 요소를 몇 가지 작성하겠다. 우선 7장에서 사이트에 사용자를 추가할 때를 대비하여 임시 링크를 작성한다. 아래 코드에서 추가된 클래스들은 모두 Bootstrap에서 제공하는 클래스이다. 2번째 링크에서는 매개변수로 이미지 파일 경로와 옵션 해시를 가진 iamge_tag 메서드를 사용하고 있다. 현재는 이미지 파일이 없으니 링크에서 다운로드하여 app/assets/images 디렉터리에 저장하자. 그러면 레일즈는 해당 이미지 파일을 에셋 파이프라인을 이용하여 app/assets/images/ 디렉터리에서 찾아 표시한다. 이와 관련된 내용은 뒤에서 조금 더 자세히 다루도록 하겠다.
<!-- app/views/static_pages/home.html.erb -->
<div class="center jumbotron">
<h1>Welcome to the Sample App</h1>
<h2>
This is the home page for the
<a href="https://railstutorial.jp/">Ruby on Rails Tutorial</a>
sample application.
</h2>
<%= link_to "Sign up now!", '#', class: "btn btn-lg btn-primary" %>
</div>
<%= link_to image_tag("rails.png", alt: "Rails logo"),
'http://rubyonrails.org/' %>
클라우드 IDE나 Unix계열의 OS(Linux maxOS 등)를 사용하는 경우에는 다음과 같이 curl 커맨드를 사용하여 간단히 다운로드하는 것이 가능하니 참고 바란다.
$ curl -o app/assets/images/rails.png -OL railstutorial.jp/rails.png
지금까지의 과정이 제대로 적용되었다면 레일즈 서버를 재부팅 후 아래와 같은 화면을 확인할 수 있다.
image_tag의 효과를 확인하기 위해 브라우저에서 HTML을 확인해 보면 9308b8f92fea4c19a3a0d8385b494526같은 문자열을 레일즈가 추가한 것을 확인할 수 있다. 이때 값은 시스템마다 다를 수 있으나 이것은 이미지 파일을 수정했을 때 브라우저 내부에 보존되어 있는 캐시에 중첩되지 않기 위한 장치이다.
또한 src 속성에는 images라고 하는 디렉터리 이름이 포함되어 있지 않다. 이것은 assets 디렉터리 내부의 다른 디렉터리도 동일하다. 이 기능은 파일 고속화를 하기 위한 기능으로 레일즈에서는 assets 디렉토리 바로 아래의 이미지파일을 app/assets/images 디렉토리에 있는 파일과 연결해 준다. 이로 인해 브라우저의 입장에서는 모든 파일이 같은 디렉터리에 있는 것처럼 해준다. 그리고 단순한 디렉토리 구성을 통해 브라우저에게 파일을 보다 빠르게 전달할 수 있게 되는 것이다.
마지막으로 alt 속성은 이미지가 없는 경우를 대신하여 표시되는 문자열이다. 예를 들면 시각장애가 있는 사용자가 사용하는 스크린리더 등은 여기서의 alt 속성을 읽어 들이는 것으로 해당 장소에 이미지 파일이 있다는 것을 표현한다.
<img alt="Rails logo" src="/assets/rails-9308b8f92fea4c19a3a0d8385b494526.png" />
Bootstrap과 Custom CSS
앞서 많은 HTML 요소에 CSS 클래스를 적용하였고 그중 일부는 Bootstrap가 제공하는 클래스임을 언급하였다. Twitter에서 만든 Bootstrap 프레임워크를 사용하면 웹 디자인과 UI 요소를 간단하게 HTML5에 추가할 수 있고 애플리케이션을 반응형 디자인 (Responsive Design)으로 만들 수 있다. 반응형 디자인을 반영하면 장치에 적절한 디자인으로 애플리케이션을 사용할 수 있다는 장점이 있다. 튜토리얼에서의 Bootstrap 적용 방법은 약간 오래전 것으로 본문과 조금 다르게 적용하도록 하겠다. Bootstrap Version 3의 적용방법은 링크에서 확인 가능하다.
먼저 Bootstap을 사용하기 위해 Gemfile에 Bootstrap gem을 추가한다.
# Gemfile
source 'https://rubygems.org'
gem 'rails', '5.1.6'
gem 'bootstrap', '~> 4.3.1' # 추가
gem 'puma', '3.9.1'
.
.
.
늘 해왔던 것처럼 설치를 위해 bundle install 명령을 실행한다.
$ bundle install
커스텀 CSS를 위해 아래와 같이 파일을 생성한다. 참고로 rails generate 명령어를 사용하면 컨트롤러별로 나눠져 있는 CSS 파일을 자동으로 만들 수 있지만 복잡도가 높아 본 튜토리얼에서는 간단하게 하나의 파일로 작성하도록 하겠다.
$ touch app/assets/stylesheets/custom.scss
파일을 생성했다면 다음 코드처럼 @import를 사용하여 Bootstrap를 읽어 들이도록 한다.
/* app/assets/stysheets/custom.scss */
@import "bootstrap";
그 후 application.css를 application.scss로 바꾼 후 내부 require 문을 삭제하고 custom.scss를 @import를 사용해 포함시킨다.
$ mv app/assets/stylesheets/application.css app/assets/stylesheets/application.scss
/* app/assets/stylesheets/application.scss */
/*
* This is a manifest file that'll be compiled into application.css, which will include all the files
* listed below.
*
* Any CSS and SCSS file within this directory, lib/assets/stylesheets, or any plugin's
* vendor/assets/stylesheets directory can be referenced here using a relative path.
*
* You're free to add application-wide styles to this file and they'll appear at the bottom of the
* compiled file so the styles you add here take precedence over styles defined in any other CSS/SCSS
* files in this directory. Styles in this file should be added after the last require_* statement.
* It is generally better to create a new file per style scope.
*
*/
@import "custom";
여기서 짚고 넘어가야 할 포인트는 지금 수정한 파일들이 포함된 폴더와 파일 확장자이다. app/assets/stylesheets 폴더는 향후 설명할 에셋 파이프라인(Asset Pipeline)의 일부이기도 하고 해당 폴더에 저장된 스타일시트는 application.css의 일부로써 웹 사이트의 레이아웃에 적용된다. 그리고 파일의 확장자 SCSS는 Sassy(Syntactically Awesome Style Sheets) CSS의 약자로 CSS를 확장한 언어이다. 에셋 파이프라인은 해당 파일의 확장자를 확인하고 SCSS를 처리할 수 있도록 한다. 서버 재시작 후 다시 한번 접속해 보자. 짜잔- 기존보다는 예쁘지만 뭔가 괜찮다고 하기도 애매한 디자인이 되었다.
조금 더 나은 디자인을 위해 레이아웃과 각 페이지에 적용할 CSS를 추가하자.
/* app/assets/stylesheets/custom.scss */
@import "bootstrap";
/* universal */
section {
overflow: auto;
}
textarea {
resize: vertical;
}
.center {
text-align: center;
}
다시 새로 고침을 해보면 조금 더 나아진 화면을 볼 수 있다.
CSS 규약에서는 보통 아이디, 클래스, 태그 혹은 이것들의 조합으로 HTML 요소들을 지정한 후 스타일링을 지정할 수 있다. 예를 들어 다음 예시는 center 클래스가 적용된 요소의 내부 요소를 모두 가운데 정렬한다는 의미이다. 이때 .center에서의 .은 클래스에 스타일을 적용한다는 의미이고 나중에 나오겠습니다만 #으로 시작하는 경우에는 아이디에 대해 스타일을 적용한다는 의미이다.
.center {
text-align: center;
}
다음은 아래와 같은 커스텀 CSS를 추가하여 텍스트의 모양을 조금 바꾸어보겠다. 이번에 추가하는 스타일은 Sample 애플리케이션의 다른 페이지에서도 사용될 것이다.
/* app/assets/stylesheets/custom.scss */
@import "bootstrap";
.
.
.
/* typography */
h1, h2, h3, h4, h5, h6 {
line-height: 1;
}
h1 {
font-size: 3em;
letter-spacing: -2px;
margin-bottom: 30px;
text-align: center;
}
h2 {
font-size: 1.2em;
letter-spacing: -1px;
margin-bottom: 30px;
text-align: center;
font-weight: normal;
color: #777;
}
p {
font-size: 1.1em;
line-height: 1.7em;
}
추가한 결과는 아래 그림과 같다.
마지막으로 몇 가지 스타일을 로고에 추가해 보자. 현재는 "sample app"만 표시하는 심플한 로고지만 아래의 CSS를 추가하여 수정하도록 하겠다. 여기서는 사이트 로고가 다른 곳에 쓰이지 않는 것을 전제로 하여 아이디를 사용하고 있지만 클래스에 적용해도 상관없다. 코드에서 color: #fff는 로고색을 하얀색으로 바꾼다. HTML의 색은 3개의 16진수로 표현되며 빨강, 파랑, 녹색 3 원색을 코드로 바꾸어 표현한다. 원래는 #ffffff로 작성하여 세 가지 색 모두 최대로 해야 하지만 여기서는 #ffffff의 축약형인 #fff를 사용한다. 참고로 CSS표준에서는 색 별칭을 많이 사용하는데 #fff는 white로 바꾸어 쓸 수 있다.
/* app/assets/stylesheets/custom.scss */
@import "bootstrap";
.
.
.
/* header */
#logo {
float: left;
margin-right: 10px;
font-size: 1.7em;
color: #fff;
text-transform: uppercase;
letter-spacing: -1px;
padding-top: 9px;
font-weight: bold;
}
#logo:hover {
color: #fff;
text-decoration: none;
}
위 코드를 적용하면 아래와 같이 바뀐 걸 확인할 수 있다.
파셜(Partial)
레이아웃의 코드는 목적을 달성했지만 몇 가지 수정이 필요한 부분이 보인다. 먼저 레이아웃 코드 내 IE 고유의 설정을 위한 HTML shim 코드가 3줄이 있다. 이 코드를 숨길 수가 있다면 좋을 것이다. 또한 HTML 헤더는 논리적 단위로 나눠져있기 때문에 한 곳으로 모아서 처리하는 것이 더욱 좋다. 레일즈에서는 파셜(partial)이라는 기능으로 이러한 문제들을 해결할 수 있다. 일단 파셜을 정의하면 레이아웃이 어떻게 변하는지 확인해 보자.
<!-- app/views/layouts/application.html.erb -->
<!-- 레이아웃 파일에 shim과 header 파셜 파일을 추가한다 -->
<!DOCTYPE html>
<html>
<head>
<title><%= full_title(yield(:title)) %></title>
<%= csrf_meta_tags %>
<%= stylesheet_link_tag 'application', media: 'all',
'data-turbolinks-track': 'reload' %>
<%= javascript_include_tag 'application',
'data-turbolinks-track': 'reload' %>
<%= render 'layouts/shim' %>
</head>
<body>
<%= render 'layouts/header' %>
<div class="container">
<%= yield %>
</div>
</body>
</html>
위 코드에서는 다음과 같이 render라는 레일즈 헬퍼를 사용하여 HTML shim 코드를 대체하고 있다. 이 코드는 app/views/layouts/_shim.html.erb 파일을 찾아 그 안의 내용을 확인하고 뷰에 삽입한다. 파일명 앞에 오는 언더바는 파셜에서 사용하는 보편적인 명명규칙이며 레일즈에서 해당 파일이 파셜 파일이라는 것을 알 수 있게 해 준다.
<%= render 'layouts/shim' %>
정상적인 파셜 동작을 위해 각 단위에 대응하는 파일을 생성하고 콘텐츠를 작성해야 한다. shim 파셜의 경우 다음과 같은 3줄의 shim코드만 존재한다.
<!-- app/views/layouts/_shim.html.erb -->
<!--[if lt IE 9]>
<script src="//cdnjs.cloudflare.com/ajax/libs/html5shiv/r29/html5.min.js">
</script>
<![endif]-->
마찬가지로 헤더도 아래와 같이 파셜 파일로 분리한다.
<!-- app/views/layouts/_header.html.erb -->
<!-- header용의 파셜 -->
<header class="navbar navbar-dark bg-dark">
<div class="container">
<%= link_to "sample app", '#', id: "logo" %>
<nav>
<ul class="nav justify-content-end">
<li class="nav-item"><%= link_to "Home", '#', class: "nav-link" %></li>
<li class="nav-item"><%= link_to "Help", '#', class: "nav-link" %></li>
<li class="nav-item"><%= link_to "Log in", '#', class: "nav-link" %></li>
</ul>
</nav>
</div>
</header>
다음으로는 헤더에 대응하는 푸터(Footer)를 같은 방법으로 작성해 보자. 파일 이름은 _footer.html.erb라는 것과 layouts 폴더 안에 저장하면 되는 것은 눈치챘을 것이다. 푸터에서는 헤더와 마찬가지로 link_to 메서드를 사용하여 About 페이지와 Contact 페이지로의 링크를 추가하고 있다. 이때 연결되는 URL은 당장은 '#'으로 하자. 또한 여기서 사용하고 있는 footer 태그는 header 태그와 마찬가지로 HTML5에서 새롭게 추가된 요소이다.
<!-- app/views/layouts/_footer.html.erb -->
<!-- footer용의 파셜 -->
<footer class="footer">
<small>
The <a href="https://railstutorial.jp/">Ruby on Rails Tutorial</a>
by <a href="http://www.michaelhartl.com/">Michael Hartl</a>
</small>
<nav>
<ul>
<li><%= link_to "About", '#' %></li>
<li><%= link_to "Contact", '#' %></li>
<li><a href="http://news.railstutorial.org/">News</a></li>
</ul>
</nav>
</footer>
그다음으로는 레이아웃 파일 내부에 푸터 파셜을 추가한다
<!-- app/views/layouts/application.html.erb -->
<!DOCTYPE html>
<html>
<head>
<title><%= full_title(yield(:title)) %></title>
<%= csrf_meta_tags %>
<%= stylesheet_link_tag 'application', media: 'all',
'data-turbolinks-track': 'reload' %>
<%= javascript_include_tag 'application',
'data-turbolinks-track': 'reload' %>
<%= render 'layouts/shim' %>
</head>
<body>
<%= render 'layouts/header' %>
<div class="container">
<%= yield %>
<%= render 'layouts/footer' %> <!-- 추가한 footer partial -->
</div>
</body>
</html>
이대로 표시하면 편하지만 디자인이 썩 좋지 않기 때문에 스타일을 약간 조정해 보도록 하겠다.
/* app/assets/stylesheets/custom.css */
.
.
.
/* footer */
footer {
margin-top: 45px;
padding-top: 5px;
border-top: 1px solid #eaeaea;
color: #777;
}
footer a {
color: #555;
}
footer a:hover {
color: #222;
}
footer small {
float: left;
}
footer ul {
float: right;
list-style: none;
}
footer ul li {
float: left;
margin-left: 15px;
}
지금까지 작업한 내용을 화면에서 살펴보면 다음과 같다.
연습으로 레일즈가 생성하는 head 태그의 부분을 아래의 코드와 같이 render로 바꾸어보자. 우선 레이아웃 파일은 아래와 같이 수정된다.
<!-- app/views/layouts/application.html.erb -->
<!DOCTYPE html>
<html>
<head>
<title><%= full_title(yield(:title)) %></title>
<%= render 'layouts/rails_default' %>
<%= render 'layouts/shim' %>
</head>
<body>
<%= render 'layouts/header' %>
<div class="container">
<%= yield %>
<%= render 'layouts/footer' %>
</div>
</body>
</html>
그 후 해당 파셜에 들어갈 head 파일을 생성한 후 아래와 같이 작성한다. 화면에서 보이는 변화는 없지만 동작 구조는 달라졌다.
<!-- app/views/layouts/_rails_default.html.erb -->
<%= csrf_meta_tags %>
<%= stylesheet_link_tag 'application', media: 'all',
'data-turbolinks-track': 'reload' %>
<%= javascript_include_tag 'application',
'data-turbolinks-track': 'reload' %>
에셋 파이프라인(Asset Pipeline)
레일즈 개발자의 관점에서는 에셋 파이프라인에 대해 세 가지 주요한 기능을 이해할 필요가 있다. 바로 에셋 디렉터리, 매니페스트 파일, 프리프로세서 엔진이다.
에셋 디렉터리
레일즈의 에셋 파이프라인에는 정적파일을 용도별로 분류한 세 개의 표준 폴더가 있다.
- app/assests: 현재의 애플리케이션의 고유한 에셋
- lib/assets : 다른 개발팀에서 작성된 라이브러리용 에셋
- vender/assets: 서드파티용의 에셋
각 폴더는 다시 에셋 클래스의 하위 폴더를 가지고 있는데 예를 들어 app/assets의 경우 다음과 같이 이미지, Javascript, CSS 용의 서브 디렉터리가 있다. 이 설명을 토대로 보면 custom.scss 는 Sample 애플리케이션 고유의 에셋이기 때문에 app/assets/stylesheets에 저장한 것이다.
$ ls app/assets/
images/ javascripts/ stylesheets/
매니페스트 파일
정적 파일(에셋)을 폴더 별로 위치시켰다면 매니페스트 파일을 사용하여 정적 파일들을 어떻게 하나의 파일로 정리할지를 레일즈에게 알려주는 것이 가능하다. 이때 매니페스트 파일은 CSS와 JavaScript에는 적용되지만 이미지 파일에는 적용되지 않는다.
프리 프로세서 엔진
필요한 에셋을 폴더에 저장하면 레일즈는 매니페스트 파일을 사용하여 에셋을 하나로 묶은 다음 사이트 템플릿용으로 준비한다. 그 후 여러 프리 프로세서 엔진을 이용하여 에셋을 실행하고 브라우저에게 송신할 수 있도록 한다. 레일즈에서는 파일의 확장자를 기준으로 어떤 프리 프로세서를 사용할지 결정하는데 제일 일반적인 확장자는 Sass(*.scss), CoffeeScript(*.coffee), ERB(*.erb)이다. 아래와 같은 경우는 CoffeeScript 프로세서를 경유하여 실행된다.
footer.js.coffee
프리 프로세서 엔진은 연결하여 실행하는 것도 가능한데 아래와 같은 경우 CoffeeScript와 ERB 양쪽의 프로세서를 경유한다. 이때 코드의 오른쪽에서 왼쪽으로 실행되기 때문에 ERB보다 CoffeeScript 프로세서가 먼저 실행된다.
footer.js.erb.coffee
배포환경에서의 효율성
실제 배포 환경에서 애셋 파이프라인의 가장 큰 이점 중 하나는 애플리케이션의 효율적인 퍼포먼스를 위해 최적화된 에셋을 자동으로 생성해 주는 것이다. 이전에는 CSS와 JavaScript를 하나로 합치기 위해 파일을 기능별로 분리한 후 읽기 쉬운 포맷으로 정리하였다. 이러한 방식은 프로그래머에게는 편리하지만 실제 배포 환경에서는 비효율적이다. 게다가 파일을 여러 개로 나누면 UX에 많은 영향을 주는 읽어 들이는 시간까지 늦어진다. 에셋 파이프라인은 개발 효율과 읽어 들이는 시간 중 하나를 선택해야 하는 문제에서 벗어나게 해 준다. 개발환경에서는 프로그래머가 이해하기 쉽게 정리해 놓고 실제 배포 환경에서는 에셋 파이프라인을 사용하여 파일을 최소화하면 되는 것이다. 구체적으로는 에셋 파이프라인이 모든 스타일시트를 하나의 CSS 파일(application.css)로 정리하고 모든 JavaScript 파일을 하나의 JS 파일 (javascripts.js)로 정리해 준다. 심지어 해당 파일 전부에 대해 불필요한 공백이나 들여 쓰기를 정리해 주는 작업을 통해 파일 사이즈를 최소화시킨다. 결과적으로 에셋 파이프라인은 개발환경과 실제 배포 환경이라고 하는 상반된 상황에 대한 최적의 환경을 제공한다.
SASS
앞에서도 간단히 설명했지만 Sass는 SCSS라고 하는 포맷에 대응하는 언어이다. SCSS는 엄밀히 말하면 CSS 본체를 추상화한 포맷으로 CSS에 새로운 기능을 추가한 것이지 완전히 새로운 언어를 정의한 것은 아니다. 때문에 사용할 수 있는 CSS 파일은 전부 SCSS 파일로도 사용할 수 있다. 레일즈의 에셋 파이프라인은 .scss 확장자를 가진 파일을 Sass를 사용하여 자동적으로 처리한다. 때문에 custom.scss 파일은 Sass 프리 프로세서에 의해 처리 후 패키지화되어 브라우저로 보내진다. 이번 섹션에서는 Sass가 지원하는 2가지 중요한 기능인 네스트와 변수에 대해 소개하고자 한다. 세 번째의 중요한 기능인 Mix-in에 대해서는 7.1.1에서 소개하도록 하겠다.
네스트(Nest)
스타일시트 안에서 공통의 패턴을 가진 경우 요소를 네스트 시킬 수 있다. 아래의 코드에서 .center와 .center h1 양쪽에 스타일이 정의되어 있다.
.center {
text-align: center;
}
.center h1 {
margin-bottom: 10px;
}
Sass를 사용하면 위 코드를 다음과 같이 변경할 수 있다. 여기서 네스트의 안쪽에 있는 h1 요소는 .center의 스타일을 상속받고 있다.
.center {
text-align: center;
h1 {
margin-bottom: 10px;
}
}
이번에는 조금 다른 스타일에 대해 네스트 기능을 사용하는 예를 들어보겠다. 다음 코드에서는 #logo라고 하는 아이디가 2번 사용되고 있다. 첫 번째는 로고 자신을 정의하기 위한 것이고 두 번째는 hover 속성에 대해 정의하기 위해 사용된다. (hover 속성은 요소 위에 마우스를 올려놓고 있을 때 적용되는 속성이다.)
#logo {
float: left;
margin-right: 10px;
font-size: 1.7em;
color: #fff;
text-transform: uppercase;
letter-spacing: -1px;
padding-top: 9px;
font-weight: bold;
}
#logo:hover {
color: #fff;
text-decoration: none;
}
2개의 스타일을 네스트 하기 위해선 부모 속성인 #logo를 참조할 필요가 있다. 이 경우 SCSS에서는 다음과 같이 & 기호를 이용하여 표현할 수 있다. Sass는 SCSS를 CSS로 변환할 때 &:hover를 #logo:hover로 변환한다.
#logo {
float: left;
margin-right: 10px;
font-size: 1.7em;
color: #fff;
text-transform: uppercase;
letter-spacing: -1px;
padding-top: 9px;
font-weight: bold;
&:hover {
color: #fff;
text-decoration: none;
}
}
네스트 기능은 푸터의 스타일시트에도 적용해 보도록 하자.
footer {
margin-top: 45px;
padding-top: 5px;
border-top: 1px solid #eaeaea;
color: #777;
a {
color: #555;
&:hover {
color: #222;
}
}
small {
float: left;
}
ul {
float: right;
list-style: none;
li {
float: left;
margin-left: 15px;
}
}
}
변수
Sass에서는 길고 전통적인 코드는 버리고 자유로운 표현을 위해 변수를 정의할 수 있다. 위에서 보았던 CSS 코드들을 본다면 다음과 같이 동일한 색을 몇 번이고 반복하는 경우가 있다.
h2 {
.
.
.
color: #777;
}
.
.
.
footer {
.
.
.
color: #777;
}
#777은 옅은 잿빛을 띄는 색으로 Sass에서는 이러한 값을 변수로 정의하고 다음과 같이 변수명을 부여할 수도 있다.
$light-gray: #777;
변수를 사용하면 기존 SCSS를 다음과 같이 수정할 수 있다. 변수 이름은 색상 코드보다 색상을 유추하기 쉽고 중복되는 값에 대해 유연하게 처리할 수 있도록 해준다.
$light-gray: #777;
.
.
.
h2 {
.
.
.
color: $light-gray;
}
.
.
.
footer {
.
.
.
color: $light-gray;
}
네스트와 변수 기능을 사용해서 SCSS 파일을 새롭게 작성해 본다면 아래와 같은 코드가 된다. 이 코드에서는 변수를 적극적으로 활용하고 있다. Sass를 사용하여 현재보다 더 심플하게 작성하는 방법은 여러 가지가 있지만 현재는 그중에서 가장 중요도가 높은 기능을 위주로 적용해 보았다. 더 깊은 내용을 확인하고 싶다면 Sass 공식 사이트 방문을 추천한다.
/* app/assets/stylesheets/custom.scss */
@import "bootstrap";
/* mixins, variables, etc. */
$gray: #555;
$gray-light: #777;
$gray-darker: #222;
$gray-medium-light: #eaeaea;
/* universal */
section {
overflow: auto;
}
textarea {
resize: vertical;
}
.center {
text-align: center;
}
/* typography */
h1, h2, h3, h4, h5, h6 {
line-height: 1;
}
h1 {
font-size: 3em;
letter-spacing: -2px;
margin-bottom: 30px;
text-align: center;
}
h2 {
font-size: 1.2em;
letter-spacing: -1px;
margin-bottom: 30px;
text-align: center;
font-weight: normal;
color: $gray-light;
}
p {
font-size: 1.1em;
line-height: 1.7em;
}
/* header */
#logo {
float: left;
margin-right: 10px;
font-size: 1.7em;
color: white;
text-transform: uppercase;
letter-spacing: -1px;
padding-top: 5px;
font-weight: bold;
&:hover {
color: white;
text-decoration: none;
}
}
/* footer */
footer {
margin-top: 45px;
padding-top: 5px;
border-top: 1px solid $gray-medium-light;
color: $gray-light;
a {
color: $gray;
&:hover {
color: $gray-darker;
}
}
small {
float: left;
}
ul {
float: right;
list-style: none;
li {
float: left;
margin-left: 15px;
}
}
}
레이아웃의 링크
레일즈의 링크
지금부터는 앞에서 #으로 대체하고 있던 링크들을 실제 링크로 변경하는 작업을 하려고 한다. 일반적으로 다음과 같이 링크를 직접 기술하는 것도 가능하지만 이건 레일즈의 방식이 아니다. 일단 about 페이지로의 URL은 /static_pages/about 보다 /about인 것이 더 이상이다.
<a href="/static_pages/about">About</a>
게다가 레일즈에서는 링크에서 이름이 붙어 있는 경로를 사용할 수 있다. 다음과 같이 하는 것으로 코드가 무슨 뜻을 가지고 있는지 알기 쉽게 된다. 또한 about_path의 정의를 바꾸면 해당 값이 사용되는 모든 URL이 변경되기 때문에 코드의 유지보수 측면에서 유리하다.
<%= link_to "About", about_path %>
다음 표는 이후에 사용할 URL과 페이지 매핑을 정리한 것이니 참고하자.
페이지명 | URL | Path 이름 |
Home | / | root_path |
About | /about | about_path |
Help | /help | help_path |
Contact | /contact | contact_path |
Sign up | /signup | signup_path |
Log in | /login | login_path |
Contact 페이지
Contact라는 새로운 페이지를 추가해 보도록 하겠다. 실제 코드를 작성하기 전 테스트 코드를 먼저 작성하도록 하겠다.
# test/controllers/static_pages_controller_test.rb
require 'test_helper'
class StaticPagesControllerTest < ActionDispatch::IntegrationTest
.
.
.
test "should get about" do
get static_pages_about_url
assert_response :success
assert_select "title" , "About | #{@base_title}"
end
test "should get contact" do
get static_pages_contact_url
assert_response :success
assert_select "title" , "Contact | #{@base_title}"
end
end
rails test 명령어를 사용하여 테스틀 진행하면 결과는 실패일 것이다. 테스트를 성공시키기 위해 가장 먼저 라우트를 변경해 주도록 하겠다.
#config/routes.rb
Rails.application.routes.draw do
root 'static_pages#home'
get 'static_pages/home'
get 'static_pages/help'
get 'static_pages/about'
get 'static_pages/contact' #추가한 코드
end
그다음으로 contact 액션을 StaticPages 컨트롤러에 추가한다.
# app/controllers/static_pages_controller.rb
class StaticPagesController < ApplicationController
.
.
.
def contact
end
end
마지막으로 Contact 뷰를 작성한다.
<!-- app/views/static_pages/contact.html.erb -->
<% provide(:title, 'Contact') %>
<h1>Contact</h1>
<p>
Contact the Ruby on Rails Tutorial about the sample app at the
<a href="https://railstutorial.jp/contact">contact page</a>.
</p>
그 후 다시 한번 테스트를 수행하면 결과가 성공으로 바뀐 것을 확인할 수 있다.
레일즈의 Route URL
여기서는 이름이 달린 패스를 Sample 애플리케이션의 정적 페이지에 사용하기 위해 라우팅 파일을 수정해 보겠다. 우리는 지금까지 루트 URL을 정의하는 코드를 세 번 보았다. 다음 3개의 코드 모두 root 메서드를 사용하여 루트 URL "/"을 컨트롤러의 액션과 연결 지었다.
# Hello 애플리케이션의 코드
root 'application#hello'
# Toy 애플리케이션의 코드
root 'users#index'
# Sample 애플리케이션의 코드
root 'static_pages#home'
루트 URL과 같이 라우팅을 정의하면 브라우저의 접근이 쉬울 뿐 아니라 파일 그대로의 URL이 아닌 이름 달린 루트를 사용해서 URL을 참조하는 것이 가능하다. 예를 들어 루트 URL을 정의하면 root_path나 root_url 메서드를 사용하여 URL을 참조하는 것이 가능하다. 참고로 전자는 루트 URL 아래의 문자열을 후자는 완전한 URL의 문자열을 사용한다. 레일즈에서는 기본적으로 _path를 사용하고 리다이렉트 할 경우 HTTM 표준에서 완전한 URL이 필요하기 때문에 _url을 사용한다. 그러나 대부분의 브라우저에서는 양쪽 모두 정상적으로 동작한다.
root_path -> '/'
root_url -> 'http://www.example.com/'
그럼 다른 페이지들도 이름 달린 패스로 변경해 보자. 먼저 기존의 help 페이지는 다음과 같이 정의되어 있었다.
get 'static_pages/help'
위 코드를 아래와 같이 변경해 보자. 이렇게 get을 사용하여 변경하면 get 요청이 /help로 보내졌을 때 StaticPages 컨트롤러의 help 액션을 호출하게 된다.
get '/help', to: 'static_pages#help'
또한 루트 URL과 마찬가지로 help_path나 help_url 등과 같은 이름이 달린 패스도 사용할 수 있게 된다.
help_path -> '/help'
help_url -> 'http://www.example.com/help'
다른 정적 페이지에 대해서도 마찬가지로 라우팅을 변경하면 라우팅 파일은 아래와 같이 변경된다. 이때 home 페이지에 대한 경로는 제거하였는데 지금부터는 root 페이지로 통일하도록 하겠다.
# config/routes.rb
Rails.application.routes.draw do
root 'static_pages#home'
get '/help', to: 'static_pages#help'
get '/about', to: 'static_pages#about'
get '/contact', to: 'static_pages#contact'
end
현시점에서 테스트 코드를 돌리면 오류가 발생할 것이다 변경된 라우팅 설정에 따라 테스트 코드로 변경해 주자.
# test/controllers/static_pages_controllers_test.rb
require 'test_helper'
class StaticPagesControllerTest < ActionDispatch::IntegrationTest
def setup
@base_title = "Ruby on Rails Tutorial Sample App"
end
test "should get home" do
get root_path
assert_response :success
assert_select "title" , "#{@base_title}"
end
test "should get help" do
get help_path
assert_response :success
assert_select "title" , "Help | #{@base_title}"
end
test "should get about" do
get about_path
assert_response :success
assert_select "title" , "About | #{@base_title}"
end
test "should get contact" do
get contact_path
assert_response :success
assert_select "title" , "Contact | #{@base_title}"
end
end
이름이 붙은 Path
라우팅 설정을 변경함으로써 레이아웃 안에서 이름이 붙은 패스를 사용할 수 있게 되었다. link_to 메서드의 두 번째 파라미터에서 적절한 이름을 가진 패스를 사용해 보도록 하자. 예를 들어 #으로 연결되어 있던 About 페이지는 다음과 같이 수정할 수 있다.
<%= link_to "About", about_path %>
일단 맨 처음으로 header 파셜 _header.html.erb부터 수정해 보겠다. 이때 로그인 링크는 8장에서 작성할 예정이기 때문에 지금은 #으로 유지하겠다.
<!-- app/views/layouts/_header.html.erb -->
<header class="navbar navbar-dark bg-dark">
<div class="container">
<%= link_to "sample app", root_path, id: "logo" %>
<nav>
<ul class="nav justify-content-end">
<li class="nav-item"><%= link_to "Home", root_path, class: "nav-link" %></li>
<li class="nav-item"><%= link_to "Help", help_path, class: "nav-link" %></li>
<li class="nav-item"><%= link_to "Log in", '#', class: "nav-link" %></li>
</ul>
</nav>
</div>
</header>
footer 파셜 _footer.html.erb에도 About 페이지와 Contact 페이지로의 링크가 존재한다. 이름이 붙은 패스를 사용하도록 수정해 보자.
<!-- app/views/layouts/_footer.html.erb -->
<footer class="footer">
<small>
The <a href="https://railstutorial.jp/">Ruby on Rails Tutorial</a>
by <a href="http://www.michaelhartl.com/">Michael Hartl</a>
</small>
<nav>
<ul>
<li><%= link_to "About", about_path %></li>
<li><%= link_to "Contact", contact_path %></li>
<li><a href="http://news.railstutorial.org/">News</a></li>
</ul>
</nav>
</footer>
링크의 테스트
레이아웃 내부에서 수정한 링크가 정상적으로 동작하는지 확인하는 테스트 코드를 작성해 보겠다. 브라우저를 실행하여 수동으로 확인하는 것도 가능하겠지만 변경이 생길 때마다 해당 작업을 수동으로 반복하는 것은 큰 부담이다. 여기서는 통합(결합) 테스트(Intergration Test)를 사용하여 일련의 작업을 자동화해보도록 하겠다. 통합테스트를 사용하면 애플리케이션의 동작을 처음부터 끝까지(end-to-end) 시뮬레이션하는 것이 가능하다. 일단 다음 명령어를 통해 site_layout이라고 하는 테스트의 템플렛을 생성하자.
$ rails generate integration_test site_layout
invoke test_unit
create test/integration/site_layout_test.rb
이번 테스트의 목적은 애플리케이션의 HTML 구조를 알아보고 레이아웃의 각 링크가 제대로 동작하는지를 확인하는 것으로 구체적으로는 다음과 같다.
- 루트 URL(Home 페이지)에 GET 요청을 송신한다.
- 올바른 페이지 템플릿이 출력되는지 확인한다.
- Home, Help, About, Contact의 각 페이지로의 링크가 제대로 동작하는지 확인한다.
레일즈의 통합테스트에서는 위 과정을 코드로 작성할 수 있다. 일단 assert_template 메서드를 사용하여 Home페이지가 제대로 뷰를 출력하는지 확인한다.
# test/integration/site_layout_test.rb
require 'test_helper'
class SiteLayoutTest < ActionDispatch::IntegrationTest
test "layout links" do
get root_path
assert_template 'static_pages/home'
assert_select "a[href=?]", root_path, count: 2
assert_select "a[href=?]", help_path
assert_select "a[href=?]", about_path
assert_select "a[href=?]", contact_path
end
end
그리고 이전에 한번 등장했던 assert_select 메서드를 사용하고 있다. 이번에는 특정 링크가 존재하는지 확인하기 위해 a 태그와 herf 속성을 옵션으로 지정하고 있다. 예를 들어 아래 코드에서는 레일즈가 자동으로 물음표를 about_path로 변환하여 주고 about_path 내부의 특수 기호가 있다면 이스케이프 처리까지 해준다.
assert_select "a[href=?]", about_path
이를 통해 다음과 같은 HTML의 존재 여부를 확인할 수 있다.
<a href="/about">...</a>
한편 루트 URL로의 링크는 로고와 내비게이션바에 2개 존재하고 있다. 이럴 때는 아래와 같은 형태로 링크의 개수도 확인할 수 있다.
assert_select "a[href=?]", root_path, count: 2
참고로 assert_select는 여기서 전부 소개할 수 없을 정도로 많은 옵션을 가지고 있다. 그러나 경험 상 이 메서드를 이용하여 복잡한 테스트를 하는 것은 추천하지 않으며 이번처럼 레이아웃 내부에서 자주 변경되는 HTML 요소를 테스트하는 정도가 적당하다. 대표적인 지정 방법을 간단하게 소개하니 참고하도록 하자.
Code | 일치하는 HTML |
assert_select "div" | <div>foobar</div> |
assert_select "div", "foobar" | <div>foobar</div> |
assert_select "div.nav" | <div class="nav">foobar</div> |
assert_select "div#profile" | <div id="profile">foobar</div> |
assert_select "div[name=yo]" | <div name="yo">hey</div> |
assert_select "a[href=?]", ’/’, count: 1 | <a href="/">foo</a> |
assert_select "a[href=?]", ’/’, text: "foo" | <a href="/">foo</a> |
아래의 명령어를 통해 통합테스트 진행이 가능하다. 통합 테스트가 성공했다면 rails test 명령어를 통해 모든 테스트도 함께 진행해 보자.
rails test:integration
레이아웃의 링크를 테스트하는 통합테스트를 추가한 것으로 링크의 수정이 잘못되었을 때는 바로 알아채릴 수 있게 되었다.
User의 등록
이번 섹션에서는 레이아웃과 라우팅의 조합을 중점으로 하여 사용자 등록페이지로의 라우팅을 작성하겠다. 이를 위해 새로운 컨트롤러를 생성할 필요가 있다. 구체적인 모델링은 6장에서 다루며 7장에서 등록 기능을 완성할 것이니 참고하자.
User Controller
전과 마찬가지로 generate 명령어를 사용하여 사용자 등록 페이지를 가지는 간단한 컨트롤러를 작성한다. 이때 레일즈에서 권장되는 REST 아키텍처에 따라서 신규 사용자 등록용의 액션 new를 만들 것이다. 따라서 generate controller의 파라미터로 new를 입력하여 자동적으로 액션을 생성할 수 있게 하겠다.
$ rails generate controller Users new
create app/controllers/users_controller.rb
route get 'users/new'
invoke erb
create app/views/users
create app/views/users/new.html.erb
invoke test_unit
create test/controllers/users_controller_test.rb
invoke helper
create app/helpers/users_helper.rb
invoke test_unit
invoke assets
invoke coffee
create app/assets/javascripts/users.coffee
invoke scss
create app/assets/stylesheets/users.scss
실행결과에서 알 수 있듯이 new 액션을 가지는 User 컨트롤러와 더미용 유저 뷰를 아래와 같이 작성해 주었다. 이때 새로운 페이지를 위한 간단한 테스트도 생성되는데 실행해 본다면 통과할 것이다.
# app/controllers/user_controller.rb
class UsersController < ApplicationController
def new
end
end
<!-- app/views/users/new.html.erb -->
<h1>Users#new</h1>
<p>Find me in app/views/users/new.html.erb</p>
# test/controllers/users_controller_test.rb
require 'test_helper'
class UsersControllerTest < ActionDispatch::IntegrationTest
test "should get new" do
get users_new_url
assert_response :success
end
end
사용자 등록용 URL
generate 명령어를 통해 신규 사용자 등록용 페이지인 /users/new가 생성되었으나 해당 URL을 /signup으로 변경하고 이름이 붙은 패스를 사용할 수 있도록 수정하겠다.
# config/routes.rb
Rails.application.routes.draw do
root 'static_pages#home'
get '/help', to: 'static_pages#help'
get '/about', to: 'static_pages#about'
get '/contact', to: 'static_pages#contact'
get '/signup', to: 'users#new' #new
end
라우팅 설정 변경에 맞춰 테스트코드도 수정해 주자.
# test/controllers/users_controller_test.rb
require 'test_helper'
class UsersControllerTest < ActionDispatch::IntegrationTest
test "should get new" do
get signup_path #update
assert_response :success
end
end
다음으로 새롭게 정의한 Signup 페이지의 이름 달린 패스를 사용하여 Home 페이지의 더미 링크를 변경하도록 하겠다.
<!-- app/views/static_pages/home.html.erb -->
<div class="center jumbotron">
<h1>Welcome to the Sample App</h1>
<h2>
This is the home page for the
<a href="https://railstutorial.jp/">Ruby on Rails Tutorial</a>
sample application.
</h2>
<%= link_to "Sign up now!", signup_path, class: "btn btn-lg btn-primary" %> <!-- new -->
</div>
<%= link_to image_tag("rails.png", alt: "Rails logo"),
'http://rubyonrails.org/' %>
마지막으로 Signup 페이지의 뷰를 수정하도록 하겠다.
<!-- app/views/users/new.html.erb -->
<% provide(:title, 'Sign up') %>
<h1>Sign up</h1>
<p>This will be a signup page for new users.</p>
지금까지의 내용을 화면에서 확인해 보면 아래와 같다.
브랜치 머지
다음 장으로 넘어가기 변경 내역을 커밋(Commit)하고 마스터 브랜치(Master branch)에 머지(Merge)하도록 하겠다.
$ git add -A
$ git commit -m "Finish layout and routes"
$ git checkout master
$ git merge filling-in-layout
습관적으로 원격 레포지토리에 푸시(Push)를 하거나 배포하기 전에 테스트 코드를 실행하여 기존 동작에 영향이 없는지 확인해 보도록 하자.
$ rails test
글을 마치며
5장에서는 아래와 같은 내용을 배울 수 있었다.
- HTML5를 사용하여 header나 footer, logo나 body 등의 콘텐츠의 레이아웃을 정의해 보았다.
- 레일즈의 파셜은 효율적인 작업을 위해 다른 파일에 코드를 분리할 수 있다.
- CSS는 클래스와 아이디를 사용하여 레이아웃이나 디자인을 조정할 수 있다.
- Bootstrap 프레임워크를 사용하면 좋은 디자인을 빠르게 만들 수 있다.
- Sass와 Asset Pipeline은 개발 효율을 위해 분리한 파일을 압축하여 실제 배포환경에 최적화한 결과를 출력해 준다.
- 레일즈의 라우팅은 자유롭게 정의할 수 있으며 그때 이름이 달린 패스를 설정할 수도 있다.
- 통합 테스트는 브라우저에 의한 페이지 간의 이동을 효율적으로 시뮬레이션해볼 수 있다.
오늘 작성한 코드 또한 아래 GitHub에서 확인할 수 있으니 참고 바란다.
참고 자료 및 사이트
- https://www.railstutorial.org/
- https://github.com/Yoodahun/Rails_Tutorials_Translation
- https://github.com/twbs/bootstrap-rubygem