1 Rails 라우터의 목적
Rails 라우터는 들어오는 HTTP 요청을 URL 경로를 기반으로 Rails 애플리케이션의 특정 컨트롤러 액션과 매칭합니다. (또한 Rack 애플리케이션으로도 전달할 수 있습니다.) 라우터는 또한 라우터에 설정된 리소스를 기반으로 경로와 URL 헬퍼를 생성합니다.
1.1 들어오는 URL을 코드로 라우팅하기
Rails 애플리케이션이 들어오는 요청을 받으면, router에게 이를 controller action(일명 method)과 매칭하도록 요청합니다. 예를 들어, 다음과 같은 들어오는 요청을 살펴보겠습니다:
GET /users/17
첫 번째로 일치하는 route가 다음과 같다면:
get "/users/:id", to: "user#show"
요청은 UsersController
클래스의 show
액션과 매치되며 params
해시에 { id: '17' }
이 포함됩니다.
to:
옵션은 문자열이 전달될 때 controller#action
형식을 기대합니다. 또는 to:
대신 심볼을 전달하고 action:
옵션을 사용할 수 있습니다. #
없이 문자열을 전달할 수도 있는데, 이 경우 to:
대신 controller:
옵션이 사용됩니다. 예를 들면:
get "/users/:id", controller: "users", action: :show
Rails는 라우트를 지정할 때 컨트롤러 이름에 snake_case를 사용합니다. 예를 들어, UserProfilesController
라는 컨트롤러가 있다면, show action으로 가는 라우트를 user_profiles#show
와 같이 지정합니다.
1.2 코드에서 Path와 URL 생성하기
Router는 자동으로 애플리케이션의 path와 URL helper method를 생성합니다. 이러한 method들을 사용하면 하드코딩된 path와 URL 문자열을 피할 수 있습니다.
예를 들어, 다음과 같은 route를 정의하면 user_path
와 user_url
helper method를 사용할 수 있습니다:
get "/users/:id", to: "users#show", as: "user"
위 구문은 users#show
action으로 요청을 라우팅하고 매개변수 id
와 함께 user_path
helper를 생성합니다.
as:
옵션은 route에 대한 사용자 지정 이름을 제공하는데 사용되며, URL과 path 헬퍼를 생성할 때 사용됩니다.
컨트롤러에 다음과 같은 코드가 포함되어 있다고 가정해보겠습니다:
@user = User.find(params[:id])
그리고 이것을 해당 view에 작성합니다:
<%= link_to '사용자 정보', user_path(@user) %>
router는 user_path(@user)
로부터 /users/17
경로를 생성합니다. user_path
헬퍼를 사용하면 view에서 경로를 하드코딩하지 않아도 됩니다. 이는 나중에 route를 다른 URL로 이동할 때 유용한데, 그에 해당하는 view를 업데이트할 필요가 없기 때문입니다.
또한 비슷한 목적의 user_url
도 생성합니다. user_path
가 /users/17
와 같은 상대 URL을 생성하는 반면, user_url
은 위 예시에서 https://example.com/users/17
와 같은 절대 URL을 생성합니다.
1.3 Rails Router 설정하기
라우트는 config/routes.rb
에 위치합니다. 다음은 일반적인 Rails 애플리케이션에서 라우트가 어떻게 보이는지 보여주는 예시입니다. 이어지는 섹션에서는 이 파일에서 사용된 다양한 route helper들을 설명할 것입니다:
Rails.application.routes.draw do
resources :brands, only: [:index, :show] do
resources :products, only: [:index, :show]
end
resource :basket, only: [:show, :update, :destroy]
# Basket 모델에 대한 라우팅 헬퍼를 정의합니다.
# 예: basket_path와 같은 라우팅 헬퍼가 자동으로 생성됩니다.
resolve("Basket") { route_for(:basket) }
end
일반적인 Ruby 소스 파일이므로, 라우트를 정의할 때 모든 Ruby 기능(조건문과 반복문 같은)을 사용할 수 있습니다.
라우트 정의를 감싸는 Rails.application.routes.draw do ... end
블록은 router DSL(Domain Specific Language)의 스코프를 설정하는 데 필요하므로 삭제해서는 안 됩니다.
routes.rb
에서 변수명을 사용할 때는 router의 DSL 메서드와 충돌할 수 있으므로 주의하세요.
2 Resource Routing: Rails의 기본
Resource routing을 사용하면 주어진 resource 컨트롤러에 대한 모든 공통 라우트를 빠르게 선언할 수 있습니다. 예를 들어, resources
를 한 번 호출하면 각 라우트를 따로 선언할 필요 없이 index
, show
, new
, edit
, create
, update
, destroy
액션에 필요한 모든 라우트가 선언됩니다.
2.1 웹상의 Resources
브라우저는 GET
, POST
, PATCH
, PUT
, DELETE
와 같은 특정 HTTP verb를 사용하여 URL에 대한 요청을 수행함으로써 Rails에 페이지를 요청합니다. 각 HTTP verb는 resource에 대한 작업을 수행하기 위한 요청입니다. resource route는 관련 요청들을 단일 controller의 actions에 매핑합니다.
Rails 애플리케이션이 다음과 같은 들어오는 요청을 받을 때:
DELETE /photos/17
라우터에게 이를 컨트롤러 액션에 매핑하도록 요청합니다. 첫 번째로 매칭되는 라우트가 다음과 같다면:
resources :photos
이는 애플리케이션에서 RESTful한 방식으로 photos를 위한 URL을 선언하게 됩니다. 또한 여러 URL 헬퍼 메소드를 생성하여 controller에서 URL을 처리할 수 있게 해줍니다.
Rails는 해당 요청을 params
의 { id: '17' }
과 함께 PhotosController
의 destroy
action으로 전달합니다.
2.2 CRUD, Verbs, 그리고 Actions
Rails에서 resourceful 라우트는 들어오는 요청(HTTP verb + URL의 조합)을 컨트롤러 액션에 매핑합니다. 관례에 따라 각 액션은 일반적으로 데이터에 대한 특정 CRUD 작업에 매핑됩니다. 라우팅 파일의 단일 항목은 다음과 같습니다:
resources :photos
photos를 다루는 RESTful한 routes를 정의합니다.
애플리케이션에 다음과 같이 7개의 서로 다른 라우트를 생성하며, 모두 PhotosController
액션에 매핑됩니다:
HTTP Verb | Path | Controller#Action | Used to |
---|---|---|---|
GET | /photos | photos#index | 모든 photos 목록 표시 |
GET | /photos/new | photos#new | 새로운 photo 생성을 위한 HTML 폼 반환 |
POST | /photos | photos#create | 새로운 photo 생성 |
GET | /photos/:id | photos#show | 특정 photo 표시 |
GET | /photos/:id/edit | photos#edit | photo 수정을 위한 HTML 폼 반환 |
PATCH/PUT | /photos/:id | photos#update | 특정 photo 업데이트 |
DELETE | /photos/:id | photos#destroy | 특정 photo 삭제 |
라우터는 HTTP verb 및 path를 사용하여 들어오는 요청을 매칭하기 때문에, 4개의 URL이 7개의 서로 다른 컨트롤러 액션에 매핑될 수 있습니다. 예를 들어, 동일한 photos/
경로가 verb가 GET
일 때는 photos#index
에 매칭되고 verb가 POST
일 때는 photos#create
에 매칭됩니다.
routes.rb
파일에서 순서가 중요합니다. Rails 라우트는 지정된 순서대로 매칭됩니다. 예를 들어, get 'photos/poll'
위에 resources :photos
가 있다면, resources 라인의 show
액션 라우트가 get
라인보다 먼저 매칭될 것입니다. photos/poll
라우트가 먼저 매칭되길 원한다면, get
라인을 resources
라인 위로 이동시켜야 합니다.
2.3 Path와 URL Helper
리소스풀 라우트를 생성하면 애플리케이션의 컨트롤러와 뷰에서 사용할 수 있는 여러 helper가 노출됩니다.
예를 들어, route 파일에 resources :photos
를 추가하면 다음과 같은 _path
helper가 생성됩니다:
Path Helper | Returns URL |
---|---|
photos_path |
/photos |
new_photo_path |
/photos/new |
edit_photo_path(:id) |
/photos/:id/edit` |
photo_path(:id) |
/photos/:id |
위의 :id
와 같은 path helper의 파라미터는 생성된 URL로 전달되어, edit_photo_path(10)
은 /photos/10/edit
를 반환합니다.
이러한 각각의 _path
helper는 해당하는 _url
helper(예: photos_url
)도 가지고 있으며, 이는 현재 host, port, path prefix가 앞에 추가된 동일한 경로를 반환합니다.
"_path"와 "_url" 앞에 붙는 접두사는 route 이름이며 rails routes
명령어 출력의 "prefix" 열에서 확인할 수 있습니다. 자세한 내용은 아래의 기존 Route 나열하기를 참조하세요.
2.4 여러 Resource를 동시에 정의하기
여러 resource에 대한 route를 생성해야 하는 경우 하나의 resources
호출로 모두 정의하면 약간의 타이핑을 줄일 수 있습니다:
resources :photos, :books, :videos
photos, books, videos에 대한 RESTful routes를 한 번에 여러 개 선언합니다.
위의 내용은 다음의 축약형입니다:
resources :photos
resources :books
resources :videos
리소스를 한 번에 여러 개 정의하고 싶으면, 단 한 줄로도 가능합니다. 한 줄로 표현한 위 코드는 각각의 리소스를 여러 줄로 나누어 선언한 것과 정확하게 동일한 결과를 만듭니다.
2.5 Singular Resources
때로는 사용자가 하나만 가질 것으로 예상되는 리소스가 있습니다(즉, 해당 리소스의 모든 값을 나열하는 index
액션을 갖는 것이 의미가 없는 경우). 이러한 경우 resources
대신 resource
(단수)를 사용할 수 있습니다.
아래의 resourceful 라우트는 애플리케이션에서 6개의 라우트를 생성하며, 모두 Geocoders
컨트롤러에 매핑됩니다:
resource :geocoder
resolve("Geocoder") { [:geocoder] }
resource 헬퍼를 사용하면 이는 아래의 내용과 같은 정의가 생성됩니다:
resolve
호출은 레코드 식별을 통해 Geocoder
인스턴스를 단수 라우트로 변환하는데 필요합니다.
다음은 단수 리소스에 대해 생성되는 모든 라우트입니다:
HTTP Verb | Path | Controller#Action | Used to |
---|---|---|---|
GET | /geocoder/new | geocoders#new | geocoder 생성을 위한 HTML 폼 반환 |
POST | /geocoder | geocoders#create | 새로운 geocoder 생성 |
GET | /geocoder | geocoders#show | 하나뿐인 geocoder 리소스 표시 |
GET | /geocoder/edit | geocoders#edit | geocoder 수정을 위한 HTML 폼 반환 |
PATCH/PUT | /geocoder | geocoders#update | 하나뿐인 geocoder 리소스 업데이트 |
DELETE | /geocoder | geocoders#destroy | geocoder 리소스 삭제 |
단수 리소스는 복수형 컨트롤러에 매핑됩니다. 예를 들어, geocoder
리소스는 GeocodersController
에 매핑됩니다.
단수 리소스 라우트는 다음과 같은 헬퍼를 생성합니다:
new_geocoder_path
는/geocoder/new
를 반환edit_geocoder_path
는/geocoder/edit
를 반환geocoder_path
는/geocoder
를 반환
복수 리소스와 마찬가지로, _url
로 끝나는 동일한 헬퍼들은 호스트, 포트, 경로 접두사도 포함합니다.
2.6 Controller Namespaces와 Routing
대규모 애플리케이션에서는 controller 그룹을 namespace로 구성하고 싶을 수 있습니다. 예를 들어 app/controllers/admin
디렉터리 안에 있는 Admin::
namespace 아래에 여러 controller를 가질 수 있습니다. 이러한 그룹에는 namespace
블록을 사용하여 routing할 수 있습니다:
namespace :admin do
resources :articles
end
의 결과로, Rails는 /admin/articles URL에 매칭되는 라우트들을 생성하고 ArticlesController를 Admin::ArticlesController 내에 위치하도록 요구할 것입니다.
articles
와 comments
컨트롤러 각각에 대해 여러 라우트가 생성됩니다. Admin::ArticlesController
의 경우 Rails는 다음과 같이 생성합니다:
HTTP Verb | Path | Controller#Action | Named Route Helper |
---|---|---|---|
GET | /admin/articles | admin/articles#index | admin_articles_path |
GET | /admin/articles/new | admin/articles#new | new_admin_article_path |
POST | /admin/articles | admin/articles#create | admin_articles_path |
GET | /admin/articles/:id | admin/articles#show | admin_article_path(:id) |
GET | /admin/articles/:id/edit | admin/articles#edit | edit_admin_article_path(:id) |
PATCH/PUT | /admin/articles/:id | admin/articles#update | admin_article_path(:id) |
DELETE | /admin/articles/:id | admin/articles#destroy | admin_article_path(:id) |
위 예시에서 모든 경로는 namespace
의 기본 규칙에 따라 /admin
접두사를 갖습니다.
2.6.1 Module 사용하기
만약 Admin::ArticlesController
에 대해 (/admin
접두사 없이) /articles
로 라우팅하고 싶다면, scope
를 사용하여 module을 지정할 수 있습니다:
scope module: "admin" do # articles_url이 /articles를 가리키고
resources :articles # articles_controller는 Admin::ArticlesController가 됨
end
위 내용을 작성하는 다른 방법:
resources :articles, module: "admin"
"admin" module 아래에 articles resource를 생성합니다.
2.6.2 Scope 사용하기
또는, /admin/articles
를 ArticlesController
로 라우팅할 수도 있습니다(Admin::
모듈 접두사 없이). scope
블록을 사용하여 경로를 지정할 수 있습니다:
scope "/admin" do
resources :articles
end
"/admin" path를 scope 내의 모든 routes에 추가합니다.
위의 내용을 작성하는 다른 방법:
resources :articles, path: "/admin/articles"
articles resource를 "/articles" 대신 "/admin/articles"에 매핑할 것입니다.
이러한 대안들(경로에 /admin
이 없고 모듈 접두사에 Admin::
이 없는 경우)에서는 named route helper가 scope
를 사용하지 않은 경우와 동일하게 유지됩니다.
마지막 경우에서는 다음 경로들이 ArticlesController
에 매핑됩니다:
HTTP Verb | Path | Controller#Action | Named Route Helper |
---|---|---|---|
GET | /admin/articles | articles#index | articles_path |
GET | /admin/articles/new | articles#new | new_article_path |
POST | /admin/articles | articles#create | articles_path |
GET | /admin/articles/:id | articles#show | article_path(:id) |
GET | /admin/articles/:id/edit | articles#edit | edit_article_path(:id) |
PATCH/PUT | /admin/articles/:id | articles#update | article_path(:id) |
DELETE | /admin/articles/:id | articles#destroy | article_path(:id) |
namespace
블록 내에서 다른 controller namespace를 사용해야 하는 경우, 절대 controller 경로를 지정할 수 있습니다. 예: get '/foo', to: '/foo#index'
.
2.7 중첩된 Resources
다른 resource의 논리적 자식인 resource를 가지는 것은 일반적입니다. 예를 들어 애플리케이션이 다음과 같은 model을 포함한다고 가정해봅시다:
class Magazine < ApplicationRecord
has_many :ads
end
class Ad < ApplicationRecord
belongs_to :magazine
end
중첩된 route 선언을 사용하면 라우팅에서 이러한 관계를 표현할 수 있습니다:
resources :magazines do
resources :ads
end
magazine이 여러 개의 ad를 포함하는 관계를 표현한 nested route입니다.
magazines에 대한 라우트 외에도, 이 선언은 ads를 AdsController
로 라우팅할 것입니다. 다음은 중첩된 ads
리소스에 대한 모든 라우트입니다:
HTTP Verb | Path | Controller#Action | Used to |
---|---|---|---|
GET | /magazines/:magazine_id/ads | ads#index | 특정 magazine의 모든 ad 목록 표시 |
GET | /magazines/:magazine_id/ads/new | ads#new | 특정 magazine에 속한 새로운 ad를 생성하기 위한 HTML 폼 반환 |
POST | /magazines/:magazine_id/ads | ads#create | 특정 magazine에 속한 새로운 ad 생성 |
GET | /magazines/:magazine_id/ads/:id | ads#show | 특정 magazine에 속한 특정 ad 표시 |
GET | /magazines/:magazine_id/ads/:id/edit | ads#edit | 특정 magazine에 속한 ad를 수정하기 위한 HTML 폼 반환 |
PATCH/PUT | /magazines/:magazine_id/ads/:id | ads#update | 특정 magazine에 속한 특정 ad 수정 |
DELETE | /magazines/:magazine_id/ads/:id | ads#destroy | 특정 magazine에 속한 특정 ad 삭제 |
이는 또한 magazine_ads_url
과 edit_magazine_ad_path
와 같은 일반적인 path와 url 라우팅 헬퍼들을 생성할 것입니다. ads
리소스가 magazines
아래에 중첩되어 있기 때문에, ad URL들은 magazine을 필요로 합니다. 헬퍼들은 Magazine
인스턴스를 첫 번째 파라미터로 받을 수 있습니다(edit_magazine_ad_path(@magazine, @ad)
).
2.7.1 중첩의 한계
원하는 경우 다른 중첩된 리소스 내에 리소스를 중첩할 수 있습니다. 예를 들어:
resources :publishers do
resources :magazines do
resources :photos
end
end
이는 publisher에 연결된 magazine에 연결된 photo의 nested resource를 정의합니다. 이 라우팅을 통해 publishers/1/magazines/2/photos/3
와 같은 경로를 만들 수 있습니다.
위 예제에서, 애플리케이션은 다음과 같은 path를 인식할 것입니다:
/publishers/1/magazines/2/photos/3
이에 해당하는 route helper는 publisher_magazine_photo_url
이 되며, 세 단계 모두에서 객체를 지정해야 합니다. 보시다시피, 깊이 중첩된 리소스는 지나치게 복잡해지고 유지보수하기가 어려워질 수 있습니다.
일반적인 경험칙은 리소스를 1단계 깊이로만 중첩하는 것입니다.
2.7.2 Shallow Nesting
깊은 중첩을 피하는 한 가지 방법(위에서 권장한 대로)은 부모 아래에 scoped된 collection 액션을 생성하는 것입니다. 이를 통해 계층 구조를 파악할 수 있으면서도 member 액션은 중첩하지 않습니다. 다시 말해, 리소스를 고유하게 식별하는 데 필요한 최소한의 정보로만 라우트를 구성하는 것입니다.
"member" 액션은 개별 리소스에 적용되며 특정 리소스를 식별하기 위한 ID가 필요한 show
, edit
등과 같은 액션입니다. "collection" 액션은 index
와 같이 리소스 전체 집합에 대해 동작하는 액션입니다.
예시:
resources :articles do
resources :comments, only: [:index, :new, :create]
end
resources :comments, only: [:show, :edit, :update, :destroy]
이는 댓글이 article의 컨텍스트 안에서 생성되도록 하면서도, 댓글을 보거나 편집/삭제할 때는 article이 필요하지 않도록 합니다. 이렇게 하면 다음과 같은 더 짧은 URL과 경로를 사용할 수 있습니다:
위에서는 Rails에게 지정된 라우트만 생성하도록 지시하는 :only
옵션을 사용했습니다. 이는 설명적인 라우트와 깊은 중첩 사이의 균형을 맞춥니다. :shallow
옵션을 통해 이를 달성할 수 있는 간단한 문법이 있습니다:
resources :articles do
resources :comments, shallow: true
end
shallow: true
옵션은 :comments에 대해 'shallow' 라우트를 생성합니다:
이는 첫 번째 예제와 동일한 routes를 생성합니다. 부모 resource에 :shallow
옵션을 지정할 수도 있으며, 이 경우 모든 중첩된 resource가 shallow로 처리됩니다:
resources :articles, shallow: true do
resources :comments
resources :quotes
end
이것은 위의 각 collection route를 정상적으로 생성하지만, member routes는 부모없이 생성됩니다:
/articles/1/comments
/articles/1/quotes
/comments/2
/quotes/2
위의 articles resource는 다음과 같은 라우트들을 생성할 것입니다:
HTTP Verb | Path | Controller#Action | Named Route Helper |
---|---|---|---|
GET | /articles/:article_id/comments(.:format) | comments#index | article_comments_path |
POST | /articles/:article_id/comments(.:format) | comments#create | article_comments_path |
GET | /articles/:article_id/comments/new(.:format) | comments#new | new_article_comment_path |
GET | /comments/:id/edit(.:format) | comments#edit | edit_comment_path |
GET | /comments/:id(.:format) | comments#show | comment_path |
PATCH/PUT | /comments/:id(.:format) | comments#update | comment_path |
DELETE | /comments/:id(.:format) | comments#destroy | comment_path |
GET | /articles/:article_id/quotes(.:format) | quotes#index | article_quotes_path |
POST | /articles/:article_id/quotes(.:format) | quotes#create | article_quotes_path |
GET | /articles/:article_id/quotes/new(.:format) | quotes#new | new_article_quote_path |
GET | /quotes/:id/edit(.:format) | quotes#edit | edit_quote_path |
GET | /quotes/:id(.:format) | quotes#show | quote_path |
PATCH/PUT | /quotes/:id(.:format) | quotes#update | quote_path |
DELETE | /quotes/:id(.:format) | quotes#destroy | quote_path |
GET | /articles(.:format) | articles#index | articles_path |
POST | /articles(.:format) | articles#create | articles_path |
GET | /articles/new(.:format) | articles#new | new_article_path |
GET | /articles/:id/edit(.:format) | articles#edit | edit_article_path |
GET | /articles/:id(.:format) | articles#show | article_path |
PATCH/PUT | /articles/:id(.:format) | articles#update | article_path |
DELETE | /articles/:id(.:format) | articles#destroy | article_path |
블록과 함께 사용되는 shallow
메소드는 모든 중첩이 shallow인 스코프를 생성합니다. 이는 이전 예제와 동일한 라우트를 생성합니다:
shallow do
resources :articles do
resources :comments
resources :quotes
end
end
위의 코드는 다음과 동일합니다:
resources :articles do
resources :comments, shallow: true
resources :quotes, shallow: true
end
:shallow_path
와 :shallow_prefix
이 두 가지 옵션을 scope
와 함께 사용하여 shallow 라우트를 커스터마이징할 수 있습니다.
shallow_path
옵션은 주어진 파라미터를 member 경로에 접두사로 추가합니다:
scope shallow_path: "sekret" do
resources :articles do
resources :comments, shallow: true
end
end
위 코드는 "sekret" prefix를 모든 shallow route에 추가합니다.
comments 리소스는 다음과 같은 라우트들이 생성됩니다:
HTTP Verb | Path | Controller#Action | Named Route Helper |
---|---|---|---|
GET | /articles/:article_id/comments(.:format) | comments#index | article_comments_path |
POST | /articles/:article_id/comments(.:format) | comments#create | article_comments_path |
GET | /articles/:article_id/comments/new(.:format) | comments#new | new_article_comment_path |
GET | /sekret/comments/:id/edit(.:format) | comments#edit | edit_comment_path |
GET | /sekret/comments/:id(.:format) | comments#show | comment_path |
PATCH/PUT | /sekret/comments/:id(.:format) | comments#update | comment_path |
DELETE | /sekret/comments/:id(.:format) | comments#destroy | comment_path |
:shallow_prefix
옵션은 지정된 파라미터를 _path
와 _url
라우트 헬퍼에 추가합니다:
scope shallow_prefix: "sekret" do
resources :articles do
resources :comments, shallow: true
end
end
위 코드는 shallow URL 생성 시 지정한 prefix를 URL에 사용하게 됩니다. resources가 다음과 같은 경로를 생성합니다:
comments resource는 다음과 같은 routes를 생성합니다:
HTTP Verb | Path | Controller#Action | Named Route Helper |
---|---|---|---|
GET | /articles/:article_id/comments(.:format) | comments#index | article_comments_path |
POST | /articles/:article_id/comments(.:format) | comments#create | article_comments_path |
GET | /articles/:article_id/comments/new(.:format) | comments#new | new_article_comment_path |
GET | /comments/:id/edit(.:format) | comments#edit | edit_sekret_comment_path |
GET | /comments/:id(.:format) | comments#show | sekret_comment_path |
PATCH/PUT | /comments/:id(.:format) | comments#update | sekret_comment_path |
DELETE | /comments/:id(.:format) | comments#destroy | sekret_comment_path |
2.8 Routing Concerns
Routing concerns를 사용하면 다른 resource들 안에서 재사용할 수 있는 공통 route들을 선언할 수 있습니다. concern을 정의하려면 concern
블록을 사용하세요:
concern :commentable do
resources :comments
end
concern :image_attachable do
resources :images, only: :index
end
이 코드는 concern들을 정의합니다. concern은 재사용 가능한 route들의 모음입니다. 위의 코드는 두 개의 concern을 정의합니다 - :commentable과 :image_attachable 입니다. 각각은 comments와 images resources에 대한 route들을 정의합니다.
이러한 concern들은 코드 중복을 피하고 route들 간에 동작을 공유하기 위해 resource에서 사용될 수 있습니다.
resources :messages, concerns: :commentable
resources :articles, concerns: [:commentable, :image_attachable]
메시지에 대한 resource에 commentable concern을 적용하는 예시입니다.
articles에 대한 resource에는 commentable과 image_attachable이라는 두 개의 concern을 적용하는 예시입니다.
위는 다음과 동일합니다:
resources :messages do
resources :comments
end
resources :articles do
resources :comments
resources :images, only: :index
end
이것은 자동으로 Messages와 Comments 사이의 관계, 그리고 Articles와 Comments 및 Articles와 Images 사이의 관계를 인식하고 파악할 것입니다.
scope
또는 namespace
블록 내에서 concerns
를 호출하여 위와 동일한 결과를 얻을 수도 있습니다. 예를 들어:
namespace :messages do
concerns :commentable
end
namespace :articles do
concerns :commentable
concerns :image_attachable
end
2.9 객체로부터 Path와 URL 생성하기
라우팅 헬퍼를 사용하는 것 외에도, Rails는 파라미터 배열로부터 path와 URL을 생성할 수 있습니다. 예를 들어, 다음과 같은 라우트가 있다고 가정해봅시다:
resources :magazines do
resources :ads
end
이는 magazine이 ads의 부모인 중첩된 라우트를 만듭니다.
magazine_ad_path
를 사용할 때, 숫자 ID 대신 Magazine
과 Ad
인스턴스를 전달할 수 있습니다:
<%= link_to '광고 세부정보', magazine_ad_path(@magazine, @ad) %>
생성된 path는 /magazines/5/ads/42
같은 형태가 됩니다.
위와 같은 path를 얻기 위해 url_for
를 객체 배열과 함께 사용할 수도 있습니다:
<%= link_to '광고 상세정보', url_for([@magazine, @ad]) %>
이 경우 Rails는 @magazine
이 Magazine
이고 @ad
가 Ad
임을 인식하여 magazine_ad_path
helper를 사용할 것입니다. link_to
를 작성하는 더 짧은 방법은 전체 url_for
호출 대신 객체만 지정하는 것입니다:
<%= link_to '광고 상세정보', [@magazine, @ad] %>
단순히 magazine에 링크하고 싶다면:
<%= link_to '잡지 상세정보', @magazine %>
다른 action들의 경우, 당신은 edit_magazine_ad_path
를 위해 배열의 첫 번째 요소로 action 이름을 삽입해야 합니다:
<%= link_to '광고 수정', [:edit, @magazine, @ad] %>
이를 통해 모델의 인스턴스를 URL처럼 다룰 수 있으며, 이는 resourceful 스타일을 사용하는 주요 장점입니다.
[@magazine, @ad]
와 같은 객체로부터 자동으로 경로와 URL을 도출하기 위해, Rails는 ActiveModel::Naming
과 ActiveModel::Conversion
모듈의 메서드들을 사용합니다. 구체적으로, @magazine.model_name.route_key
는 magazines
를 반환하고 @magazine.to_param
은 모델의 id
를 문자열로 반환합니다. 따라서 [@magazine, @ad]
객체에 대해 생성되는 경로는 /magazines/1/ads/42
와 같은 형태가 될 수 있습니다.
2.10 RESTful 라우트 추가하기
기본적으로 RESTful 라우팅이 생성하는 7개의 라우트로만 제한되지는 않습니다. 컬렉션이나 컬렉션의 개별 멤버에 적용되는 추가 라우트를 설정할 수 있습니다.
아래 섹션에서는 member 라우트와 collection 라우트를 추가하는 방법을 설명합니다. member
라는 용어는 show
, update
, destroy
와 같이 단일 요소에 작용하는 라우트를 의미합니다. collection
이라는 용어는 index
라우트처럼 여러 요소 또는 요소의 컬렉션에 작용하는 라우트를 의미합니다.
2.10.1 Member 라우트 추가하기
resource 블록 안에 member
블록을 다음과 같이 추가할 수 있습니다:
resources :photos do
member do
get "preview"
end
end
이렇게 하면 /photos/1/preview
같은 형태의 URL이 인식됩니다. preview action 내에서 params[:id]
를 사용하여 photo record를 찾을 수 있습니다.
/photos/1/preview
로 들어오는 GET 요청은 PhotosController
의 preview
액션으로 라우팅됩니다. 리소스 id 값은 params[:id]
에서 사용할 수 있습니다. 또한 preview_photo_url
과 preview_photo_path
헬퍼를 생성합니다.
member
블록 내에서 각 라우트 정의는 HTTP 동사를 지정합니다(위 예시에서는 get 'preview'
와 같이 get
을 사용). get
외에도 patch
, put
, post
, 또는 delete
를 사용할 수 있습니다.
여러 개의 member
라우트가 없는 경우, 블록을 없애고 :on
을 라우트에 전달할 수도 있습니다:
resources :photos do
get "preview", on: :member
end
:member
modifier를 사용하면 아래와 같이 photos#preview
를 취급하는 라우트가 생성됩니다:
:on
옵션을 생략할 수도 있습니다. 이렇게 하면 동일한 member 라우트가 생성되지만 리소스 id 값이 params[:id]
대신 params[:photo_id]
로 사용 가능합니다. 라우트 헬퍼도 preview_photo_url
과 preview_photo_path
에서 photo_preview_url
과 photo_preview_path
로 이름이 변경됩니다.
2.10.2 Collection 라우트 추가하기
collection에 라우트를 추가하려면 collection
블록을 사용하세요:
resources :photos do
collection do
get "search"
end
end
이는 /photos/search
URL을 post#search action으로 routing할 것입니다. GET 대신 collection를 통해 POST가 있는 경우, 일반적인 resourceful route를 정의하는 것과 동일한 방식으로 작동합니다.
이는 Rails가 GET 요청이 있는 /photos/search
와 같은 경로를 인식하고 PhotosController
의 search
액션으로 라우팅할 수 있게 해줍니다. 또한 search_photos_url
과 search_photos_path
라우트 헬퍼를 생성합니다.
member 라우트와 마찬가지로, 라우트에 :on
을 전달할 수 있습니다:
resources :photos do
get "search", on: :collection
end
:collection 옵션을 사용하여 컬렉션 라우트를 만듭니다. 이 라우트는 컬렉션을 위한 actions를 위한 것입니다. id가 필요하지 않은 라우트입니다.
첫 번째 위치 인자로 심볼을 사용하여 추가적인 resource route를 정의할 때는, 문자열을 사용하는 것과 동일하지 않다는 점을 주의하세요. 심볼은 controller action을 추론하고 문자열은 경로를 추론합니다.
2.10.3 추가적인 New Action에 대한 Route 추가하기
:on
단축어를 사용하여 대체 new action을 추가하려면:
resources :comments do
get "preview", on: :new
end
collection이나 member가 아닌 새로운 리소스 path에 액션을 추가합니다. 이는 /comments/new/preview
와 같은 형태의 path를 생성합니다.
이를 통해 Rails는 GET을 사용한 /comments/new/preview
와 같은 경로를 인식하고 CommentsController
의 preview
액션으로 라우팅할 수 있게 됩니다. 또한 preview_new_comment_url
과 preview_new_comment_path
라우트 헬퍼를 생성합니다.
resourceful 라우트에 많은 추가 액션을 추가하고 있다면, 잠시 멈추고 다른 리소스의 존재를 감추고 있는 것은 아닌지 자문해볼 때입니다.
resources
에 의해 생성되는 기본 라우트와 헬퍼를 커스터마이징하는 것이 가능합니다. 자세한 내용은 resourceful 라우트 커스터마이징 섹션을 참조하세요.
3 Non-Resourceful 라우트
resources
를 사용한 resourceful 라우팅 외에도, Rails는 임의의 URL을 액션에 라우팅하기 위한 강력한 지원을 제공합니다. resourceful 라우팅에 의해 자동으로 생성되는 라우트 그룹을 얻지는 못합니다. 대신, 애플리케이션 내에서 각 라우트를 개별적으로 설정합니다.
일반적으로 resourceful 라우팅을 사용해야 하지만, non-resourceful 라우팅이 더 적절한 경우가 있습니다. 애플리케이션의 모든 부분을 무리하게 resourceful 프레임워크에 맞추려고 할 필요는 없습니다.
non-resourceful 라우팅의 한 가지 사용 사례는 기존 레거시 URL을 새로운 Rails 액션에 매핑하는 것입니다.
3.1 Bound Parameters
일반적인 라우트를 설정할 때, Rails가 들어오는 HTTP 요청의 일부에 매핑하는 일련의 심볼을 제공합니다. 예를 들어, 다음의 라우트를 살펴보세요:
get "photos(/:id)", to: "photos#display"
id
가 선택적 parameter인 경로를 생성합니다. 이 라우트는 /photos/12
또는 /photos
모두 매칭될 것입니다.
만약 들어오는 GET
요청인 /photos/1
이 이 라우트에 의해 처리된다면, PhotosController
의 display
액션이 호출되고 최종 파라미터인 "1"
은 params[:id]
로 사용할 수 있게 됩니다. 이 라우트는 또한 /photos
라는 들어오는 요청을 PhotosController#display
로 라우팅할 것입니다. 왜냐하면 :id
는 위 예제에서 괄호로 표시된 선택적 파라미터이기 때문입니다.
3.2 Dynamic Segments
일반적인 라우트 내에서 원하는 만큼의 dynamic segments를 설정할 수 있습니다. 모든 segment는 params
의 일부로 액션에서 사용할 수 있습니다. 다음과 같은 라우트를 설정하면:
get "photos/:id/:user_id", to: "photos#show"
이 라우트는 /photos/1/2
와 같은 경로에 응답할 것입니다. params
해시는 { controller: 'photos', action: 'show', id: '1', user_id: '2' }가 될 것입니다.
기본적으로 dynamic segments는 점(.)을 허용하지 않습니다 - 이는 점이 formatted routes의 구분자로 사용되기 때문입니다. dynamic segment 내에서 점을 사용해야 한다면, 이를 재정의하는 제약조건을 추가하세요 - 예를 들어, id: /[^\/]+/
는 슬래시를 제외한 모든 것을 허용합니다.
3.3 Static Segments
Route를 생성할 때 세그먼트 앞에 콜론을 붙이지 않음으로써 static segment를 지정할 수 있습니다:
get "photos/:id/with_user/:user_id", to: "photos#show"
이 라우트는 /photos/1/with_user/2
와 같은 경로에 응답합니다. 이 경우 params
는 { controller: 'photos', action: 'show', id: '1', user_id: '2' }
가 됩니다.
3.4 쿼리 스트링
params
는 쿼리 스트링의 모든 파라미터도 포함합니다. 예를 들어 다음 라우트에서:
get "photos/:id", to: "photos#show"
"photos/:id"와 일치하는 요청에 라우팅합니다. 예를 들어, photos/1로의 요청은 PhotosController의 show 액션에 라우팅하며, { id: '1' } 을 params에 전달합니다.
들어오는 /photos/1?user_id=2
에 대한 GET
요청은 일반적으로 PhotosController
클래스의 show
action으로 전달되며, params
hash는 { controller: 'photos', action: 'show', id: '1', user_id: '2' }
가 됩니다.
3.5 기본 매개변수 정의하기
route에서는 :defaults
옵션에 hash를 제공하여 기본값을 정의할 수 있습니다. 이는 dynamic segments로 지정하지 않은 매개변수에도 적용됩니다. 예를 들어:
get "photos/:id", to: "photos#show", defaults: { format: "jpg" }
기본값으로 지정된 format이 있는 경우 요청하는 resource를 format 없이도 사용할 수 있습니다.
Rails는 photos/12
를 PhotosController
의 show
액션에 매칭시키고, params[:format]
을 "jpg"
로 설정할 것입니다.
또한 defaults
블록을 사용하여 여러 항목에 대한 기본값을 정의할 수 있습니다:
defaults format: :json do
resources :photos
resources :articles
end
format: :json
을 기본 형식으로 하여 라우팅 블록을 정의합니다. 블록에 있는 모든 라우트는 JSON을 기본 형식으로 사용합니다. photos
리소스와 articles
리소스가 모두 JSON 형식을 사용하게 됩니다.
보안상의 이유로 query 파라미터를 통해 defaults를 재정의할 수 없습니다. 재정의할 수 있는 defaults는 URL 경로에서 대체를 통한 동적 세그먼트뿐입니다.
3.6 Routes 명명하기
어떤 route에 대해서도 :as
옵션을 사용해서 _path
와 _url
helper에서 사용될 이름을 지정할 수 있습니다:
get "exit", to: "sessions#destroy", as: :logout
"exit" 경로를 sessions#destroy
action으로 라우팅하고 logout
이라는 이름을 지정합니다.
이렇게 하면 애플리케이션에서 route helper로 logout_path
와 logout_url
이 생성됩니다. logout_path
를 호출하면 /exit
을 반환합니다.
또한 아래와 같이 resource가 정의되기 전에 custom route 정의를 배치하여 resources
로 정의된 routing helper 이름을 as
로 덮어쓸 수 있습니다:
get ":username", to: "users#show", as: :user # 사용자명을 통해 사용자 프로필 표시
resources :users # 사용자를 위한 RESTful 라우트 생성
이는 /:username
(예: /jane
)과 매칭되는 user_path
헬퍼를 정의합니다. UsersController
의 show
액션 내에서 params[:username]
은 해당 사용자의 username을 포함하게 됩니다.
3.7 HTTP Verb 제약조건
일반적으로 라우트를 특정 HTTP verb로 제한하려면 get
, post
, put
, patch
, delete
메서드를 사용해야 합니다. 여러 개의 verb를 한 번에 매칭하려면 :via
옵션과 함께 match
메서드를 사용할 수 있습니다:
match "photos", to: "photos#show", via: [:get, :post]
다음 HTTP 메서드들에 대해서만 라우팅을 수행합니다: GET와 POST.
위 route는 PhotosController
의 show
action에 대한 GET과 POST 요청을 매칭합니다.
via: :all
을 사용하여 특정 route에 대한 모든 verb를 매칭할 수 있습니다:
"photos" 경로를 `:all` HTTP 메서드를 통해 `photos#show`로 매칭합니다.
단일 action에 GET
과 POST
요청을 모두 라우팅하는 것은 보안상 영향이 있습니다. 예를 들어, GET
action은 CSRF 토큰을 확인하지 않습니다(따라서 GET
요청으로 데이터베이스에 쓰는 것은 좋은 생각이 아닙니다. 자세한 내용은 보안 가이드를 참조하세요). 일반적으로 타당한 이유가 없다면 모든 HTTP 동사를 단일 action으로 라우팅하는 것을 피하세요.
3.8 Segment 제약사항
:constraints
옵션을 사용하여 동적 segment의 형식을 강제할 수 있습니다:
get "photos/:id", to: "photos#show", constraints: { id: /[A-Z]\d{5}/ }
이 문장은 id가 대문자 하나와 5자리 숫자로만 이루어진 요청만을 매칭합니다.
위의 라우트 정의는 id
가 5자리의 영숫자여야 합니다. 따라서 이 라우트는 /photos/A12345
와 같은 경로와는 매칭되지만 /photos/893
와는 매칭되지 않습니다. 동일한 라우트를 다음과 같이 더 간단하게 표현할 수 있습니다:
get "photos/:id", to: "photos#show", id: /[A-Z]\d{5}/
위 route는 대문자와 5자리 숫자로 구성된 ID(예: A12345)만 매칭됩니다.
:constraints
옵션은 정규표현식(또는 matches?
메소드에 응답하는 모든 객체)을 사용합니다. 단, regexp 앵커는 사용할 수 없다는 제약이 있습니다. 예를 들어, 다음 라우트는 작동하지 않습니다:
get "/:id", to: "articles#show", constraints: { id: /^\d/ }
숫자로 시작하는 :id
인 경우에만 route가 일치하도록 정의합니다.
그러나 모든 route가 시작과 끝에 정박되어 있으므로 앵커를 사용할 필요가 없다는 점에 유의하세요.
예를 들면:
get "/:id", to: "articles#show", constraints: { id: /\d.+/ }
get "/:username", to: "users#show"
첫 번째 route는 id 매개변수가 최소한 하나의 숫자(\d)로 시작하고 그 뒤에 임의의 문자(.+)가 오는 경우에만 일치하게 됩니다.
두 번째 route는 숫자로 시작하지 않는 모든 매개변수와 일치하게 됩니다. 이는 사용자 이름 기반 URL에 적합합니다.
위 routes는 root namespace를 공유하고 다음을 허용합니다:
/1-hello-world
와 같이 항상 숫자로 시작하는 route paths는id
값과 함께articles
로 라우팅됩니다./david
와 같이 절대 숫자로 시작하지 않는 route paths는username
값과 함께users
로 라우팅됩니다.
3.9 Request 기반 제약조건
Request 객체에서 String
을 반환하는 모든 메소드를 기반으로 route를 제약할 수도 있습니다.
request 기반 제약조건은 segment 제약조건을 지정하는 것과 동일한 방식으로 지정합니다. 예를 들어:
get "photos", to: "photos#index", constraints: { subdomain: "admin" }
subdomain이 "admin"인 경우에만 route가 매치됩니다.
경로가 admin
서브도메인과 일치하는 들어오는 요청과 매칭됩니다.
constraints
블록을 사용하여 제약조건을 지정할 수도 있습니다:
subdomain: "admin" 제약조건을 가진 경우에만
resources :photos
end
https://admin.example.com/photos
와 같은 것과 매칭될 것입니다.
Request 제약조건은 해시 키와 동일한 이름의 메서드를 Request 객체에서 호출하고, 반환값을 해시 값과 비교하는 방식으로 동작합니다. 예를 들어: constraints: { subdomain: 'api' }
는 예상대로 api
서브도메인과 매칭됩니다. 하지만 심볼 constraints: { subdomain: :api }
을 사용하면 매칭되지 않습니다. request.subdomain
이 문자열로 'api'
를 반환하기 때문입니다.
제약조건 값은 해당하는 Request 객체 메서드의 반환 타입과 일치해야 합니다.
format
제약조건의 경우 예외가 있습니다. Request 객체의 메서드이긴 하지만, 모든 경로에서 암시적인 선택적 파라미터이기도 합니다. 세그먼트 제약조건이 우선순위를 가지며 format
제약조건은 해시를 통해 강제될 때만 적용됩니다. 예를 들어, get 'foo', constraints: { format: 'json' }
은 GET /foo
와 매칭됩니다. format이 기본적으로 선택사항이기 때문입니다.
get 'foo', constraints: lambda { |req| req.format == :json }
와 같이 lambda를 사용하여 명시적인 JSON 요청에만 라우트를 매칭시킬 수 있습니다.
3.10 고급 Constraints
더 고급 수준의 constraint가 필요한 경우, Rails가 사용할 matches?
에 응답하는 객체를 제공할 수 있습니다. 제한된 목록에 있는 모든 사용자를 RestrictedListController
로 라우팅하려는 경우를 예로 들어보겠습니다. 다음과 같이 할 수 있습니다:
class RestrictedListConstraint
def initialize
@ips = RestrictedList.retrieve_ips
end
def matches?(request)
@ips.include?(request.remote_ip)
end
end
Rails.application.routes.draw do
get "*path", to: "restricted_list#index",
constraints: RestrictedListConstraint.new
end
위의 예제에서 RestrictedListConstraint
객체는 요청의 IP가 제한된 IP 목록에 있는지 검사하는 데 사용됩니다. *path
는 루트의 모든 요청을 매칭합니다.
제약조건을 lambda로도 지정할 수 있습니다:
Rails.application.routes.draw do
get "*path", to: "restricted_list#index",
constraints: lambda { |request| RestrictedList.retrieve_ips.include?(request.remote_ip) }
end
제약조건이 포함된 route가 처리되는 동안 특정 IP 목록을 포함하는 요청만을 받습니다. 이렇게 하면 차단된 IP 주소들이 application에 접근할 수 없습니다.
matches?
메소드와 lambda 모두 request
객체를 인자로 받습니다.
3.10.1 블록 형식의 Constraints
블록 형식으로 constraints를 지정할 수 있습니다. 이는 여러 라우트에 동일한 규칙을 적용해야 할 때 유용합니다. 예를 들어:
class RestrictedListConstraint
# ...위 예제와 동일합니다
end
Rails.application.routes.draw do
constraints(RestrictedListConstraint.new) do
get "*path", to: "restricted_list#index"
get "*other-path", to: "other_restricted_list#index"
end
end
lambda
도 사용할 수 있습니다:
Rails.application.routes.draw do
constraints(lambda { |request| RestrictedList.retrieve_ips.include?(request.remote_ip) }) do
get "*path", to: "restricted_list#index"
get "*other-path", to: "other_restricted_list#index"
end
end
특정 IP 목록이 포함된 요청만 restricted_list#index
및 other_restricted_list#index
로 라우팅되도록 제한합니다.
3.11 와일드카드 세그먼트
라우트 정의에는 와일드카드 세그먼트를 포함할 수 있습니다. 와일드카드 세그먼트는 별표로 시작하는 세그먼트입니다. 예를 들면 *other
와 같습니다:
get "photos/*other", to: "photos#unknown"
photos 이후의 모든 요청을 PhotosController의 unknown action으로 routing 합니다.
Wildcard segments는 "route globbing"이라고 불리는 것을 가능하게 하는데, 이는 특정 파라미터(위의 *other
)가 라우트의 나머지 부분과 매칭되도록 지정하는 방법입니다.
따라서 위의 라우트는 photos/12
또는 /photos/long/path/to/12
와 매칭되며, params[:other]
를 "12"
또는 "long/path/to/12"
로 설정합니다.
Wildcard segments는 라우트의 어느 위치에나 올 수 있습니다. 예를 들어:
get "books/*section/:title", to: "books#show"
books의 임의의 문자열 section과 title을 매칭시킵니다. section은 슬래시를 포함할 수 있어, "books/some/section/last-words-a-memoir/title"과 같은 요청이 { section: 'some/section/last-words-a-memoir', title: 'title' }
라는 파라미터로 인식됩니다.
이것은 params[:section]
이 'some/section'
이고 params[:title]
이 'last-words-a-memoir'
인 books/some/section/last-words-a-memoir
와 매칭됩니다.
기술적으로, 라우트는 하나 이상의 wildcard 세그먼트를 가질 수 있습니다. 매처는 세그먼트를 나타나는 순서대로 파라미터에 할당합니다. 예를 들어:
get "*a/foo/*b", to: "test#index"
zoo/woo/foo/bar/baz
를 매칭하며 params[:a]
는 'zoo/woo'
와 같고, params[:b]
는 'bar/baz'
와 같습니다.
3.12 세그먼트 포맷
다음과 같은 라우트 정의가 있다고 가정하면:
get "*pages", to: "pages#show"
이것은 URL의 모든 segments를 "pages" 파라미터에 저장하고 PagesController의 show action으로 라우팅합니다.
'/foo/bar.json'
을 요청하면, params[:pages]
는 'foo/bar'
가 되고 요청 format은 params[:format]
에 JSON으로 설정됩니다.
format
의 기본 동작은 URL에 포함되어 있다면 Rails가 자동으로 이를 캡처하여 params[:format]에 포함시키지만, URL에 format
이 반드시 필요한 것은 아닙니다.
명시적인 format이 없는 URL과 일치시키고 format 확장자가 포함된 URL을 무시하려면, 다음과 같이 format: false
를 제공할 수 있습니다:
get "*pages", to: "pages#show", format: false
어떤 format 접미사도 처리하지 않고 페이지 URL의 모든 부분을 잡아내려면, 이런 route 설정을 사용하세요.
format 세그먼트를 필수로 만들어서 생략할 수 없게 하려면, 다음과 같이 format: true
를 넣을 수 있습니다:
get "*pages", to: "pages#show", format: true
"*pages"와 매칭되는 모든 route를 pages#show
action으로 보냅니다. format을 true로 설정하면 URL에 format 매개변수가 포함될 수 있습니다.
3.13 Redirection
라우터에서 redirect
헬퍼를 사용하여 어떤 경로든 다른 경로로 리다이렉트할 수 있습니다:
get "/stories", to: redirect("/articles")
/stories
로의 요청을 /articles
로 리다이렉트합니다
리디렉션 경로 내에서 match의 동적 세그먼트를 재사용할 수도 있습니다:
get "/stories/:name", to: redirect("/articles/%{name}")
"/stories/:name" 으로 들어온 request를 "/articles/%{name}" 으로 리디렉션합니다.
redirect
에 block을 제공할 수도 있습니다. 이 block은 심볼화된 path 파라미터와 request 객체를 받습니다:
get "/stories/:name", to: redirect { |path_params, req| "/articles/#{path_params[:name].pluralize}" } # 객체의 복수형으로 stories 매개변수를 리다이렉트
get "/stories", to: redirect { |path_params, req| "/articles/#{req.subdomain}" } # 서브도메인으로 리다이렉트
기본 리다이렉션은 301 "Moved Permanently" 리다이렉트라는 점을 참고하세요. 일부 웹 브라우저나 프록시 서버가 이러한 유형의 리다이렉트를 캐시하여 이전 페이지에 접근할 수 없게 될 수 있다는 점에 유의하세요. :status
옵션을 사용하여 응답 상태를 변경할 수 있습니다.
get "/stories/:name", to: redirect("/articles/%{name}", status: 302)
:name parameter를 포함하는 URL path에서 다른 path로 redirect하는 예제입니다. redirect 메서드의 status 옵션으로 HTTP 상태 코드를 지정할 수 있습니다.
이러한 모든 경우에서 host(http://www.example.com
)를 제공하지 않으면, Rails는 현재 request에서 해당 세부 정보를 가져갑니다.
3.14 Rack Application으로 라우팅하기
:to
를 ArticlesController
클래스의 index
메서드에 해당하는 'articles#index'
와 같은 String으로 지정하는 대신, matcher의 endpoint로 어떤 Rack application이든 지정할 수 있습니다:
match "/application.js"를 MyRackApp으로 향하도록 하고, via: :all을 사용해 모든 HTTP 메소드에 대해 매칭합니다
MyRackApp
이 call
에 응답하고 [status, headers, body]
를 반환하는 한, 라우터는 Rack 애플리케이션과 컨트롤러 액션의 차이를 알 수 없습니다. 이는 Rack 애플리케이션이 모든 HTTP 동사를 처리하도록 허용하려는 경우 via: :all
을 적절하게 사용하는 예시입니다.
흥미로운 점 - 'articles#index'
는 ArticlesController.action(:index)
로 확장되며, 이는 유효한 Rack 애플리케이션을 반환합니다.
proc/lambda는 call
에 응답하는 객체이므로, 매우 간단한 라우트(예: 헬스 체크)를 인라인으로 구현할 수 있습니다. 예: get '/health', to: ->(env) { [204, {}, ['']] }
매처의 엔드포인트로 Rack 애플리케이션을 지정할 때, 수신 애플리케이션에서 라우트가 변경되지 않는다는 점을 기억하세요. 다음 라우트를 사용하는 경우 Rack 애플리케이션은 라우트가 /admin
이 될 것으로 예상해야 합니다.
match "/admin", to: AdminApp, via: :all
모든 HTTP method를 AdminApp으로 매칭합니다.
만약 Rack 애플리케이션이 루트 경로에서 요청을 받도록 하고 싶다면, mount
를 사용하세요:
AdminApp을 "/admin"에 mount 합니다
3.15 root
사용하기
root
메서드를 사용하여 Rails가 '/'
를 어디로 라우팅할지 지정할 수 있습니다:
root to: "pages#main"
root "pages#main" # 위의 단축 표현
일반적으로 root
route는 파일 최상단에 위치시켜 첫번째로 매칭될 수 있도록 합니다.
root
route는 기본적으로 GET
요청을 처리합니다. 하지만 다른 verb를 처리하도록 구성할 수도 있습니다 (예: root "posts#index", via: :post
)
namespace와 scope 내부에서도 root를 사용할 수 있습니다:
root to: "home#index" # 루트 경로를 "home" 컨트롤러의 "index" 액션으로 연결합니다
namespace :admin do
root to: "admin#index" # admin 네임스페이스의 루트 경로를 "admin" 컨트롤러의 "index" 액션으로 연결합니다
end
위 코드는 /admin
을 AdminController
의 index
action에 매칭하고, /
를 HomeController
의 index
action에 매칭합니다.
3.16 유니코드 문자 라우트
라우트에 유니코드 문자를 직접 지정할 수 있습니다. 예시:
get "안녕하세요", to: "welcome#index"
3.17 Direct Route들
direct
를 호출하여 사용자 정의 URL 헬퍼를 만들 수 있습니다. 예시:
direct :homepage do
"https://rubyonrails.org"
end
# >> homepage_url
# => "https://rubyonrails.org"
위 예시는 direct를 이용하여 homepage라는 이름의 URL을 직접 생성하는 방법을 보여줍니다. 해당 URL 생성 결과로 homepage_url을 호출하면 "https://rubyonrails.org" 가 반환됩니다.
블록의 반환값은 url_for
메서드의 인자로 유효해야 합니다. 따라서 유효한 string URL, Hash, Array, Active Model 인스턴스 또는 Active Model 클래스를 전달할 수 있습니다.
direct :commentable do |model|
[ model, anchor: model.dom_id ]
end
주석을 달 수 있는 모델로 직접 연결합니다.
direct :main do
{ controller: "pages", action: "index", subdomain: "www" }
end
# >> main_url
# => "http://www.example.com/pages"
3.18 resolve
사용하기
resolve
메소드는 모델의 polymorphic 매핑을 커스터마이징할 수 있게 해줍니다. 예를 들면:
resource :basket
resolve("Basket") { [:basket] }
:basket
resource는 단수형 리소스입니다. URL 헬퍼는 단수형(예: basket_path)을 사용하고 있지만, 실제 모델 인스턴스를 검색할 때 사용되는 라우트 해석은 복수형인 :baskets
를 사용하게 되어 있습니다. resolve
호출은 리소스 이름 매칭을 단수형으로 지정해서 이것을 수정합니다.
<%= form_with model: @basket do |form| %>
<!-- basket form -->
<% end %>
위 코드는 변경없이 그대로 유지해야 하므로 번역하지 않았습니다.
이는 일반적인 /baskets/:id
대신 단수형 URL /basket
을 생성할 것입니다.
4 Resourceful 라우트 커스터마이징
resources
에 의해 생성되는 기본 라우트와 헬퍼는 보통 잘 동작하지만, 어떤 방식으로든 이를 커스터마이징해야 할 수도 있습니다. Rails는 resourceful 라우트와 헬퍼를 커스터마이징하는 여러 가지 방법을 제공합니다. 이 섹션에서는 사용 가능한 옵션들을 자세히 설명합니다.
4.1 사용할 Controller를 지정하기
:controller
옵션을 사용하면 resource에 사용할 controller를 명시적으로 지정할 수 있습니다. 예를 들면:
resources :photos, controller: "images"
이것은 요청을 photos_controller.rb
대신 images_controller.rb
로 라우팅하도록 지정합니다.
/photos
로 시작하는 수신 경로를 인식하지만 Images
controller로 라우팅합니다:
HTTP Verb | Path | Controller#Action | Named Route Helper |
---|---|---|---|
GET | /photos | images#index | photos_path |
GET | /photos/new | images#new | new_photo_path |
POST | /photos | images#create | photos_path |
GET | /photos/:id | images#show | photo_path(:id) |
GET | /photos/:id/edit | images#edit | edit_photo_path(:id) |
PATCH/PUT | /photos/:id | images#update | photo_path(:id) |
DELETE | /photos/:id | images#destroy | photo_path(:id) |
namespace가 적용된 controller의 경우 디렉토리 표기법을 사용할 수 있습니다. 예를 들어:
resources :user_permissions, controller: "admin/user_permissions"
admin 디렉토리에 있는 user_permissions 컨트롤러를 사용하면서 URL helper는 그대로 유지됩니다.
이것은 Admin::UserPermissionsController
인스턴스로 라우팅됩니다.
디렉토리 표기법만 지원됩니다. Ruby constant 표기법(예: controller: 'Admin::UserPermissions'
)으로 controller를 지정하는 것은 지원되지 않습니다.
4.2 id
에 대한 제약 조건 지정하기
:constraints
옵션을 사용하여 암묵적인 id
에 대해 필요한 형식을 지정할 수 있습니다. 예를 들어:
resources :photos, constraints: { id: /[A-Z][A-Z][0-9]+/ }
id에 두 개의 대문자와 하나 이상의 숫자가 있어야 하는 패턴으로 제한하는 예입니다.
이 선언은 :id
파라미터가 주어진 regular expression과 일치하도록 제한합니다. 라우터는 더 이상 /photos/1
을 이 라우트에 매칭하지 않습니다. 대신 /photos/RR27
이 매칭될 것입니다.
블록 형식을 사용하여 여러 라우트에 적용할 단일 constraint를 지정할 수 있습니다:
constraints(id: /[A-Z][A-Z][0-9]+/) do
resources :photos
resources :accounts
end
이 블록 내의 모든 routes는 두 개의 대문자와 그 뒤에 숫자가 있어야 하는 id
segment에 의해 제약됩니다.
이 컨텍스트에서도 non-resourceful 라우팅 섹션에서 제공되는 advanced constraints를 사용할 수 있습니다.
기본적으로 :id
파라미터는 점(dot)을 허용하지 않습니다 - 이는 점이 formatted 라우트의 구분자로 사용되기 때문입니다. :id
내에서 점을 사용해야 한다면 이를 재정의하는 constraint를 추가하세요 - 예를 들어 id: /[^\/]+/
는 슬래시를 제외한 모든 것을 허용합니다.
4.3 Named Route Helpers 오버라이딩하기
:as
옵션을 사용하면 route helpers의 기본 명칭을 오버라이드할 수 있습니다. 예를 들어:
resources :photos, as: "images"
리소스의 URL helper를 다르게 지정할 수 있지만, path 자체는 그대로 유지합니다. URL helper를 photos_path
대신 images_path
로 사용할 수 있게 됩니다.
이것은 /photos
와 매칭되고 평소처럼 PhotosController
로 요청을 라우팅하지만, :as
옵션의 값을 사용하여 아래와 같이 헬퍼를 images_path
등으로 이름 짓습니다:
HTTP Verb | Path | Controller#Action | Named Route Helper |
---|---|---|---|
GET | /photos | photos#index | images_path |
GET | /photos/new | photos#new | new_image_path |
POST | /photos | photos#create | images_path |
GET | /photos/:id | photos#show | image_path(:id) |
GET | /photos/:id/edit | photos#edit | edit_image_path(:id) |
PATCH/PUT | /photos/:id | photos#update | image_path(:id) |
DELETE | /photos/:id | photos#destroy | image_path(:id) |
4.4 new
와 edit
경로 이름 변경하기
:path_names
옵션을 사용하면 경로의 기본 new
와 edit
세그먼트를 재정의할 수 있습니다. 예를 들어:
resources :photos, path_names: { new: "make", edit: "change" }
new나 edit와 같은 자동 생성되는 path 세그먼트를 수정합니다. 위 예제는 다음을 생성합니다:
이렇게 하면 /photos/new
와 /photos/1/edit
대신 /photos/make
와 /photos/1/change
와 같은 경로를 사용할 수 있습니다.
route helper와 controller action 이름은 이 옵션에 의해 변경되지 않습니다. 위의 두 경로는 여전히 new_photo_path
와 edit_photo_path
helper를 가지며 new
와 edit
action으로 라우팅됩니다.
scope
블록을 사용하여 모든 route에 대해 이 옵션을 일괄적으로 변경할 수도 있습니다:
scope path_names: { new: "make" } do
# 나머지 route들
end
4.5 :as
로 Named Route Helper에 접두사 붙이기
:as
옵션을 사용하여 Rails가 라우트에 대해 생성하는 named route helper에 접두사를 붙일 수 있습니다. 이 옵션은 path scope를 사용하는 라우트 간의 이름 충돌을 방지하기 위해 사용합니다. 예를 들어:
scope "admin" do
resources :photos, as: "admin_photos"
end
resources :photos
"admin" scope 내에서 photos를 admin_photos
라는 이름으로 정의하면서도, scope 외부에서는 일반적인 photos
리소스를 따로 가질 수 있습니다.
이는 /admin/photos
의 라우트 헬퍼를 photos_path
, new_photos_path
등에서 admin_photos_path
, new_admin_photo_path
등으로 변경합니다.
scoped resources :photos
에 as: 'admin_photos'
를 추가하지 않으면, non-scoped resources :photos
는 어떤 라우트 헬퍼도 가지지 않게 됩니다.
라우트 헬퍼 그룹에 접두사를 붙이려면, scope
와 함께 :as
를 사용하세요:
"admin" scope로, "admin"이라는 이름으로 스코프를 지정하고
내부에서 photos와 accounts 리소스를 정의합니다.
photos와 accounts 리소스를 정의합니다.
이전과 마찬가지로 이는 /admin
scope가 지정된 resource helper들을 admin_photos_path
와 admin_accounts_path
로 변경하고, scope가 지정되지 않은 resource들은 photos_path
와 accounts_path
를 사용할 수 있게 합니다.
namespace
scope는 :module
과 :path
prefix뿐만 아니라 :as
도 자동으로 추가합니다.
4.6 중첩된 Resource에서 :as
사용하기
:as
옵션은 중첩된 라우트에서도 resource의 라우팅 헬퍼 이름을 오버라이드할 수 있습니다. 예를 들어:
resources :magazines do
resources :ads, as: "periodical_ads"
end
위 코드는 URL helper를 다시 명명할 수 있게 해줍니다. 이 경우에는 magazine_ads_url
경로 헬퍼 대신에 magazine_periodical_ads_url
을 생성하게 됩니다.
이렇게 하면 기본값인 magazine_ads_url
과 edit_magazine_ad_path
대신에 magazine_periodical_ads_url
과 edit_magazine_periodical_ad_path
같은 routing helper가 생성됩니다.
4.7 매개변수적인 Scope들
named parameter로 routes에 접두사를 붙일 수 있습니다:
scope ":account_id", as: "account", constraints: { account_id: /\d+/ } do
resources :articles
end
:account_id
scope를 생성하며, :account_id
는 숫자로만 구성되어야 합니다. scope는 resources :articles를 포함하고 있습니다.
이렇게 하면 /1/articles/9
와 같은 path들이 제공되며, controllers, helpers, views에서 path의 account_id
부분을 params[:account_id]
로 참조할 수 있습니다.
또한 account_
로 시작하는 path와 URL helper들이 생성되어, 예상대로 객체들을 전달할 수 있습니다.
account_article_path(@account, @article) # => /1/article/9
url_for([@account, @article]) # => /1/article/9
form_with(model: [@account, @article]) # => <form action="/1/article/9" ...>
:as
옵션은 필수는 아니지만, 이것이 없으면 Rails는 url_for([@account, @article])
또는 form_with
와 같은 url_for
에 의존하는 다른 헬퍼들을 평가할 때 에러를 발생시킵니다.
4.8 생성되는 라우트 제한하기
기본적으로 resources
를 사용하면 7개의 기본 action(index
, show
, new
, create
, edit
, update
, destroy
)에 대한 라우트가 생성됩니다. :only
와 :except
옵션을 사용하여 생성되는 라우트를 제한할 수 있습니다.
:only
옵션은 Rails에게 지정된 라우트만 생성하도록 지시합니다:
resources :photos, only: [:index, :show]
인덱스와 쇼 액션만 포함한 RESTful한 라우트를 생성하고자 하는 경우에 사용할 수 있습니다.
이제 /photos
또는 /photos/:id
에 대한 GET
요청은 성공하지만, /photos
에 대한 POST
요청은 일치하지 않게 됩니다.
:except
option은 Rails가 생성하지 않아야 할 route나 route 목록을 지정합니다:
resources :photos, except: :destroy
:destroy
액션을 제외한 모든 기본 라우팅을 생성합니다.
이 경우 Rails는 destroy
라우트(/photos/:id
에 대한 DELETE
요청)를 제외한 모든 일반 라우트를 생성합니다.
애플리케이션에 많은 RESTful 라우트가 있다면 :only
와 :except
를 사용해 실제로 필요한 라우트만 생성하는 것이 사용되지 않는 라우트를 제거함으로써 메모리 사용량을 줄이고 라우팅 프로세스의 속도를 향상시킬 수 있습니다.
4.9 번역된 Path들
scope
를 사용하면 resources
로 생성된 path 이름을 변경할 수 있습니다:
scope(path_names: { new: "neu", edit: "bearbeiten" }) do
resources :categories, path: "kategorien"
end
routes를 scope로 감싸서 경로 이름을 다른 것으로 변경할 수 있습니다. 위 예시에서는 /categories/new
가 /kategorien/neu
가 되고 /categories/1/edit
은 /kategorien/1/bearbeiten
이 됩니다.
Rails는 이제 CategoriesController
로 향하는 라우트들을 생성합니다.
HTTP Verb | Path | Controller#Action | Named Route Helper |
---|---|---|---|
GET | /kategorien | categories#index | categories_path |
GET | /kategorien/neu | categories#new | new_category_path |
POST | /kategorien | categories#create | categories_path |
GET | /kategorien/:id | categories#show | category_path(:id) |
GET | /kategorien/:id/bearbeiten | categories#edit | edit_category_path(:id) |
PATCH/PUT | /kategorien/:id | categories#update | category_path(:id) |
DELETE | /kategorien/:id | categories#destroy | category_path(:id) |
4.10 Resource의 단수형 지정하기
Resource의 단수형을 재정의해야 하는 경우, inflections
를 통해 Active Support Inflector에 규칙을 추가할 수 있습니다:
ActiveSupport::Inflector.inflections do |inflect|
inflect.irregular "tooth", "teeth"
end
4.11 기본 라우트 파라미터 id
이름 변경하기
:param
옵션을 사용하여 기본 파라미터 이름 id
를 변경할 수 있습니다. 예시:
resources :videos, param: :identifier
:identifier로 지정된 param을 사용하여 :videos resource를 정의합니다.
이제 params[:id]
대신 params[:identifier]
를 사용합니다.
videos GET /videos(.:format) videos#index
POST /videos(.:format) videos#create
new_video GET /videos/new(.:format) videos#new
edit_video GET /videos/:identifier/edit(.:format) videos#edit
Video.find_by(id: params[:identifier])
# 다음과 같이 하는 대신
Video.find_by(id: params[:id])
연관된 모델의 URL을 생성하기 위해 ActiveRecord::Base#to_param
을 오버라이드할 수 있습니다:
class Video < ApplicationRecord
def to_param
identifier
end
end
한 모델에서 URL에 기본 id 대신 다른 속성을 사용하기를 원한다면, to_param
메서드를 오버라이드하세요.
irb> video = Video.find_by(identifier: "Roman-Holiday")
irb> edit_video_path(video)
=> "/videos/Roman-Holiday/edit"
5 라우트 검사하기
Rails는 라우트를 검사하고 테스트할 수 있는 몇 가지 다른 방법을 제공합니다.
5.1 기존 라우트 나열하기
애플리케이션에서 사용 가능한 라우트의 전체 목록을 보려면, development 환경에서 http://localhost:3000/rails/info/routes
를 방문하세요. 터미널에서 bin/rails routes
명령어를 실행하여 동일한 출력을 얻을 수도 있습니다.
두 방법 모두 config/routes.rb
에 나타나는 순서대로 모든 라우트를 나열할 것입니다. 각 라우트에 대해 다음과 같은 정보를 볼 수 있습니다:
- 라우트 이름(있는 경우)
- 사용된 HTTP verb(라우트가 모든 verb에 응답하지 않는 경우)
- 매칭할 URL 패턴
- 해당 라우트의 라우팅 파라미터
예를 들어, 다음은 RESTful 라우트에 대한 bin/rails routes
출력의 작은 부분입니다:
users GET /users(.:format) users#index
POST /users(.:format) users#create
new_user GET /users/new(.:format) users#new
edit_user GET /users/:id/edit(.:format) users#edit
라우트 이름(예를 들어 위의 new_user
)은 라우트 헬퍼를 생성하는 기본이 될 수 있습니다. 라우트 헬퍼의 이름을 얻으려면 라우트 이름에 _path
또는 _url
접미사를 추가하세요(예: new_user_path
).
또한 --expanded
옵션을 사용하여 확장된 테이블 포맷팅 모드를 켤 수 있습니다.
$ bin/rails routes --expanded
--[ Route 1 ]----------------------------------------------------
Prefix | users
Verb | GET
URI | /users(.:format)
Controller#Action | users#index
--[ Route 2 ]----------------------------------------------------
Prefix |
Verb | POST
URI | /users(.:format)
Controller#Action | users#create
--[ Route 3 ]----------------------------------------------------
Prefix | new_user
Verb | GET
URI | /users/new(.:format)
Controller#Action | users#new
--[ Route 4 ]----------------------------------------------------
Prefix | edit_user
Verb | GET
URI | /users/:id/edit(.:format)
Controller#Action | users#edit
5.2 Routes 검색하기
grep 옵션 -g
을 사용하여 routes를 검색할 수 있습니다. 이는 URL helper 메소드 이름, HTTP verb, URL 경로와 부분적으로 일치하는 모든 routes를 출력합니다.
$ bin/rails routes -g new_comment
$ bin/rails routes -g POST
$ bin/rails routes -g admin
Rails route를 검색할 때 pattern matching을 사용할 수 있습니다. pattern을 -g와 함께 지정하면 경로 이름, HTTP 메서드 또는 URL 경로와 매칭되는 route들만 표시됩니다.
특정 controller에 매핑되는 routes만 보고 싶다면, -c
controller 옵션을 사용할 수 있습니다.
$ bin/rails routes -c users
$ bin/rails routes -c admin/users
$ bin/rails routes -c Comments
$ bin/rails routes -c Articles::CommentsController
위 명령어들은 특정 controller의 route만 표시합니다.
터미널 창을 출력 라인이 줄바꿈되지 않을 때까지 넓히거나 --expanded
옵션을 사용하면 bin/rails routes
의 출력을 더 쉽게 읽을 수 있습니다.
5.3 사용되지 않는 Route 목록 보기
--unused
옵션을 사용하면 애플리케이션에서 사용되지 않는 route를 스캔할 수 있습니다. Rails에서 "사용되지 않는" route는 config/routes.rb 파일에 정의되어 있지만 애플리케이션의 어떤 controller action이나 view에서도 참조되지 않는 route를 말합니다. 예시:
$ bin/rails routes --unused
사용되지 않는 route 8개를 찾았습니다:
Prefix Verb URI Pattern Controller#Action
people GET /people(.:format) people#index
POST /people(.:format) people#create
new_person GET /people/new(.:format) people#new
edit_person GET /people/:id/edit(.:format) people#edit
person GET /people/:id(.:format) people#show
PATCH /people/:id(.:format) people#update
PUT /people/:id(.:format) people#update
DELETE /people/:id(.:format) people#destroy
5.4 Rails Console에서의 Routes
Rails Console 내에서 Rails.application.routes.url_helpers
를 사용하여 route helper에 접근할 수 있습니다. 이들은 app 객체를 통해서도 사용할 수 있습니다. 예시:
irb> Rails.application.routes.url_helpers.users_path
=> "/users"
irb> user = User.first
=> #<User:0x00007fc1eab81628
irb> app.edit_user_path(user)
=> "/users/1/edit"
6 Routes 테스트하기
Rails는 routes 테스트를 더 간단하게 만들기 위해 3가지 내장된 assertion을 제공합니다:
6.1 assert_generates
Assertion
assert_generates
는 특정 옵션 세트가 특정 경로를 생성하는지 검증하며 기본 라우트나 커스텀 라우트에서 사용할 수 있습니다. 예시:
assert_generates "/photos/1", { controller: "photos", action: "show", id: "1" }
assert_generates "/about", controller: "pages", action: "about"
위 코드는 주어진 URL 경로가 올바른 route 매핑으로 생성되었는지를 검증합니다.
6.2 assert_recognizes
Assertion
assert_recognizes
는 assert_generates
의 반대입니다. 주어진 경로가 인식되고 애플리케이션의 특정 위치로 라우팅되는지 검증합니다. 예를 들어:
assert_recognizes({ controller: "photos", action: "show", id: "1" }, "/photos/1")
이것은 요청 "/photos/1"이 지정된 controller, action, parameters를 인식하는지 확인합니다.
HTTP verb를 지정하기 위해 :method
인자를 제공할 수 있습니다:
assert_recognizes({ controller: "photos", action: "create" }, { path: "photos", method: :post })
path와 method가 주어진 controller와 action으로 인식되는지 검증합니다.
6.3 assert_routing
Assertion
assert_routing
assertion은 양방향으로 라우트를 체크합니다. assert_generates
와 assert_recognizes
의 기능을 합친 것입니다. 경로가 옵션을 생성하는지, 그리고 옵션이 경로를 생성하는지 모두 테스트합니다:
assert_routing({ path: "photos", method: :post }, { controller: "photos", action: "create" })
주어진 path와 HTTP method가 올바른 controller와 action으로 routing되는지 assertion합니다.
7 draw
로 큰 라우트 파일 분리하기
수천 개의 라우트가 있는 대규모 애플리케이션에서는 단일 config/routes.rb
파일이 다루기 어렵고 읽기 힘들어질 수 있습니다. Rails는 draw
매크로를 사용하여 하나의 routes.rb
파일을 여러 개의 작은 파일로 분리하는 방법을 제공합니다.
예를 들어, admin 영역과 관련된 모든 라우트를 포함하는 admin.rb
파일과 API 관련 리소스를 위한 api.rb
파일 등을 추가할 수 있습니다.
# config/routes.rb
Rails.application.routes.draw do
get "foo", to: "foo#bar"
draw(:admin) # `config/routes/admin.rb`에 위치한 다른 route 파일을 로드할 것입니다
end
# config/routes/admin.rb
namespace :admin do
resources :comments
end
Rails.application.routes.draw
블록 내에서 draw(:admin)
를 호출하면 주어진 인자와 동일한 이름을 가진 route 파일(이 예시에서는 admin.rb
)을 로드하려고 시도합니다. 이 파일은 config/routes
디렉토리나 하위 디렉토리(예: config/routes/admin.rb
또는 config/routes/external/admin.rb
) 내에 위치해야 합니다.
admin.rb
와 같은 보조 라우팅 파일 내에서 일반적인 라우팅 DSL을 사용할 수 있지만, Rails.application.routes.draw
블록으로 감싸지는 마세요. 이는 메인 config/routes.rb
파일에서만 사용되어야 합니다.
정말 필요한 경우가 아니라면 이 기능을 사용하지 마세요. 여러 개의 라우팅 파일을 사용하면 한 곳에서 route들을 발견하기가 더 어려워집니다. 대부분의 애플리케이션에서는 - 심지어 수백 개의 route가 있는 경우에도 - 개발자들에게는 단일 라우팅 파일을 가지는 것이 더 쉽습니다. Rails 라우팅 DSL은 이미 namespace
와 scope
를 통해 route들을 체계적으로 분리하는 방법을 제공합니다.