2021-01-04(Mon)

ํ•ญ๋ชฉ

๋‚ด์šฉ

ํ•™์Šต ๋‚ ์งœ

2021-01-04(์›”)

ํ•™์Šต ์‹œ๊ฐ„

12:00~24:00

ํ•™์Šต ๋ฒ”์œ„ ๋ฐ ์ฃผ์ œ

๋ฃจ๋น„์˜จ๋ ˆ์ผ์ฆˆ ๋ผ์šฐํŒ…, ํ…Œ์ŠคํŠธ

ํ•™์Šต ๋ชฉํ‘œ

ํผํŽ™ํŠธ ๋ฃจ๋น„์˜จ๋ ˆ์ผ์ฆˆ ๋ผ์šฐํŒ…, ํ…Œ์ŠคํŠธ ์ฑ•ํ„ฐ๋ฅผ ๋…ํŒŒํ•œ๋‹ค.

๋™๋ฃŒ ํ•™์Šต ๋ฐฉ๋ฒ•

-

์ƒ์„ธ ํ•™์Šต ๋‚ด์šฉ

์ฑ…์„ ํ›‘์œผ๋ฉฐ ์•„๋ž˜์ฒ˜๋Ÿผ ๊ฐ„๋‹จํ•˜๊ฒŒ ๋ฉ”๋ชจ๋ฅผ ์ง„ํ–‰ํ–ˆ๋‹ค.

๋ผ์šฐํŒ…

RESTful ์ธํ„ฐํŽ˜์ด์Šค

RESTful ์ธํ„ฐํŽ˜์ด์Šค๋Š” REST์˜ ํŠน์ง•์„ ๊ฐ€์ง„ ๋ผ์šฐํŠธ๋ฅผ ๋งํ•œ๋‹ค. REST๋Š” HTTP ๋ฉ”์„œ๋“œ์™€ CRUD๋ฅผ ๋Œ€์‘์‹œํ‚ค๋Š” ๊ฒƒ์ด๋ผ ์ƒ๊ฐํ•˜๋ฉด ๋œ๋‹ค.

  • ์ถ”์ถœ: GET

  • ์ƒ์„ฑ: POST

  • ๋ณ€๊ฒฝ: PATCH

  • ์ œ๊ฑฐ: DELETE

Rails๋Š” ์›์น™์ ์œผ๋กœ RESTful ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ๋ผ์šฐํŠธ๋ฅผ ์„ค๊ณ„ํ•œ๋‹ค. ๋น„RESTful์ ์ธ ๋ผ์šฐํŠธ๋ฅผ ์„ค์ •ํ•  ์ˆ˜๋„ ์žˆ์ง€๋งŒ, Rails์—์„œ ์ œ๊ณตํ•˜๋Š” form_for, url_for, link_to ๋“ฑ์˜ ๋ทฐ ํ—ฌํผ๋Š” RESTful ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์ „์ œ๋กœ ์„ค๊ณ„๋˜์–ด ์žˆ์œผ๋ฏ€๋กœ ์™ ๋งŒํ•˜๋ฉด RESTful์ ์ธ ๋ผ์šฐํŠธ๋ฅผ ์‚ฌ์šฉํ•˜์ž.

resources ๋ฉ”์„œ๋“œ

RESTful ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์ •์˜ํ•  ๋•Œ๋Š” routes.rb์—์„œ resources ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•œ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด ์•„๋ž˜ ์ฝ”๋“œ๋ฅผ ์ ์œผ๋ฉด ์•„๋ž˜ ํ‘œ์ฒ˜๋Ÿผ URL๋กœ ์•ก์…˜์ด ๋งคํ•‘๋œ๋‹ค.

Railbook::Application.routes.draw do
  resources :users
  ...
end

URL

์•ก์…˜

HTTP ๋ฉ”์„œ๋“œ

์—ญํ• 

/users(.:format)

index

GET

์‚ฌ์šฉ์ž ๋ชฉ๋ก ์ƒ์„ฑ

/users/:id(.:format)

show

GET

๊ฐ๊ฐ์˜ ์‚ฌ์šฉ์ž ์ƒ์„ธ ํ™”๋ฉด ์ƒ์„ฑ

/users/new(.:format)

new

GET

์‹ ๊ทœ ์‚ฌ์šฉ์ž ์ถ”๊ฐ€ ํ™”๋ฉด ์ƒ์„ฑ

/users(.:format)

create

POST

์‹ ๊ทœ ์‚ฌ์šฉ์ž ํ™”๋ฉด์œผ๋กœ๋ถ€ํ„ฐ์˜ ์ž…๋ ฅ์„ ๋ฐ›์•„ ๋“ฑ๋ก ์ฒ˜๋ฆฌ

/users/:id/edit(.:format)

edit

GET

๊ธฐ์กด์˜ ์‚ฌ์šฉ์ž ํŽธ์ง‘ ํ™”๋ฉด ์ƒ์„ฑ

/users/:id(.:format)

update

PATCH/PUT

ํŽธ์ง‘ ํ™”๋ฉด์œผ๋กœ๋ถ€ํ„ฐ ์ž…๋ ฅ์„ ๋ฐ›์•„ ์ˆ˜์ • ์ฒ˜๋ฆฌ

/users/:id(.:format)

destory

DELETE

๋ชฉ๋ก ํ™”๋ฉด์—์„œ ์„ ํƒํ•œ ๋ฐ์ดํ„ฐ ์ œ๊ฑฐ ์ฒ˜๋ฆฌ

๋˜ํ•œ resources ๋ฉ”์„œ๋“œ๋Š” ๋ทฐ ํ—ฌํผ(link_to ๋“ฑ)์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” Url ํ—ฌํผ๋„ ์ž๋™์œผ๋กœ ์ƒ์„ฑํ•œ๋‹ค.

ํ—ฌํผ ์ด๋ฆ„(_path)

ํ—ฌํผ ์ด๋ฆ„(_url)

๋ฆฌํ„ด ๊ฐ’(๊ฒฝ๋กœ)

users_path

users_url

/users

user_path(id)

user_url(id)

/users/:id

new_user_path

new_user_url

/users/new

edit_user_path(id)

edit_user_url(id)

/users/:id/edit

์ด๋Ÿฌํ•œ ํ—ฌํผ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋งํฌ๋ฅผ ๋ณด๋‹ค ์ง๊ด€์ ์œผ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์€ ๋ฌผ๋ก , ๋ผ์šฐํŠธ ์ •์˜์— ์˜์กดํ•˜์ง€ ์•Š์„ ์ˆ˜๋„ ์žˆ๋‹ค.

resource ๋ฉ”์„œ๋“œ

resources ๋ฉ”์„œ๋“œ๊ฐ€ ์—ฌ๋Ÿฌ ๊ฐœ์˜ ๋ฆฌ์†Œ์Šค๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” RESTful ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์ƒ์„ฑํ•œ๋‹ค๋ฉด, resource ๋ฉ”์„œ๋“œ๋Š” ํ•˜๋‚˜์˜ ๋ฆฌ์†Œ์Šค๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” RESTful ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด ์•„๋ž˜ ์ฝ”๋“œ๋ฅผ ์ ์œผ๋ฉด ์•„๋ž˜ ํ‘œ์ฒ˜๋Ÿผ URL๋กœ ์•ก์…˜์ด ๋งคํ•‘๋œ๋‹ค.

Railbook::Application.routes.draw do
  resource :config
  ...
end

URL

์•ก์…˜

HTTP ๋ฉ”์„œ๋“œ

์—ญํ• 

/config(.:format)

show

GET

์„ค์ • ์ •๋ณด ํ™”๋ฉด ํ‘œ์‹œ ์ƒ์„ธ ํ™”๋ฉด ์ƒ์„ฑ

/config/new(.:format)

new

GET

์‹ ๊ทœ ์„ค์ • ์ถ”๊ฐ€ ํ™”๋ฉด ์ƒ์„ฑ

/config(.:format)

create

POST

๋“ฑ๋ก ํ™”๋ฉด์—์„œ ์ž…๋ ฅ์„ ๋ฐ›์•„ ๋“ฑ๋ก ์ฒ˜๋ฆฌ

/config/edit(.:format)

edit

GET

๊ธฐ์กด ์„ค์ • ์ˆ˜์ • ํ™”๋ฉด ํ‘œ์‹œ

/config(.:format)

update

PATCH/PUT

์ˆ˜์ • ํ™”๋ฉด์—์„œ ์ž…๋ ฅ์„ ๋ฐ›์•„ ์ˆ˜์ • ์ฒ˜๋ฆฌ

/config(.:format)

destroy

DELETE

์ง€์ •๋œ ์„ค์ • ์ •๋ณด๋ฅผ ์ œ๊ฑฐ ์ฒ˜๋ฆฌ

resources ๋ฉ”์„œ๋“œ์™€ ๋น„์Šทํ•˜์ง€๋งŒ, index ์•ก์…˜์ด ์ •์˜๋˜์ง€ ์•Š์•˜์œผ๋ฏ€๋กœ show, edit, delete ๋“ฑ์—์„œ :id๋ฅผ ๋งค๊ฐœ ๋ณ€์ˆ˜๋กœ ๋ฐ›์ง€ ์•Š๋Š”๋‹ค๋Š” ์ ์ด ๋‹ค๋ฅด๋‹ค.

  • ์ฐธ๊ณ 1) resource ๋ฉ”์„œ๋“œ๋„ config ๋ฆฌ์†Œ์Šค๊ฐ€ ConfigsController๋กœ ๋งคํ•‘๋œ๋‹ค.

  • ์ฐธ๊ณ 2) http://localhost:3000/rails/info/routes๋กœ ์ ‘๊ทผํ•˜๋ฉด ๋ธŒ๋ผ์šฐ์ €๋กœ๋„ ๋ผ์šฐํŠธ ์ •์˜๋ฅผ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

RESTful ์ธํ„ฐํŽ˜์ด์Šค์˜ ์‚ฌ์šฉ์ž ์ •์˜ํ™”

resources, resource ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด RESTfulํ•œ ์ •ํ˜•์ ์ธ ๋ผ์šฐํŠธ๋ฅผ ์ž๋™์œผ๋กœ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค. ํ•˜์ง€๋งŒ ์‹ค์ œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๋งŒ๋“ ๋‹ค๋ฉด ํ‘œ์ค€์ ์ธ ๊ทœ์น™๋งŒ์œผ๋กœ๋Š” ๋ชจ๋“  ๊ฒƒ์„ ๊ตฌํ˜„ํ•  ์ˆ˜ ์—†์œผ๋ฏ€๋กœ ์ค‘์š”ํ•œ ์˜ต์…˜๋“ค์ด ๋ญ๊ฐ€ ์žˆ๋Š”์ง€๋Š” ํ™•์ธํ•ด๋‘˜ ํ•„์š”๊ฐ€ ์žˆ๋‹ค.

๋ผ์šฐํŠธ ๋งค๊ฐœ ๋ณ€์ˆ˜ ์ œ์•ฝ ์กฐ๊ฑด - contraints ์˜ต์…˜

์‚ฌ์‹ค ๋ผ์šฐํŠธ ๋งค๊ฐœ ๋ณ€์ˆ˜์™€ ๊ด€๋ จ๋œ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ๋Š” ๋ชจ๋ธ์—์„œ ํ•˜๋Š” ๊ฒƒ์ด ๊ธฐ๋ณธ์ด์ง€๋งŒ, ๋ผ์šฐํŠธ์—์„œ ์ฒ˜๋ฆฌํ•˜๋ฉด ์›์น˜ ์•Š๋Š” ๊ฐ’์„ ๋ณด๋‹ค ํ™•์‹คํ•˜๊ฒŒ ์ฐจ๋‹จํ•  ์ˆ˜ ์žˆ๋‹ค.

constraints: { <๋งค๊ฐœ ๋ณ€์ˆ˜ ์ด๋ฆ„>: <์ •๊ทœ ํ‘œํ˜„์‹> } ํ˜•ํƒœ๋กœ ๋ผ์šฐํŠธ ๋งค๊ฐœ ๋ณ€์ˆ˜์˜ ์ œ์•ฝ ์กฐ๊ฑด์„ ์ง€์ •ํ•  ์ˆ˜ ์žˆ๋‹ค. ์•„๋ž˜์ฒ˜๋Ÿผ!

Railbook::Application.routes.draw do
  resources :books, constraints: { id: /[0-9]{1,2}/ }
  ...
end

์—ฌ๋Ÿฌ ๊ฐœ์˜ ๋ฆฌ์†Œ์Šค์— ๋™์ผํ•œ ์ œ์•ฝ ์กฐ๊ฑด์„ ๋ถ€์—ฌํ•  ๋•Œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋ธ”๋ก ํ˜•์‹์œผ๋กœ ์ œ์•ฝ ์กฐ๊ฒ…๋Š˜ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค.

constraints(id: /[0-9]{1,2}/) do
  resources :books
  resources :reviews
end

๋ณต์žกํ•œ ์ œ์•ฝ ์กฐ๊ฑด ์„ค์ • - ์ œ์•ฝ ํด๋ž˜์Šค ์ •์˜

์ •๊ทœ ํ‘œํ˜„์‹๋งŒ์œผ๋กœ๋Š” ํ‘œํ˜„ํ•  ์ˆ˜ ์—†๋Š” ๋ณต์žกํ•œ ์ œ์•ฝ ์กฐ๊ฑด์„ ์„ค์ •ํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด ์ œ์•ฝ ํด๋ž˜์Šค๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋œ๋‹ค. ์ œ์•ฝ ํด๋ž˜์Šค์— ์กฐ๊ฑด์„ ๋งŒ๋“ค ๋•Œ๋Š” matches? ๋ฉ”์„œ๋“œ๋ฅผ ๋งŒ๋“ค์–ด์ฃผ๊ธฐ๋งŒ ํ•˜๋ฉด ๋œ๋‹ค.

matches? ๋ฉ”์„œ๋“œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๊ทœ์น™์„ ์ง€์ผœ์•ผํ•œ๋‹ค.

  • ๋งค๊ฐœ ๋ณ€์ˆ˜๋กœ ์š”์ฒญ ์ •๋ณด(request ๊ฐ์ฒด)๋ฅผ ๋ฐ›์Œ.

  • ๋ฆฌํ„ด ๊ฐ’์œผ๋กœ๋Š” ๋ผ์šฐํŠธ๋ฅผ ์œ ํšจํ™”ํ• ์ง€์— ๋Œ€ํ•œ true ๋˜๋Š” false๋ฅผ ๋ฆฌํ„ด

์˜ˆ์‹œ๋ฅผ ๋ณด์ž. ์•„๋ž˜์ฒ˜๋Ÿผ ์ œ์•ฝ ํด๋ž˜์Šค๋ฅผ ์ •์˜ํ–ˆ๋‹ค๋ฉด,

class TimeConstaint
  def matches?(request)
    current = Time.now
    current.hour >= 9 && current.hour < 18
  end
end

์•„๋ž˜์ฒ˜๋Ÿผ ์ œ์•ฝ ํด๋ž˜์Šค๋ฅผ ๋ถˆ๋Ÿฌ์™€์„œ constraint ์˜ต์…˜์œผ๋กœ ์ „๋‹ฌ๋งŒ ํ•ด์ฃผ๋ฉด ๋œ๋‹ค.

require 'TimeConstraint'
โ€‹
Railbook::Application.routes.draw.do
  resources :books, constraints: TimeConstraint.new
  ...
end

form ๋งค๊ฐœ ๋ณ€์ˆ˜ ์ œ๊ฑฐ - form ์˜ต์…˜

resources์™€ resource ๋ฉ”์„œ๋“œ๋กœ ์ •์˜๋œ ๋ชจ๋“  ๋ผ์šฐํŠธ๋Š” ~(.:format)์ด ๋ถ™์–ด์žˆ๋‹ค. ๋”ฐ๋ผ์„œ ~books.xml ๋˜๋Š” ~/books.json์ฒ˜๋Ÿผ ์ถœ๋ ฅ ํ˜•์‹์„ ํ™•์žฅ์ž ํ˜•ํƒœ๋กœ ์ง€์ •ํ•  ์ˆ˜๋„ ์žˆ๋‹ค.

ํ•˜์ง€๋งŒ ๋ฆฌ์†Œ์Šค์— ๋”ฐ๋ผ์„œ๋Š” ์—ฌ๋Ÿฌ ํ˜•์‹์— ๋Œ€์‘ํ•˜์ง€ ์•Š์„ ์ˆ˜๋„ ์žˆ๋‹ค. ์ด๋Ÿฐ ๊ฒฝ์šฐ์—” format ์˜ต์…˜์„ false๋กœ ์ง€์ •ํ•˜์ž. ๊ทธ๋Ÿผ URL ํŒจํ„ด์—์„œ ~(.:format)์ด ์ œ๊ฑฐ๋œ ๋ผ์šฐํŠธ๊ฐ€ ์ƒ์„ฑ๋œ๋‹ค.

์ปจํŠธ๋กค๋Ÿฌ ํด๋ž˜์Šค์™€ Url ํ—ฌํผ์˜ ์ด๋ฆ„ ์ˆ˜์ • - controller์™€ as ์˜ต์…˜

resources์™€ resource ๋ฉ”์„œ๋“œ๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ ์ง€์ •๋œ ๋ฆฌ์†Œ์Šค ์ด๋ฆ„์„ ๊ธฐ๋ฐ˜์œผ๋กœ ๋Œ€์‘๋˜๋Š” ์ปจํŠธ๋กค๋Ÿฌ๋ฅผ ๊ฒฐ์ •ํ•˜๊ณ  Url ํ—ฌํผ๋ฅผ ์ƒ์„ฑํ•œ๋‹ค.

๋ชจ๋“ˆ ๋‚ด๋ถ€์˜ ์ปจํŠธ๋กค๋Ÿฌ๋ฅผ ๋งตํ•‘ - namespace์™€ scope ๋ธ”๋ก

์ปจํŠธ๋กค๋Ÿฌ ํด๋ž˜์Šค์˜ ์ˆ˜๊ฐ€ ๋งŽ์•„์ง€๋ฉด ๋ชจ๋“ˆ์„ ์‚ฌ์šฉํ•ด ์ปจํŠธ๋กค๋Ÿฌ๋ฅผ ํด๋”๋กœ ์ •๋ฆฌํ•˜๊ณ  ์‹ถ์€ ๊ฒฝ์šฐ๊ฐ€ ์žˆ์„ ๊ฒƒ์ด๋‹ค. ์•„๋ž˜์ฒ˜๋Ÿผ ์ปจํŠธ๋กค๋Ÿฌ ํด๋ž˜์Šค๋ฅผ ์ƒ์„ฑํ•˜๋ฉด ๋œ๋‹ค.

rails generate controller Admin::Books

์ด๋ ‡๊ฒŒ ํ•˜๋ฉด Admin::BooksController๊ฐ€ controllers/admin ํด๋” ์•„๋ž˜์— books_controller.rb๋ผ๋Š” ์ด๋ฆ„์œผ๋กœ ์ƒ์„ฑ๋œ๋‹ค.

์ด๋ ‡๊ฒŒ ๋ชจ๋“ˆ๋กœ ์ปจํŠธ๋กค๋Ÿฌ ํด๋ž˜์Šค๋ฅผ ์ƒ์„ฑํ•  ๊ฒฝ์šฐ์—๋Š” ํ…œํ”Œ๋ฆฟ์„ /views/<๋ชจ๋“ˆ ์ด๋ฆ„>/<์ปจํŠธ๋กค๋Ÿฌ ์ด๋ฆ„>ํด๋”์— ๋„ฃ์œผ๋ฉด ๋œ๋‹ค.

์ด์ฒ˜๋Ÿผ ๋ชจ๋“ˆ์„ ์‚ฌ์šฉํ•œ ์ปจํŠธ๋กค๋Ÿฌ ํด๋ž˜์Šค์— RESTful ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์ •์˜ํ•˜๋ ค๋ฉด ์•„๋ž˜์ฒ˜๋Ÿผ namespace ๋ธ”๋ก์„ ์‚ฌ์šฉํ•˜๋ฉด ๋œ๋‹ค. ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด /admin/books ๋˜๋Š” /admin/books/:id์™€ ๊ฐ™์€ URL ํŒจํ„ด๊ณผ, admin_books_path ๋˜๋Š” admin_book_path(id)์™€ ๊ฐ™์€ URL ํ—ฌํผ๊ฐ€ ์ƒ์„ฑ๋œ๋‹ค.

namespace :admin do
  resources :books
end

๋งŒ์•ฝ์— ๋ชจ๋“ˆ์„ ์ธ์‹๋งŒ ํ•˜๊ณ  URL ํŒจํ„ด๊ณผ URL ํ—ฌํผ์—๋Š” ์˜ํ–ฅ์„ ์ฃผ๊ณ  ์‹ถ์ง€ ์•Š์€ ๊ฒฝ์šฐ์—๋Š” ์•„๋ž˜์ฒ˜๋Ÿผ scope ๋ธ”๋ก์„ ์‚ฌ์šฉํ•˜๋ฉด ๋œ๋‹ค.

scope module: :admin do
  resources :books
end

RESTful ์ธํ„ฐํŽ˜์ด์Šค์— ์•ก์…˜ ์ถ”๊ฐ€ - collection๊ณผ member ๋ธ”๋ก

collection๊ณผ member ๋ธ”๋ก์„ ์‚ฌ์šฉํ•˜๋ฉด resources์™€ resource ๋ฉ”์„œ๋“œ๋กœ ์ž๋™ ์ƒ์„œ๋˜๋Š” ๋ผ์šฐํŠธ ์™ธ์— ์›ํ•˜๋Š” ์•ก์…˜์„ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ๋‹ค.

resources :name do
  [collection do
    method action
    ...
  end]
  [member do
    method action
    ...
  end]
end

collection ๋ธ”๋ก์€ ์—ฌ๋Ÿฌ ๊ฐ์ฒด๋ฅผ ๋‹ค๋ฃจ๋Š” ์•ก์…˜์„, member ๋ธ”๋ก์€ ํ•˜๋‚˜์˜ ๊ฐ์ฒด๋ฅผ ๋‹ค๋ฃจ๋Š” ์•ก์…˜์„ ๋งŒ๋“ค ๋•Œ ์‚ฌ์šฉํ•œ๋‹ค.

RESTful ์ธํ„ฐํŽ˜์ด์Šค์˜ ์•ก์…˜์„ ๋ฌดํšจํ™” - only์™€ except ์˜ต์…˜

collection, member ๋ธ”๋ก๊ณผ ๋ฐ˜๋Œ€๋กœ ๊ธฐ๋ณธ์ ์œผ๋กœ ์ƒ์„ฑ๋˜๋Š” ์•ก์…˜์˜ ์ผ๋ถ€๋ฅผ ๋ฌดํšจํ™”ํ•˜๊ณ  ์‹ถ์„ ๋•Œ๋Š” only ๋˜๋Š” except ์˜ต์…˜์„ ์ง€์ •ํ•œ๋‹ค.

๋ผ์šฐํŠธ ์ •์˜๋ฅผ ์ถ”๊ฐ€ ๋˜๋Š” ๋ฌดํšจํ™”ํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ ํ‘œ์ค€ ์•ก์…˜์ธ new ์•ก์…˜, edit ์•ก์…˜๊ณผ ๊ด€๋ จ๋œ URL์„ ๋ณ€๊ฒฝํ•˜๊ณ  ์‹ถ์€ ๊ฒฝ์šฐ์—๋Š” :path_names ์˜ต์…˜์„ ์ง€์ •ํ•œ๋‹ค.

๊ณ„์ธต ๊ตฌ์กฐ๋ฅผ ๊ฐ€์ง„ ๋ฆฌ์†Œ์Šค ํ‘œํ˜„ - resources ๋ฉ”์„œ๋“œ ์ค‘์ฒฉ

๋ฆฌ์†Œ์Šค๋“ค์ด ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋‚ด๋ถ€์—์„œ ๊ณ„์ธต ๊ด€๊ณ„๋ฅผ ๊ฐ–๋Š” ๊ฒฝ์šฐ๊ฐ€ ์žˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, books ๋ฆฌ์†Œ์Šค(๋„์„œ ์ •๋ณด)๋Š” reviews ๋ฆฌ์†Œ์Šค(๋„์„œ ๋ฆฌ๋ทฐ)๋ฅผ ํฌํ•จํ•œ๋‹ค. ์ด๋Ÿฌํ•œ ๋ฆฌ์†Œ์Šค ๊ณ„์ธต ๊ด€๊ณ„๋Š” has_many ๋˜๋Š” belongs_to ๋“ฑ์˜ ๋ชจ๋ธ Association์œผ๋กœ ๋‚˜ํƒ€๋‚ธ๋‹ค.

์ด๋Ÿฌํ•œ ๋ฆฌ์†Œ์Šค(๋ชจ๋ธ)์˜ ๊ด€๊ณ„๋Š” URL๋กœ๋„ ํ‘œํ˜„ํ•ด์ฃผ๋Š” ๊ฒƒ์ด ์ง๊ด€์ ์ด๋‹ค. ๊ฐ€๋ น ๋„์„œ1์˜ ๋ฆฌ๋ทฐ ์ •๋ณด๋Š” ~/books/1/reviews์ฒ˜๋Ÿผ ๋‚˜ํƒ€๋‚ด๋Š” ๊ฒƒ์ด ์ข‹๋‹ค.

์ด๋Ÿฌํ•œ ๊ด€๊ณ„๋Š” resources์™€ resource ๋ฉ”์„œ๋“œ๋ฅผ ์ค‘์ฒฉํ•ด์„œ ๋‚˜ํƒ€๋‚ธ๋‹ค.

resources :books do
  resources :reviews
end

์ด๋Ÿฌ๋ฉด URL ํ—ฌํผ์— book_์ด๋ผ๋Š” ์ ‘๋‘์‚ฌ๊ฐ€ ๋ถ™๋Š”๋‹ค. resources์™€ resource ๋ฉ”์„œ๋“œ๋Š” ๊ณ„์†ํ•ด์„œ ์ค‘์ฒฉํ•  ์ˆ˜ ์žˆ์ง€๋งŒ, ๊ณ„์ธต์€ 2๋‹จ๊ณ„ ๊นŒ์ง€๋งŒ ๋งŒ๋“œ๋Š” ๊ฒƒ์ด ๋ฌด๋‚œํ•˜๋‹ค.

๋ฆฌ์†Œ์Šค์˜ ์–•์€ ์ค‘์ฒฉ ํ‘œํ˜„ - shallow ์˜ต์…˜

์•„๋ž˜์ฒ˜๋Ÿผ shallow ์˜ต์…˜์„ ์“ฐ๋ฉด '์–•์€ URL'์ด ์ƒ์„ฑ๋œ๋‹ค.

resources :books do
  resources :reviews, shallow: true
end

๋ผ์šฐํŠธ ์ •์˜ ์žฌ์ด์šฉ - concern ๋ฉ”์„œ๋“œ์™€ concerns ์˜ต์…˜

concern ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๊ณตํ†ต๋˜๋Š” ๋‚ด์šฉ์„ ์—ฌ๋Ÿฌ ๊ฐœ์˜ ๋ผ์šฐํŠธ ์ •์˜์— ๋„ฃ์„ ์ˆ˜ ์žˆ๋‹ค.

RESTful ํ•˜์ง€ ์•Š์€ ๋ผ์šฐํŠธ ์ •์˜

๋ชจ๋“  ๊ฒƒ์„ RESTfulํ•˜๊ฒŒ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์€ ์•„๋‹ˆ๋‹ค. ์ด๋Ÿด ๋• ๋ฌด๋ฆฌํ•ด์„œ RESTful ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์ ์šฉํ•˜๋ ค ๋“ค์ง€ ๋ง๊ณ , ๊ฐ„๋‹จํ•˜๊ฒŒ RESTful ํ•˜์ง€ ์•Š์€ ๋ผ์šฐํŠธ๋ฅผ ์ •์˜ํ•ด๋ณด์ž.

match ๋ฉ”์„œ๋“œ

RESTful ํ•˜์ง€ ์•Š์€ ๋ผ์šฐํŠธ๋ฅผ ์ •์˜ํ•  ๋•Œ๋Š” match ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.

via ์˜ต์…˜์—๋Š” ํŠน๋ณ„ํ•œ ๊ฐ’์œผ๋กœ :all(๋ชจ๋“  HTTP ๋ฉ”์„œ๋“œ ํ—ˆ์šฉ)์„ ์ง€์ •ํ•  ์ˆ˜๋„ ์žˆ๋‹ค. ํ•˜์ง€๋งŒ CSRF ๊ณต๊ฒฉ์˜ ๊ฐ„์ ‘์ ์ธ ์›์ธ์ด ๋˜๋ฏ€๋กœ ๊ฐ€๊ธ‰์  ์‚ฌ์šฉํ•˜์ง€ ๋ง์ž.

๋‹ค์–‘ํ•œ RESTful ํ•˜์ง€ ์•Š์€ ๋ผ์šฐํŠธ ํ‘œํ˜„

์˜ˆ์‹œ๋ฅผ ๋ณด์ž.

get '/blogs/:user_id' => 'blogs#index'
get 'hello/view'
get 'articles(/:category)' => 'articles#index', defaults: { category: 'general', format: 'xml'}
get 'blogs/:user_id' => 'blogs#index', constraints: { user_id: /[A-Za-z]{3, 7}/ }
get ':controller(/:action(/:id))', controller: /common|/[^\/]+/
get 'articles' => 'main#index', as: :top
get 'articles/*category/:id' => 'articles#category'
get '/books/:id' => redirect('/articles/%{id}')
get '/books/:id' => redirect {|p, req| "/articles/#{p[:id].to_i + 10000}"}

๋ฃจํŠธ ๋งคํ•‘ ์ •์˜ - root ๋ฉ”์„œ๋“œ

๋ฃจํŠธ์— ๋Œ€์‘ํ•˜๋Š” ๋ผ์šฐํŠธ๋ฅผ ์„ค์ •ํ•  ๋•Œ๋Š” root ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค. root ๋ฉ”์„œ๋“œ๋Š” ์ผ๋ฐ˜์ ์œผ๋กœ routes.rb์˜ ๋งˆ์ง€๋ง‰์— ์ž‘์„ฑํ•œ๋‹ค.

ํ…Œ์ŠคํŠธ

์ž๋™ํ™”๋œ ํ…Œ์ŠคํŠธ์€ ์•ˆ์ •์ ์ด๊ณ  ์œ ์—ฐํ•œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๋งŒ๋“œ๋Š”๋ฐ ํ•„์ˆ˜์š”์†Œ๋‹ค. Rails๋Š” ์ดˆ๊ธฐ ๋ฒ„์ „๋ถ€ํ„ฐ ์ด๋Ÿฐ ์ž๋™ํ™”๋œ ํ…Œ์ŠคํŠธ๋ฅผ ๊ต‰์žฅํžˆ ์ค‘์š”์‹œํ•˜๊ณ  ์žˆ๊ณ , ์•„๋ž˜ ํ…Œ์ŠคํŠธ๋“ค์„ ์ง€์›ํ•œ๋‹ค.

  • Unit ํ…Œ์ŠคํŠธ: ๋ชจ๋ธ ๋˜๋Š” ๋ทฐ ํ—ฌํผ์˜ ๋™์ž‘ ํ™•์ธ

  • Functional ํ…Œ์ŠคํŠธ: ์ปจํŠธ๋กค๋Ÿฌ์™€ ํ…œํ”Œ๋ฆฟ์˜ ํ˜ธ์ถœ ๊ฒฐ๊ณผ ํ™•์ธ(์ƒํƒœ ์ฝ”๋“œ ๋˜๋Š” ํ…œํ”Œ๋ฆฟ ๋ณ€์ˆ˜ ๋ทฐ์˜ ์ถœ๋ ฅ ๊ฒฐ๊ณผ ๋“ฑ)

  • Integration ํ…Œ์ŠคํŠธ: ์—ฌ๋Ÿฌ ๊ฐœ์˜ ์ปจํŠธ๋กค๋Ÿฌ๋ฅผ ๋„˜๋‚˜๋“ค๋ฉฐ ์‚ฌ์šฉ์ž์˜ ์‹ค์ œ ์กฐ์ž‘์„ ๋ชจ๋ฐฉํ•˜๊ณ  ๊ฒฐ๊ณผ ํ™•์ธ

ํ…Œ์ŠคํŠธ ํ”„๋ ˆ์ž„์›Œํฌ๋กœ๋Š” RSpec, minitest, Test::Unit ๋“ฑ์ด ์žˆ๋‹ค. ์ฐธ๊ณ 

์ฑ…์—์„œ๋Š” Test::Unit์— ๋Œ€ํ•ด ์„ค๋ช…ํ•œ๋‹ค.

ํ…Œ์ŠคํŠธ ์ค€๋น„

์šฐ์„  ํ…Œ์ŠคํŠธ๋ฅผ ํ•˜๋ ค๋ฉด ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์™€ ํ…Œ์ŠคํŠธ ์ „์šฉ ๋ฐ์ดํ„ฐ๊ฐ€ ํ•„์š”ํ•˜๋‹ค. ์˜ˆ์‹œ๋ฅผ ๋”ฐ๋ผ๊ฐ€๋ณด์ž.

1. ํ…Œ์ŠคํŠธ ๋ฐ์ดํ„ฐ ๋ฒ ์ด์Šค ๊ตฌ์ถ•

์•„๋ž˜์ฒ˜๋Ÿผ rake ๋ช…๋ น์–ด๋ฅผ ์‚ฌ์šฉํ•ด์„œ ํ…Œ์ŠคํŠธ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋ฅผ ๊ตฌ์ถ•ํ•œ๋‹ค.

rake db:migrate
rake db:test:load

rake db:migrate ๋ช…๋ น์–ด๋กœ ๋ฏธ์‹คํ–‰ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜์„ ์‹คํ–‰ํ•˜๊ณ , schema.rb๋ฅผ ์ตœ์‹  ์ƒํƒœ๋กœ ์—…๋ฐ์ดํŠธํ•œ ๋’ค์— rake db:test:load ๋ช…๋ น์–ด๋กœ schema.rb๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ํ•˜๋Š” ํ…Œ์ŠคํŠธ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋ฅผ ์ƒ์„ฑํ•œ๋‹ค. ์ด๋ ‡๊ฒŒ๋งŒ ํ•˜๋ฉด ๊ฐœ๋ฐœ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์™€ ๊ฐ™์€ ๊ตฌ์กฐ๋กœ ํ…Œ์ŠคํŠธ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๊ฐ€ ๊ตฌ์ถ•๋œ๋‹ค.

ํ…Œ์ŠคํŠธ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๊ฐ€ ์ž˜ ๊ตฌ์ถ•๋˜์—ˆ๋Š”์ง€ ํ…Œ์ŠคํŠธ ํ™˜๊ฒฝ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋กœ ์ ‘์†ํ•˜์—ฌ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค. rails ๋ฒ„์ „๋ณ„๋กœ ๋ช…๋ น์–ด๊ฐ€ ๋‹ค๋ฅด๋‹ˆ ์ฃผ์˜ํ•  ๊ฒƒ.

  • Rails 3, 4: rails dbconsole test

  • Rails 5, 6: rails dbconsole -e test

    2. ํ…Œ์ŠคํŠธ ๋ฐ์ดํ„ฐ ์ค€๋น„

    ํ”ฝ์Šค์ฒ˜๋ฅผ test/fixtures ๋””๋ ‰ํ† ๋ฆฌ์— ๋„ฃ์–ด์ฃผ์ž.

    Unit ํ…Œ์ŠคํŠธ

    Unit ํ…Œ์ŠคํŠธ(๋‹จ์œ„ ํ…Œ์ŠคํŠธ)๋Š” ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๊ตฌ์„ฑํ•˜๊ณ  ์žˆ๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ(์ฃผ์š” ๋ชจ๋ธ ๋“ฑ)๊ฐ€ ์ œ๋Œ€๋กœ ์ž‘๋™ํ•˜๋Š”์ง€ ํ™•์ธํ•˜๋Š” ํ…Œ์ŠคํŠธ์ด๋‹ค.

    models ํ…Œ์ŠคํŠธ

    /test/models ๋‚ด๋ถ€์— ์ƒ์„ฑ๋œ ์Šคํฌ๋ฆฝํŠธ์— test ๋ฉ”์„œ๋“œ๋ฅผ ์ด์šฉํ•ด์„œ ํ…Œ์ŠคํŠธ ํ•จ์ˆ˜๋ฅผ ๋งŒ๋“ค์–ด์ฃผ์ž. ์ด ๋•Œ test๋ฉ”์„œ๋“œ๋„ ๋‚ด๋ถ€์ ์œผ๋กœ test_xxxx ๋ฉ”์„œ๋“œ๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๊ฒƒ๋ฟ์ด๋ฏ€๋กœ test_๋กœ ์‹œ์ž‘ํ•˜๋Š” ๋ฉ”์„œ๋“œ๋ฅผ ์ง์ ‘ ์ •์˜ํ•ด๋„ ์ƒ๊ด€์—†๋‹ค.

    ์ดํ›„ rake test:models ๋ช…๋ น์–ด๋กœ ๋ชจ๋ธ ํ…Œ์ŠคํŠธ๋ฅผ ์‹คํ–‰ํ•œ๋‹ค. ๋งŒ์•ฝ ํŠน์ •ํ•œ ํ…Œ์ŠคํŠธ ์Šคํฌ๋ฆฝํŠธ๋ฅผ ์ง€์ •ํ•˜๊ณ  ์‹คํ–‰ํ•˜๋ ค๋ฉด rake test:models ํ…Œ์ŠคํŠธ_์Šคํฌ๋ฆฝํŠธ_๊ฒฝ๋กœ ๋ฅผ ์‹คํ–‰์‹œํ‚ค๋ฉด ๋œ๋‹ค.

    ํ…Œ์ŠคํŠธ ๋ฉ”์„œ๋“œ๊ฐ€ ์—ฌ๋Ÿฌ ๊ฐœ ์žˆ์„ ๋•Œ๋Š” ์‹คํ–‰ ์ˆœ์„œ๊ฐ€ ๋งˆ์Œ๋Œ€๋กœ์ด๋ฏ€๋กœ ์‹คํ–‰ ์ˆœ์„œ์— ์˜์กดํ•˜๋Š” ํ…Œ์ŠคํŠธ ๋ฉ”์„œ๋“œ๋Š” ์ž‘์„ฑํ•˜์ง€ ์•Š๋„๋ก ํ•˜์ž.

    Rails๋Š” ํ…Œ์ŠคํŠธ๋ฅผ ์‹คํ–‰ํ•  ๋•Œ ํ”ฝ์Šค์ฒ˜๋ฅผ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ๋กœ๋“œํ•˜๋Š” ๊ฒƒ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ, ํ…Œ์ŠคํŠธ ์Šคํฌ๋ฆฝํŠธ์—์„œ ์ด์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์‹œ๋กœ ์ „๊ฐœํ•œ๋‹ค.

    ์˜ˆ๋ฅผ ๋“ค์–ด books.yml ๋‚ด๋ถ€์— :islb๋ผ๋Š” ํ‚ค๋กœ ์ •์˜๋œ ๋ ˆ์ฝ”๋“œ๊ฐ€ ์žˆ๋‹ค๋ฉด, books(:jslib)์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋‹ค.

    view helper ํ…Œ์ŠคํŠธ

    /test/helpers ํด๋” ๋‚ด๋ถ€์— <์ปจํŠธ๋กค๋Ÿฌ>_helper_test.rb์ฒ˜๋Ÿผ ํ…Œ์ŠคํŠธ ์Šคํฌ๋ฆฝํŠธ๋ฅผ ๋งŒ๋“ค๊ณ  ์—ญ์‹œ test๋ฉ”์„œ๋“œ๋กœ ํ…Œ์ŠคํŠธ๋ฅผ ์ž‘์„ฑํ•œ ๋‹ค์Œ rake test:helpers ๋ช…๋ น์–ด๋กœ ์‹คํ–‰ํ•˜์ž.

    ์—ญ์‹œ๋‚˜ ๋งŒ์•ฝ ํŠน์ •ํ•œ ํ…Œ์ŠคํŠธ ์Šคํฌ๋ฆฝํŠธ๋ฅผ ์ง€์ •ํ•˜๊ณ  ์‹คํ–‰ํ•˜๋ ค๋ฉด rake test:helpers ํ…Œ์ŠคํŠธ_์Šคํฌ๋ฆฝํŠธ_๊ฒฝ๋กœ ๋ฅผ ์‹คํ–‰์‹œํ‚ค๋ฉด ๋œ๋‹ค.

    ํ…Œ์ŠคํŠธ ์ค€๋น„์™€ ๋’ค์ฒ˜๋ฆฌ - setup๊ณผ teardown ๋ฉ”์„œ๋“œ

    ํ…Œ์ŠคํŠธ ์Šคํฌ๋ฆฝํŠธ์—๋Š” ๊ฐ๊ฐ์˜ ํ…Œ์ŠคํŠธ ๋ฉ”์„œ๋“œ๊ฐ€ ํ˜ธ์ถœ๋˜๊ธฐ ์ „๊ณผ ํ›„์— ์ž๋™์œผ๋กœ ํ˜ธ์ถœ๋˜๋Š” ์˜ˆ์•ฝ ๋ฉ”์„œ๋“œ๊ฐ€ ์žˆ๋‹ค. ํ…Œ์ŠคํŠธ ์Šคํฌ๋ฆฝํŠธ์˜ ๋ถ€๋ชจ ํด๋ž˜์Šค ActiveSupport::TestCase์— ์ •์˜๋˜์–ด ์žˆ๋Š” ๋ฉ”์„œ๋“œ์ด๋ฏ€๋กœ ์˜ค๋ฒ„๋ผ์ด๋“œํ•ด์„œ ์‚ฌ์šฉํ•œ๋‹ค.

    ๊ฐ๊ฐ ๋ฌด์Šจ ์—ญํ• ์„ ํ•˜๋Š”์ง€ ์ด๋ฆ„์—์„œ ๋”ฑ ๊ฐ์ด ์˜จ๋‹ค.

    • setup: ๊ฐ ํ…Œ์ŠคํŠธ ๋ฉ”์„œ๋“œ๊ฐ€ ํ˜ธ์ถœ๋˜๊ธฐ ์ „์— ์‹คํ–‰(์‚ฌ์šฉํ•  ๋ฆฌ์†Œ์Šค ์ดˆ๊ธฐํ™”)

    • teardown: ๊ฐ ํ…Œ์ŠคํŠธ ๋ฉ”์„œ๋“œ๊ฐ€ ํ˜ธ์ถœ๋œ ์ดํ›„์— ์‹คํ–‰(์‚ฌ์šฉํ•œ ๋ฆฌ์†Œ์Šค ๋’ค์ฒ˜๋ฆฌ)

    ์•„๋ž˜์ฒ˜๋Ÿผ ์“ฐ๋ฉด ๋œ๋‹ค.

    def setup
      @b = books(:jslib)
    end
    โ€‹
    def teardown
      @b = nil
    end
    โ€‹
    test "where method test" do
      ...
        assert_equal @b.isbn, result.isbn, 'isbn column is wrong'
        assert_equal @b.published, result.published, 'published column is wrong'
    end

    ์ฐธ๊ณ ๋กœ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ํ”ฝ์Šค์ฒ˜๋ฅผ ์ฝ๋Š” ๊ฒƒ๊ณผ ์ œ๊ฑฐ๋Š” Rails๊ฐ€ ์ž๋™์ ์œผ๋กœ ์ฒ˜๋ฆฌํ•˜๋ฏ€๋กœ setup ๋ฉ”์„œ๋“œ์—์„œ ๋”ฐ๋กœ ์‹คํ–‰ํ•ด์ฃผ์ง€ ์•Š์•„๋„ ๋œ๋‹ค.

    Functional ํ…Œ์ŠคํŠธ

    Functional ํ…Œ์ŠคํŠธ(๊ธฐ๋Šฅ ํ…Œ์ŠคํŠธ)๋Š” ์ปจํŠธ๋กค๋Ÿฌ(์•ก์…˜)์˜ ๋™์ž‘ ๋˜๋Š” ํ…œํ”Œ๋ฆฟ์˜ ์ถœ๋ ฅ์„ ํ™•์ธํ•˜๊ธฐ ์œ„ํ•œ ํ…Œ์ŠคํŠธ์ด๋‹ค. Functional ํ…Œ์ŠคํŠธ์—์„œ๋Š” ๋ธŒ๋ผ์šฐ์ €์ฒ˜๋Ÿผ HTTP ์š”์ฒญ์„ ์œ ์‚ฌ์ ์œผ๋กœ ์ž‘์„ฑํ•˜๋Š” ๊ฒƒ์œผ๋กœ ์•ก์…˜ ๋ฉ”์„œ๋“œ๋ฅผ ์‹คํ–‰ํ•˜๊ณ  ๊ทธ ๊ฒฐ๊ณผ๋กœ HTTP ์ƒํƒœ ์ฝ”๋“œ, ํ…œํ”Œ๋ฆฟ ๋ณ€์ˆ˜ ๋˜๋Š” ์ตœ์ข…์ ์ธ ์ถœ๋ ฅ ๊ตฌ์กฐ ๋“ฑ์„ ํ™•์ธํ•œ๋‹ค. ๋˜ํ•œ, ๋ผ์šฐํŠธ ์ •์˜์˜ ์œ ํšจ์„ฑ์„ ํ™•์ธํ•˜๋Š” ๊ฒƒ๋„ Functional ํ…Œ์ŠคํŠธ์˜ ์—ญํ• ์ด๋‹ค.

    ์ปจํŠธ๋กค๋Ÿฌ test ๋ฉ”์„œ๋“œ ์ž‘์„ฑ

    /test/controllers ํด๋” ๋‚ด๋ถ€์— xxx_controller_test.rb์— test ๋ฉ”์„œ๋“œ๋กœ ํ…Œ์ŠคํŠธ๋ฅผ ์ž‘์„ฑํ•œ๋‹ค. ์•„๋ž˜๋Š” ์˜ˆ์‹œ.

    require "test_helper"
    โ€‹
    class HelloControllerTest < ActionDispatch::IntegrationTest
      test "list action" do
        get :list
        assert_equal 10, assigns(:books).length, 'found rows is wrong.'
        assert_response :success, 'list action failed.'
        assert_template 'hello/list'
      end
    end

    ํ…Œ์ŠคํŠธ ๋ฉ”์„œ๋“œ๋ฅผ ์ž‘์„ฑํ•˜๋Š” ๊ฒƒ ์ž์ฒด๋Š” Unit ํ…Œ์ŠคํŠธ์™€ ๊ฐ™์ง€๋งŒ, ๋ช‡ ๊ฐ€์ง€ Functional ํ…Œ์ŠคํŠธ๋งŒ์˜ ํฌ์ธํŠธ๊ฐ€ ์žˆ๋‹ค.

    get ๋ฉ”์„œ๋“œ๋กœ ์š”์ฒญ ์ƒ์„ฑ

    Functional ํ…Œ์ŠคํŠธ์—์„œ๋Š” ์ผ๋‹จ ์ปจํŠธ๋กค๋Ÿฌ๋ฅผ ์‹คํ–‰ํ•˜๊ธฐ ์œ„ํ•ด get ๋ฉ”์„œ๋“œ๋กœ HTTP ์š”์ฒญ์„ ์ƒ์„ฑํ•œ๋‹ค.

    ์•„๋ž˜๋Š” ๋งค๊ฐœ ๋ณ€์ˆ˜ ์ •๋ณด๋ฅผ ํ•จ๊ป˜ ์ „๋‹ฌํ•˜๋Š” ์˜ˆ์ œ!

    get :show, { id: 108 }

    Functional ํ…Œ์ŠคํŠธ์—์„œ ์ด์šฉํ•  ์ˆ˜ ์žˆ๋Š” ์˜ˆ์•ฝ ๋ณ€์ˆ˜

    Functional ํ…Œ์ŠคํŠธ์—์„œ๋Š” get, post ๋“ฑ์˜ ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•œ ํ›„์— ์•„๋ž˜ ์˜ˆ์•ฝ ๋ณ€์ˆ˜์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋‹ค.

    ๋ถ„๋ฅ˜

    ๋ณ€์ˆ˜ ์ด๋ฆ„

    ์„ค๋ช…

    ๊ฐ์ฒด

    @controller

    ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•œ ์ปจํŠธ๋กค๋Ÿฌ ํด๋ž˜์Šค

    ๊ฐ์ฒด

    @request

    ์š”์ฒญ ๊ฐ์ฒด

    ๊ฐ์ฒด

    @response

    ์‘๋‹ต ๊ฐ์ฒด

    ํ•ด์‹œ

    assigns(:key), assigns['key']

    ๋ทฐ์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ํ…œํ”Œ๋ฆฟ ๋ณ€์ˆ˜

    ํ•ด์‹œ

    cookies[:key]

    ์ฟ ํ‚ค ์ •๋ณด

    ํ•ด์‹œ

    flash[:key]

    ํ”Œ๋ž˜์‹œ ์ •๋ณด

    ํ•ด์‹œ

    session[:key]

    ์„ธ์…˜ ์ •๋ณด

    Functional ํ…Œ์ŠคํŠธ์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” assert_xxxx ๋ฉ”์„œ๋“œ

    Unit ํ…Œ์ŠคํŠธ์—์„œ ์ผ๋˜ Assertion ๋ฉ”์„œ๋“œ ๋ง๊ณ ๋„ Functional ํ…Œ์ŠคํŠธ์—์„œ ์ถ”๊ฐ€๋กœ ์“ธ ์ˆ˜ ์žˆ๋Š” Assertion๊ฐ€ ์žˆ๋‹ค. ์ค‘์š”ํ•œ ๊ฒƒ ๋ช‡ ๊ฐœ๋ฅผ ์ •๋ฆฌํ•ด๋ณด์ž๋ฉด ์•„๋ž˜์™€ ๊ฐ™๋‹ค.

    1. assert_difference ๋ฉ”์„œ๋“œ: ์ฒ˜๋ฆฌ ํ›„ ์ƒํƒœ ๋ณ€ํ™” ํ™•์ธ

    2. assert_generates ๋ฉ”์„œ๋“œ: ๋ผ์šฐํŒ… ๋™์ž‘ ํ™•์ธ

    3. assert_select ๋ฉ”์„œ๋“œ: ํ…œํ”Œ๋ฆฟ ์ถœ๋ ฅ ๊ฒฐ๊ณผ ํ™•์ธ

    Integration ํ…Œ์ŠคํŠธ

    Integration ํ…Œ์ŠคํŠธ(ํ†ตํ•ฉ ํ…Œ์ŠคํŠธ)๋Š” ์—ฌ๋Ÿฌ ๊ฐœ์˜ ์ปจํŠธ๋กค๋Ÿฌ๋ฅผ ๋„˜๋‚˜๋“ค๋ฉฐ ์‹ค์ œ ์‚ฌ์šฉ์ž์˜ ํ–‰๋™์„ ๋ชจ๋ฐฉํ•  ๋•Œ ์‚ฌ์šฉํ•œ๋‹ค.

    ์˜ˆ๋ฅผ ๋“ค์–ด ์ฑ…์—์„œ ๊ตฌํ˜„ํ–ˆ๋˜ ๋กœ๊ทธ์ธ ๊ธฐ๋Šฅ์˜ ๊ฒฝ์šฐ ์•„๋ž˜ ์ ˆ์ฐจ๋ฅผ ๋”ฐ๋ฅธ๋‹ค. Integration ํ…Œ์ŠคํŠธ๋กœ ์ด๋Ÿฐ ๋‹จ๊ณ„์ ์ธ ์ฒ˜๋ฆฌ๋ฅผ ์‹ค์ œ๋กœ ๋ชจ๋ฐฉํ•ด์„œ ๊ฐ๊ฐ์˜ ๋‹จ๊ณ„์—์„œ ์ œ๋Œ€๋กœ ๋œ ์ฒ˜๋ฆฌ๊ฐ€ ์ด๋ฃจ์–ด์ง€๋Š”์ง€๋ฅผ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

    1. hello#view ์•ก์…˜์— ์ ‘๊ทผ

    2. ๋ฏธ์ธ์ฆ ์ƒํƒœ์ด๋ฏ€๋กœ, login#index ์•ก์…˜(๋กœ๊ทธ์ธ ํŽ˜์ด์ง€)๋กœ ๋ฆฌ๋‹ค์ด๋ ‰ํŠธ

    3. ๋กœ๊ทธ์ธ ํŽ˜์ด์ง€์—์„œ ์‚ฌ์šฉ์ž ์ด๋ฆ„๊ณผ ๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ์ž…๋ ฅํ•˜๊ณ  ์ธ์ฆ ์ฒ˜๋ฆฌ

    4. login#auth ์•ก์…˜์—์„œ ์ธ์ฆ ์ฒ˜๋ฆฌ๊ฐ€ ์™„๋ฃŒ๋˜๋ฉด hello#view ์•ก์…˜์œผ๋กœ ๋ฆฌ๋‹ค์ด๋ ‰ํŠธ

    ํ…Œ์ŠคํŠธ ์Šคํฌ๋ฆฝํŠธ ์˜ˆ์‹œ

    1. ํ…Œ์ŠคํŠธ ์Šคํฌ๋ฆฝํŠธ ์ƒ์„ฑ

      Integration ํ…Œ์ŠคํŠธ๋Š” ์ง์ ‘ rails generate integration_test xxxxx ๋ช…๋ น์–ด๋กœ ์ƒ์„ฑํ•ด์ค˜์•ผํ•œ๋‹ค.

      rails generate integration_test admin_login
      # test/integration/admin_login_test.rb ๊ฐ€ ์ƒ์„ฑ๋จ.
    2. ํ…Œ์ŠคํŠธ ์Šคํฌ๋ฆฝํŠธ ์ž‘์„ฑ ์œ„์— ์˜ˆ์‹œ๋กœ ์ ์€ ๋กœ๊ทธ์ธ ์ฒ˜๋ฆฌ๋ฅผ ํ™•์ธํ•˜๋Š” ์ฝ”๋“œ ์˜ˆ์‹œ๋Š” ์•„๋ž˜์™€ ๊ฐ™๋‹ค.

      require 'test_helper'
      class AdminLoginTest < ActionDispatch::IntegrationTest
        test "login test" do
          get '/hello/view'
          assert_response :redirect
          assert_redirected_to controller: :login, action: :index
          assert_equal '/hello/view', flash[:referer]
          
          follow_redirect!
          assert_response :success
          assert_equal '/hello/view', flash[:referer]
          
          post '/login/auth', { username: 'arint', password: '12345', referer: '/hello/view' }
          assert_response :redirect
          assert_redirected_to controller: :hello, action: :view
          assert_equal users(:arint).id, session[:usr]
          
          follow_redirect!
          assert_response :success
        end
      end 

      ์ค‘๊ฐ„ ์ค‘๊ฐ„์— ์žˆ๋Š” follow_redirect! ๋Š” ์‘๋‹ต์— ์žˆ๋Š” ๋ฆฌ๋‹ค์ด๋ ‰ํŠธ ๋Œ€์ƒ์œผ๋กœ ๋‹ค์‹œ ์š”์ฒญํ•˜๋Š” ๊ธฐ๋Šฅ์ด๋‹ค. ๋ฏธ์ธ์ฆ ์ƒํƒœ์˜ ์‚ฌ์šฉ์ž๊ฐ€ /hello/view์— ์ ‘๊ทผํ•˜๋ฉด ๋กœ๊ทธ์ธ ํŽ˜์ด์ง€๋กœ ๋ฆฌ๋‹ค์ด๋ ‰ํŠธํ•˜๋ผ๋Š” ์‘๋‹ต์„ ๋ฐ›๊ฒŒ ๋ ํ…๋ฐ, ์ด ๋•Œ ๋ฐ›์€ ๋ฆฌ๋‹ค์ด๋ ‰ํŠธ ๋Œ€์ƒ์œผ๋กœ ์ด๋™ํ•˜๋Š” ๊ฒƒ์„ ๋ชจ๋ฐฉํ•˜๋Š” ๊ฒƒ์ด๋‹ค.

    3. ํ…Œ์ŠคํŠธ ์Šคํฌ๋ฆฝํŠธ ์‹คํ–‰

      rake test:integration ๋ช…๋ น์–ด๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ํ…Œ์ŠคํŠธ๋ฅผ ์‹คํ–‰์‹œํ‚ฌ ์ˆ˜ ์žˆ๋‹ค.

ํ•™์Šต ๋‚ด์šฉ์— ๋Œ€ํ•œ ๊ฐœ์ธ์ ์ธ ์ดํ‰

RESTful, Test ๋‘˜ ๋ชจ๋‘ ์ทจ์—…๊ณต๊ณ ๋ฅผ ๋ณด๋ฉด ์ž์ฃผ ๋งŒ๋‚  ์ˆ˜ ์žˆ๋Š” ํ‚ค์›Œ๋“œ์ž…๋‹ˆ๋‹ค. Rails๋ฅผ ํ•™์Šตํ•˜๋Š” ๊ณผ์ •์—์„œ ์ด ๋‘˜์„ ์•ฝ๊ฐ„์ด๋‚˜๋งˆ ๋ง›๋ณผ ์ˆ˜ ์žˆ๋Š”๊ฒŒ ์ข‹๋„ค์š”. Rails๋ฅผ ํ•™์Šตํ•  ๋•Œ๋งˆ๋‹ค nest.js๋‚˜ spring ํ•™์Šต์— ์‹œ๊ฐ„์„ ์“ฐ๊ณ  ์‹ถ๋‹ค๋Š” ์ƒ๊ฐ์ด ์™•์™•๋“ค๊ธด ํ•˜์ง€๋งŒ, ์ด๋Ÿฐ ์‹์œผ๋กœ '๋ฐฑ์—”๋“œ'์— ํ•„์š”ํ•œ ๊ฐœ๋…๊ณผ ๊ธฐ์ˆ ์„ ํ™•์‹คํžˆ ํ•™์Šตํ•ด๋ฒ„๋ฆฌ๋Š” ๊ธฐํšŒ๋กœ ์‚ผ์•„์•ผ๊ฒ ์Šต๋‹ˆ๋‹ค.

๋‹ค์Œ ํ•™์Šต ๊ณ„ํš

  • ๋ฃจ๋น„์˜จ๋ ˆ์ผ์ฆˆ ํด๋ผ์ด์–ธํŠธ๋‹จ ํ›‘๊ธฐ

Last updated