Rails 라우팅 — URL을 콘트롤러로 연결하는 규칙

Rails 라우팅 — URL을 콘트롤러로 연결하는 규칙

브라우저에 /products/1 같은 주소를 입력하면 Rails는 어떤 콘트롤러의 어떤 액션이 실행될지를 결정해야 해요. 이 결정을 내려주는 규칙 모음이 바로 **라우팅(routing)**이에요. 라우터는 퍼즐의 조각들을 이어주는 역할을 하는데, 들어온 요청의 URL을 보고 매칭되는 라우트를 찾아 해당 콘트롤러 액션을 호출하고, 그 결과를 조립해서 응답으로 되돌려줘요. 라우팅을 이해하면 "어떤 URL이 어떤 코드로 이어지는가"가 머릿속에 자연스럽게 그려져요.

출처: Rails Routing from the Outside In

본문

라우팅의 목적

Rails의 라우터는 두 가지 일을 한 번에 처리해요. 하나는 들어오는 요청을 액션으로 연결하는 것이고, 다른 하나는 URL 경로를 만들어내는 헬퍼 메서드를 생성하는 것이에요. 이 덕분에 링크를 만들 때 URL을 하드코딩하는 대신 products_path처럼 라우트가 만들어 준 헬퍼를 쓰면 되죠.

리소스 기반 라우팅

가장 많이 쓰는 방식은 resources로 RESTful 리소스를 선언하는 거예요.

Rails.application.routes.draw do
  resources :products
end

이 한 줄로 일곱 개의 표준 라우트가 만들어져요. HTTP 동사와 URL, 액션의 대응 관계를 정리하면 이렇게 되죠.

HTTP 동사 경로 액션 용도
GET /products index 목록 표시
POST /products create 새 레코드 저장
GET /products/new new 생성 폼 표시
GET /products/:id show 단건 표시
PATCH/PUT /products/:id update 기존 레코드 갱신
GET /products/:id/edit edit 수정 폼 표시
DELETE /products/:id destroy 레코드 삭제

:id처럼 콜론으로 시작하는 부분을 동적 세그먼트라고 불러요. 요청이 들어오면 여기에 실제 값이 채워져서 콘트롤러의 params로 전달돼요.

단일 리소스

하나의 객체만 다루는 경우에는 resource(단수형)를 쓸 수 있어요. 이 경우 index 라우트와 :id를 포함한 라우트가 만들어지지 않아요.

resource :geocoder
resolve("Geocoder") { [:geocoder] }

추가 라우트

리소스에 액션이 기본 일곱 개를 넘어서 추가될 때가 있어요. 예를 들어 상품을 검색하는 기능을 추가한다면 이렇게 작성해요.

resources :products do
  get :search, on: :collection
  get :preview, on: :member
end

on: :collection은 URL에 :id가 없는 컬렉션 라우트(/products/search)를 만들고, on: :member:id가 붙는 멤버 라우트(/products/:id/preview)를 만들어요. 여러 개를 묶으려면 collection do ... end 블록을 쓰는 편이 깔끔해요.

중첩 리소스

리소스가 소속 관계를 가질 때는 중첩으로 표현해요. 예를 들어 기사(articles)가 여러 댓글(comments)을 가진다면 이렇게 선언하죠.

resources :articles do
  resources :comments
end

이렇게 하면 /articles/1/comments 같은 경로가 유효해져요. 다만 중첩이 깊어지면 URL이 길어지고 라우트가 복잡해지므로, 일반적으로는 중첩을 한 단계로 유지하는 걸 권장해요.

블록 없는 리소스 라우팅

resources에 리소스 여러 개를 한 번에 넘기면 동일한 액션 집합을 한꺼번에 만들 수 있어요.

resources :photos, :books, :videos

지금은 블록 안에서 다시 resources를 쓰는 대신, 같은 레벨로 필요한 리소스들을 나열하는 방식을 더 권장한답니다.

매칭 순서

Rails는 라우트를 파일에 적힌 순서대로 위에서 아래로 매칭해요. 맨 처음 매칭된 라우트가 실행되고 나머지는 무시되죠. 그래서 제네럴한 라우트보다 구체적인 라우트를 먼저 적어야 해요. 예를 들어 /products/:id처럼 :id를 받는 라우트 뒤에 /products/new를 두면, new:id로 잡혀버릴 수 있으니 조심해야 해요.

라우트 확인

설정한 라우트의 실제 형태를 확인하고 싶다면 콘솔에서 이 명령을 쓰면 돼요.

bin/rails routes

이 명령은 모든 라우트의 동사, 경로, 액션, 헬퍼를 한눈에 보여줘요. -g 옵션으로 특정 리소스만 걸러낼 수도 있어요.

bin/rails routes -g products

더 알아보기 (Learn more)