해당 포스트는 Rails Routes for Rookies를 읽고 해석한 글입니다.

최근, Tracoon라 불리는 프로젝트를 완료했는데 해당 프로젝트에서 우리가 자주 사용했던 컨셉 중 하나는 바로 라우트다. 라우트를 레일즈 프로젝트에서 어떻게 사용하는지에 대해 파악할 수 있었지만, 좀 더 깊게 이해하고 싶어졌다.

Routes

레일즈에서 라우트의 역할은 HTTP 리퀘스트를 처리해야할 컨트롤러의 액션에 적절히 맵핑해주는 것이다. 리퀘스트를 받게 되면, 레일즈는 먼저 routes.rb 파일에 정의된 각 경로를 스캔하며 리퀘스트의 verb 및 URL 조합과 일치하는 것이 있는지 확인한다. 레일즈는 해당 요청을 일치하는 경로로 보내고, 엔드포인트에 경로가 없다면 ‘no routes match error’를 발생시킨다.

railsroutes.png
출처 : https://medium.com/@tafby88/rails-routes-for-rookies-13d5fa2decdd


라우트의 또 다른 기능 중 하나는 경로에서 특정 부분을 추출하여 컨트롤러의 param hash에서 사용가능하게끔 해준다는 것이다. 예를 들어, GET /racoon/:id 라는 리퀘스트를 받았을 때, id 부분을 컨트롤러의 param hash로 사용 가능하다. 좀 더 구체적인 예로는, localhost:3000/racoons/6이라는 리퀘스트를 받았다면 라우트는 라쿤 컨트롤러의 show 액션으로 해당 id를 함깨 보내며 우리에게 id 6번의 라쿤 데이터를 반환해준다.

class RaccoonsController < ApplicationController
  def index
  	@raccoons = Raccoon.all
  end

  def show
  	@raccoon = Raccoon.find(params[:id])
  end
end


Resources

당신은 직접 당신만의 라우트와 액션을 사용할 수 있지만, RESTful routing을 사용하는 것이 베스트 프랙티스이다. REST란 REpresentational State Transfer의 약자이며 일반적으로 가장 많이 쓰이는 API 패턴이다. REST API에는 객체에서 사용해야할 7가지의 메인 타입의 액션이 있다. 아래의 이미지는 그 액션들을 나타낸 표이다. 주목해야할 점은 URL이 동일하지만 HTTP verb가 다르다는 점이다. 각 verb와 URL의 조합으로 해당되는 액션으로 라우팅된다.

rest_routes.png
출처 : https://medium.com/@tafby88/rails-routes-for-rookies-13d5fa2decdd


config/routes.rb 파일에서 이러한 방식으로 경로를 입력할 수 있다.

# config/routes.rb

get "/raccoons", to: "raccoons#index"
get "/raccoons/:id", to: "raccoons#show"
get "/raccoons/new", to: "raccoons#new"
post "/raccoons", to: "raccoons#create"
get "/raccoons/:id/edit", to: "raccoons#edit"
put "/raccoons/:id", to: "raccoons#update"
delete "/raccoons/:id", to: "raccoons#destroy"

레일즈는 이 7가지 라우트를 헬퍼 메소드를 통해 한번에 제공해준다. resources :raccoons 라고 적는다면, 위의 7가지 메소드를 직접 적을 필요없이 단 한줄의 코드로 모든 메소드를 사용할 수 있게 된다.

# config/routes.rb

resources :raccoons

만약 7가지 메소드 모두 필요하지는 않다면? 아래와 같이 only, 혹은 except 기능을 통해 필요한 메소드만 적용 가능하다.

# config/routes.rb

resources :raccoons, only: [:index, :show] # 7개의 라우트 중 index와 show만 적용된다
resources :raccoons, except: [:index] # 7개의 라우트 중 index를 제외한다


rails routes command

당신이 정의한 라우트를 확인하고 싶다면 간단히 터미널에 rails route명령어만 적어주면 된다.

routes_command.png
출처 : https://medium.com/@tafby88/rails-routes-for-rookies-13d5fa2decdd


Renaming URLs

물론 리네임도 가능하다. 예를 들어, 만약 유저의 로그인을 위해 새로운 세션을 생성하는 컨트롤러가 있다고 해보자. URL은 localhost:3000/sessions/new 이러한 형태가 될 것이다. 하지만 이는 직관적이지 않을 수 있다. 만약 URL이 localhost:3000/login 이러하다면 어떠한가. 좀 더 그럴싸한 URL로 보인다.

# config/routes.rb

get "/login", to: "sessions#new", as: "login"


Nested Routes

예를 들어, 라쿤페이지에 댓글을 추가하고 싶다고 해보자. 중첩 라우트를 사용한다면 특정한 라쿤 페이지에 대한 댓글을 찾을 수 있게 해준다.

# config/routes.rb

resources :raccoons do 
	resources :comments
end

터미널에서 rails routes 명령어를 입력한다면 아래와 같은 라우트 리스트를 확인할 수 있다.

nested_routes.png
출처 : https://medium.com/@tafby88/rails-routes-for-rookies-13d5fa2decdd


raccoon 라우트 아래에 comment가 중첩되어 있는 것을 볼 수 있을 것이다. 이러한 URL을 통해 요청된 객체를 찾기 위해 필요한 두 params, raccoon_id와 id(comment id이다)에 접근할 수 있다. 하지만 너무 많은 중첩은 프로그램의 복잡성을 높일 수 있으니 최대 2개 정도의 중첩 라우트를 사용하길 권장한다.