Rails 외부에서의 라우팅
이 가이드는 Rails 라우팅의 사용자 중심 기능을 다룹니다.
이 가이드를 읽고 나면 다음을 알 수 있습니다:
config/routes.rb
의 코드를 해석하는 방법.- 선호되는 리소스 스타일 또는
match
메서드를 사용하여 자신만의 경로를 구축하는 방법. - 컨트롤러 작업에 전달되는 경로 매개변수를 선언하는 방법.
- 경로 헬퍼를 사용하여 경로와 URL을 자동으로 생성하는 방법.
- 제약 조건 생성 및 Rack 엔드포인트 마운팅과 같은 고급 기술.
Rails 라우터의 목적
Rails 라우터는 URL을 인식하고 컨트롤러의 작업 또는 Rack 애플리케이션으로 디스패치합니다. 또한 문자열을 뷰에 하드코딩할 필요 없이 경로와 URL을 생성할 수 있습니다.
URL을 코드에 연결하기
Rails 애플리케이션이 다음과 같은 들어오는 요청을 받으면:
GET /patients/17
라우터에게 이를 컨트롤러 작업과 일치시키도록 요청합니다. 첫 번째 일치하는 경로가 다음과 같은 경우:
get '/patients/:id', to: 'patients#show'
요청은 params
에 { id: '17' }
이 포함된 상태로 patients
컨트롤러의 show
작업으로 디스패치됩니다.
참고: Rails는 여기서 컨트롤러 이름에 snakecase를 사용합니다. 예를 들어 MonsterTrucksController
와 같은 다중 단어 컨트롤러의 경우 `monstertrucks#show`를 사용해야 합니다.
코드에서 경로와 URL 생성하기
경로와 URL도 생성할 수 있습니다. 위의 경로가 다음과 같이 수정된 경우:
get '/patients/:id', to: 'patients#show', as: 'patient'
그리고 애플리케이션에 다음과 같은 컨트롤러 코드가 있는 경우:
@patient = Patient.find(params[:id])
그리고 해당 뷰에 다음과 같은 코드가 있는 경우:
<%= link_to 'Patient Record', patient_path(@patient) %>
그러면 라우터가 /patients/17
을 생성합니다. 이렇게 하면 뷰의 취약성이 줄어들고 코드를 더 쉽게 이해할 수 있습니다. 참고로 id는 경로 헬퍼에 지정할 필요가 없습니다.
Rails 라우터 구성하기
애플리케이션 또는 엔진의 경로는 config/routes.rb
파일에 있으며 일반적으로 다음과 같습니다:
Rails.application.routes.draw do resources :brands, only: [:index, :show] do resources :products, only: [:index, :show] end resource :basket, only: [:show, :update, :destroy] resolve("Basket") { route_for(:basket) } end
이것은 일반 Ruby 소스 파일이므로 경로를 정의할 때 모든 기능을 사용할 수 있지만 변수 이름이 라우터 DSL 메서드와 충돌할 수 있으므로 주의해야 합니다.
참고: 경로 정의를 감싸는 Rails.application.routes.draw do ... end
블록은 라우터 DSL의 범위를 설정하는 데 필요하며 삭제해서는 안 됩니다.
리소스 라우팅: Rails 기본값
리소스 라우팅을 사용하면 특정 리소스 컨트롤러에 대한 일반적인 모든 경로를 빠르게 선언할 수 있습니다. resources
에 대한 단일 호출로 index
, show
, new
, edit
, create
, update
및 destroy
작업에 필요한 모든 경로를 선언할 수 있습니다.
웹의 리소스
브라우저는 GET
, POST
, PATCH
, PUT
및 DELETE
와 같은 특정 HTTP 메서드를 사용하여 Rails에서 페이지를 요청합니다. 각 메서드는 리소스에 대한 작업을 수행하는 요청입니다. 리소스 경로는 단일 컨트롤러의 여러 관련 요청을 작업에 매핑합니다.
Rails 애플리케이션이 다음과 같은 들어오는 요청을 받으면:
DELETE /photos/17
라우터에게 이를 컨트롤러 작업에 매핑하도록 요청합니다. 첫 번째 일치하는 경로가 다음과 같은 경우:
resources :photos
Rails는 params
에 { id: '17' }
이 포함된 상태로 photos
컨트롤러의 destroy
작업으로 해당 요청을 디스패치합니다.
CRUD, 동사 및 작업
Rails에서 리소스 경로는 HTTP 동사와 URL을 컨트롤러 작업에 매핑합니다. 관례에 따라 각 작업은 데이터베이스의 특정 CRUD 작업에도 매핑됩니다. 라우팅 파일의 단일 항목, 예를 들어:
resources :photos
은 Photos
컨트롤러에 매핑되는 7개의 다른 경로를 애플리케이션에 생성합니다:
HTTP 동사 | 경로 | 컨트롤러#작업 | 사용 목적 |
---|---|---|---|
GET | /photos | photos#index | 모든 사진 목록 표시 |
GET | /photos/new | photos#new | 새 사진 생성을 위한 HTML 양식 반환 |
POST | /photos | photos#create | 새 사진 생성 |
GET | /photos/:id | photos#show | 특정 사진 표시 |
GET | /photos/:id/edit | photos#edit | 사진 편집을 위한 HTML 양식 반환 |
PATCH/PUT | /photos/:id | photos#update | 특정 사진 업데이트 |
DELETE | /photos/:id | photos#destroy | 특정 사진 삭제 |
참고: 라우터는 HTTP 동사와 URL을 사용하여 들어오는 요청을 일치시키므로 4개의 URL이 7개의 다른 작업에 매핑됩니다.
참고: Rails 경로는 지정된 순서대로 일치되므로 resources :photos
위에 get 'photos/poll'
이 있는 경우 resources
줄의 show
작업 경로가 get
줄보다 먼저 일치됩니다. 이를 해결하려면 get
줄을 resources
줄 위로 이동하여 먼저 일치되도록 합니다.
경로 및 URL 헬퍼
리소스 경로를 생성하면 애플리케이션의 컨트롤러에 여러 헬퍼가 노출됩니다. resources :photos
의 경우:
photos_path
는/photos
를 반환합니다.new_photo_path
는/photos/new
를 반환합니다.edit_photo_path(:id)
는/photos/:id/edit
를 반환합니다(예:edit_photo_path(10)
은/photos/10/edit
를 반환).photo_path(:id)
는/photos/:id
를 반환합니다(예:photo_path(10)
은/photos/10
를 반환).
각각의 헬퍼에는 현재 호스트, 포트 및 경로 접두사로 시작하는 동일한 경로의 _url
헬퍼(예: photos_url
)가 있습니다.
팁: 경로 헬퍼 이름을 찾으려면 아래의 기존 경로 나열하기를 참조하세요.
한 번에 여러 리소스 정의하기
여러 리소스에 대한 경로를 생성해야 하는 경우 resources
호출을 한 번만 하면 타이핑을 줄일 수 있습니다:
resources :photos, :books, :videos
이것은 다음과 정확히 같습니다:
resources :photos resources :books resources :videos
단일 리소스
때로는 클라이언트가 ID를 참조하지 않고 항상 조회하는 리소스가 있습니다. 예를 들어 현재 로그인한 사용자의 프로필을 항상 표시하고 싶을 수 있습니다. 이 경우 단일 리소스를 사용하여 /profile
(rather than /profile/:id
)를 show
작업에 매핑할 수 있습니다:
get 'profile', to: 'users#show'
to:
에 String
을 전달하면 controller#action
형식을 예상합니다. Symbol
을 사용할 때는 to:
옵션을 action:
으로 바꿔야 합니다. #
이 없는 String
을 사용할 때는 to:
옵션을 controller:
로 바꿔야 합니다:
get 'profile', action: :show, controller: 'users'
이 리소스 경로:
resource :geocoder resolve('Geocoder') { [:geocoder] }
은 Geocoders
컨트롤러에 매핑되는 6개의 다른 경로를 애플리케이션에 생성합니다:
HTTP 동사 | 경로 | 컨트롤러#작업 | 사용 목적 |
---|---|---|---|
GET | /geocoder/new | geocoders#new | 지오코더 생성을 위한 HTML 양식 반환 |
POST | /geocoder | geocoders#create | 새 지오코더 생성 |
GET | /geocoder | geocoders#show | 하나의 지오코더 리소스 표시 |
GET | /geocoder/edit | geocoders#edit | 지오코더 편집을 위한 HTML 양식 반환 |
PATCH/PUT | /geocoder | geocoders#update | 하나의 지오코더 리소스 업데이트 |
DELETE | /geocoder | geocoders#destroy | 지오코더 리소스 삭제 |
참고: 단일 경로(/account
)와 복수 경로(/accounts/45
)에 동일한 컨트롤러를 사용하고 싶을 수 있으므로 단일 리소스는 복수 컨트롤러에 매핑됩니다. 따라서 resource :photo
와 resources :photos
는 동일한 컨트롤러(PhotosController
)에 매핑되는 단일 및 복수 경로를 생성합니다.
단일 리소스 경로는 다음과 같은 헬퍼를 생성합니다:
new_geocoder_path
는/geocoder/new
를 반환합니다.edit_geocoder_path
는/geocoder/edit
를 반환합니다.geocoder_path
는/geocoder
를 반환합니다.
참고: resolve
호출은 레코드 식별을 통해 Geocoder
인스턴스를 경로로 변환하는 데 필요합니다.
복수 리소스와 마찬가지로 _url
끝나는 동일한 헬퍼에는 호스트, 포트 및 경로 접두사도 포함됩니다.
컨트롤러 네임스페이스 및 라우팅
컨트롤러 그룹을 네임스페이스 아래에 구성하고 싶을 수 있습니다. 가장 일반적으로 Admin::
네임스페이스 아래에 여러 관리 컨트롤러를 그룹화하고 이를 app/controllers/admin
디렉토리에 배치할 수 있습니다. namespace
블록을 사용하여 이러한 그룹에 경로를 지정할네, 계속해서 번역하겠습니다.
컨트롤러 네임스페이스 및 라우팅 (계속)
namespace :admin do resources :articles, :comments end
이렇게 하면 각각의 articles
와 comments
컨트롤러에 대한 여러 경로가 생성됩니다. Admin::ArticlesController
의 경우 Rails는 다음과 같은 경로를 생성합니다:
HTTP 동사 | 경로 | 컨트롤러#작업 | 명명된 경로 헬퍼 |
---|---|---|---|
GET | /admin/articles | admin/articles#index | adminarticlespath |
GET | /admin/articles/new | admin/articles#new | newadminarticle_path |
POST | /admin/articles | admin/articles#create | adminarticlespath |
GET | /admin/articles/:id | admin/articles#show | adminarticlepath(:id) |
GET | /admin/articles/:id/edit | admin/articles#edit | editadminarticle_path(:id) |
PATCH/PUT | /admin/articles/:id | admin/articles#update | adminarticlepath(:id) |
DELETE | /admin/articles/:id | admin/articles#destroy | adminarticlepath(:id) |
대신 /articles
(prefix /admin
없음)를 Admin::ArticlesController
로 라우팅하려면 scope
블록을 사용할 수 있습니다:
scope module: 'admin' do resources :articles, :comments end
단일 경로에 대해서도 이렇게 할 수 있습니다:
resources :articles, module: 'admin'
반면에 /admin/articles
를 ArticlesController
(prefix Admin::
없음)로 라우팅하려면 scope
블록에서 경로를 지정할 수 있습니다:
scope '/admin' do resources :articles, :comments end
단일 경로에 대해서도 이렇게 할 수 있습니다:
resources :articles, path: '/admin/articles'
이 두 경우 모두 명명된 경로 헬퍼는 scope
를 사용하지 않은 것과 동일합니다. 마지막 경우 다음과 같은 경로가 ArticlesController
에 매핑됩니다:
HTTP 동사 | 경로 | 컨트롤러#작업 | 명명된 경로 헬퍼 |
---|---|---|---|
GET | /admin/articles | articles#index | articles_path |
GET | /admin/articles/new | articles#new | newarticlepath |
POST | /admin/articles | articles#create | articles_path |
GET | /admin/articles/:id | articles#show | article_path(:id) |
GET | /admin/articles/:id/edit | articles#edit | editarticlepath(:id) |
PATCH/PUT | /admin/articles/:id | articles#update | article_path(:id) |
DELETE | /admin/articles/:id | articles#destroy | article_path(:id) |
팁: 네임스페이스 블록 내에서 다른 컨트롤러 네임스페이스를 사용해야 하는 경우 절대 컨트롤러 경로를 지정할 수 있습니다. 예: get '/foo', to: '/foo#index'
.
중첩 리소스
다른 리소스의 논리적 자식인 리소스가 있는 경우가 일반적입니다. 예를 들어 애플리케이션에 다음과 같은 모델이 포함되어 있다고 가정합니다:
class Magazine < ApplicationRecord has_many :ads end class Ad < ApplicationRecord belongs_to :magazine end
중첩 경로를 사용하면 라우팅에서 이 관계를 캡처할 수 있습니다. 이 경우 다음과 같은 경로 선언을 포함할 수 있습니다:
resources :magazines do resources :ads end
매거진에 대한 경로 외에도 이 선언은 AdsController
로 광고를 라우팅합니다. 광고 URL에는 매거진이 필요합니다:
HTTP 동사 | 경로 | 컨트롤러#작업 | 사용 목적 |
---|---|---|---|
GET | /magazines/:magazine_id/ads | ads#index | 특정 매거진에 대한 모든 광고 목록 표시 |
GET | /magazines/:magazine_id/ads/new | ads#new | 특정 매거진에 속하는 새 광고 생성을 위한 HTML 양식 반환 |
POST | /magazines/:magazine_id/ads | ads#create | 특정 매거진에 속하는 새 광고 생성 |
GET | /magazines/:magazine_id/ads/:id | ads#show | 특정 매거진에 속하는 특정 광고 표시 |
GET | /magazines/:magazine_id/ads/:id/edit | ads#edit | 특정 매거진에 속하는 광고 편집을 위한 HTML 양식 반환 |
PATCH/PUT | /magazines/:magazine_id/ads/:id | ads#update | 특정 매거진에 속하는 특정 광고 업데이트 |
DELETE | /magazines/:magazine_id/ads/:id | ads#destroy | 특정 매거진에 속하는 특정 광고 삭제 |
이렇게 하면 magazine_ads_url
및 edit_magazine_ad_path
와 같은 라우팅 헬퍼도 생성됩니다. 이러한 헬퍼는 첫 번째 매개변수로 Magazine의 인스턴스를 사용합니다(magazine_ads_url(@magazine)
).
중첩의 한계
다른 중첩 리소스 내에 리소스를 중첩할 수도 있습니다. 예를 들어:
resources :publishers do resources :magazines do resources :photos end end
깊이 중첩된 리소스는 빠르게 복잡해집니다. 이 경우 예를 들어 애플리케이션은 다음과 같은 경로를 인식할 것입니다:
/publishers/1/magazines/2/photos/3
해당 경로 헬퍼는 publisher_magazine_photo_url
이 될 것이며, 세 레벨의 모든 객체를 지정해야 합니다. 실제로 이 상황은 Jamis Buck의 유명한 기사에서 제안한 규칙을 혼란스럽게 할 정도입니다:
팁: 리소스는 절대 1 레벨 이상 중첩되어서는 안 됩니다.
얕은 중첩
위에서 권장한 대로 깊은 중첩을 피하는 한 가지 방법은 부모 범위 아래에 컬렉션 작업을 생성하여 계층 구조를 파악할 수 있지만 멤버 작업은 중첩하지 않는 것입니다. 즉, 리소스를 고유하게 식별하는 데 필요한 최소한의 정보로만 경로를 생성하는 것입니다. 예를 들어:
resources :articles do resources :comments, only: [:index, :new, :create] end resources :comments, only: [:show, :edit, :update, :destroy]
이 아이디어는 설명적인 경로와 깊은 중첩 사이의 균형을 잡습니다. 이를 달성하기 위한 단축 구문이 :shallow
옵션을 통해 존재합니다:
resources :articles do resources :comments, shallow: true end
이렇게 하면 첫 번째 예와 정확히 같은 경로가 생성됩니다. 또한 부모 리소스에서 :shallow
옵션을 지정할 수 있으며, 이 경우 모든 중첩 리소스가 얕아집니다:
resources :articles, shallow: true do resources :comments resources :quotes resources :drafts end
여기서 articles 리소스에 대해 다음과 같은 경로가 생성됩니다:
HTTP 동사 | 경로 | 컨트롤러#작업 | 명명된 경로 헬퍼 |
---|---|---|---|
GET | /articles/:article_id/comments(.:format) | comments#index | articlecommentspath |
POST | /articles/:article_id/comments(.:format) | comments#create | articlecommentspath |
GET | /articles/:article_id/comments/new(.:format) | comments#new | newarticlecomment_path |
GET | /comments/:id/edit(.:format) | comments#edit | editcommentpath |
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 | articlequotespath |
POST | /articles/:article_id/quotes(.:format) | quotes#create | articlequotespath |
GET | /articles/:article_id/quotes/new(.:format) | quotes#new | newarticlequote_path |
GET | /quotes/:id/edit(.:format) | quotes#edit | editquotepath |
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/:article_id/drafts(.:format) | drafts#index | articledraftspath |
POST | /articles/:article_id/drafts(.:format) | drafts#create | articledraftspath |
GET | /articles/:article_id/drafts/new(.:format) | drafts#new | newarticledraft_path |
GET | /drafts/:id/edit(.:format) | drafts#edit | editdraftpath |
GET | /drafts/:id(.:format) | drafts#show | draft_path |
PATCH/PUT | /drafts/:id(.:format) | drafts#update | draft_path |
DELETE | /drafts/:id(.:format) | drafts#destroy | draft_path |
GET | /articles(.:format) | articles#index | articles_path |
POST | /articles(.:format) | articles#create | articles_path |
GET | /articles/new(.:format) | articles#new | newarticlepath |
GET | /articles/:id/edit(.:format) | articles#edit | editarticlepath |
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
][] DSL 메서드는 중첩 내에서 모든 것이 얕아지는 범위를 만듭니다. 이렇게 하면 이전 예와 동일한 경로가 생성됩니다:
shallow do resources :articles do resources :comments resources :quotes resources :drafts end end
scope
에는 얕은 경로를 사용자 정의하기 위한 두 가지 옵션이 있습니다. :shallow_path
는 지정된 매개변수로 멤버 경로를 접두사로 붙입니다:
scope shallow_path: "sekret" do resources :articles do resources :comments, shallow: true end end
여기서 comments 리소스에 대해 다음과 같은 경로가 생성됩니다:
HTTP 동사 | 경로 | 컨트롤러#작업 | 명명된 경로 헬퍼 |
---|---|---|---|
GET | /articles/:article_id/comments(.:format) | comments#index | articlecommentspath |
POST | /articles/:article_id/comments(.:format) | comments#create | articlecommentspath |
GET | /articles/:article_id/comments/new(.:format) | comments#new | newarticlecomment_path |
GET | /sekret/comments/:id/edit(.:format) | comments#edit | editcommentpath |
GET | /sekret/comments/:id(.:format) | comments#show | comment_path |
PATCH/PUT | /sekret/comments/:id(.:format) | comments#update | comment_path |
네, 계속해서 번역하겠습니다. |
라우팅 관심사
라우팅 관심사를 사용하면 다른 리소스와 경로 내에서 재사용할 수 있는 공통 경로를 선언할 수 있습니다. 관심사를 정의하려면 concern
블록을 사용합니다:
concern :commentable do resources :comments end concern :image_attachable do resources :images, only: :index end
이러한 관심사는 코드 중복을 방지하고 경로 간에 동작을 공유하기 위해 리소스에서 사용할 수 있습니다:
resources :messages, concerns: :commentable resources :articles, concerns: [:commentable, :image_attachable]
위와 같은 것은 다음과 같습니다:
resources :messages do resources :comments end resources :articles do resources :comments resources :images, only: :index end
또한 concerns
를 호출하여 어디서든 사용할 수 있습니다. 예를 들어 scope
또는 namespace
블록 내에서:
namespace :articles do concerns :commentable end
객체에서 경로와 URL 생성하기
라우팅 헬퍼를 사용하는 것 외에도 Rails는 매개변수 배열에서 경로와 URL을 생성할 수 있습니다. 예를 들어 다음과 같은 경로 집합이 있다고 가정합니다:
resources :magazines do resources :ads end
magazine_ad_path
를 사용할 때 숫자 ID 대신 Magazine
및 Ad
인스턴스를 전달할 수 있습니다:
<%= link_to 'Ad details', magazine_ad_path(@magazine, @ad) %>
또한 url_for
를 객체 집합과 함께 사용할 수 있으며, Rails는 자동으로 사용할 경로를 결정합니다:
<%= link_to 'Ad details', url_for([@magazine, @ad]) %>
이 경우 Rails는 @magazine
이 Magazine
이고 @ad
가 Ad
라는 것을 알아차리고 magazine_ad_path
헬퍼를 사용합니다. link_to
와 같은 헬퍼에서 url_for
호출 전체 대신 객체만 지정할 수 있습니다:
<%= link_to 'Ad details', [@magazine, @ad] %>
매거진만 연결하려면:
<%= link_to 'Magazine details', @magazine %>
다른 작업의 경우 작업 이름을 배열의 첫 번째 요소로 삽입하면 됩니다:
<%= link_to 'Edit Ad', [:edit, @magazine, @ad] %>
이를 통해 모델 인스턴스를 URL로 처리할 수 있으며, 리소스 스타일을 사용하는 주요 이점 중 하나입니다.
추가 RESTful 작업 추가하기
기본적으로 RESTful 라우팅이 생성하는 7개의 경로로 제한되지 않습니다. 원하는 경우 컬렉션 또는 개별 구성원에 대한 추가 경로를 추가할 수 있습니다.
멤버 경로 추가하기
멤버 경로를 추가하려면 리소스 블록 내에 member
블록을 추가하면 됩니다:
resources :photos do member do get 'preview' end end
이렇게 하면 GET /photos/1/preview
를 인식하고 PhotosController
의 preview
작업으로 라우팅합니다. 리소스 ID 값은 params[:id]
에 전달됩니다. preview_photo_url
및 preview_photo_path
헬퍼도 생성됩니다.
멤버 경로 블록 내에서 각 경로 이름은 인식할 HTTP 동사를 지정합니다. get
, patch
, put
, post
, 또는 delete
를 여기서 사용할 수 있습니다. 여러 member
경로가 없는 경우 :on
을 경로에 전달하여 블록을 제거할 수도 있습니다:
resources :photos do get 'preview', on: :member end
:on
옵션을 생략할 수 있습니다. 이렇게 하면 동일한 멤버 경로가 생성되지만 리소스 ID 값은 params[:photo_id]
가 아닌 params[:id]
에 있습니다. 경로 헬퍼의 이름도 preview_photo_url
및 preview_photo_path
에서 photo_preview_url
및 photo_preview_path
로 변경됩니다.
컬렉션 경로 추가하기
컬렉션에 경로를 추가하려면 collection
블록을 사용합니다:
resources :photos do collection do get 'search' end end
이렇게 하면 Rails가 GET /photos/search
와 같은 경로를 인식하고 PhotosController
의 search
작업으로 라우팅할 수 있습니다. search_photos_url
및 search_photos_path
경로 헬퍼도 생성됩니다.
멤버 경로와 마찬가지로 :on
을 경로에 전달할 수 있습니다:
resources :photos do get 'search', on: :collection end
참고: 첫 번째 위치 인수로 기호를 정의하는 추가 리소스 경로를 정의할 때는 기호와 문자열이 동등하지 않다는 점에 유의하세요. 기호는 컨트롤러 작업을 추론하지만 문자열은 경로를 추론합니다.
추가 새 작업에 대한 경로 추가하기
:on
단축키를 사용하여 대체 새 작업을 추가하려면:
resources :comments do get 'preview', on: :new end
이렇게 하면 Rails가 GET /comments/new/preview
와 같은 경로를 인식하고 CommentsController
의 preview
작업으로 라우팅할 수 있습니다. preview_new_comment_url
및 preview_new_comment_path
경로 헬퍼도 생성됩니다.
팁: 리소스 경로에 많은 추가 작업을 추가하게 되면 다른 리소스의 존재를 숨기고 있는지 멈춰 서서 생각해 볼 시간입니다.
비 리소스 경로
리소스 라우팅 외에도 Rails는 임의의 URL을 작업에 라우팅하는 강력한 지원을 제공합니다. 여기서는 리소스 라우팅에 의해 자동으로 생성되는 경로 그룹이 없습니다. 대신 애플리케이션 내에서 각 경로를 별도로 설정합니다.
일반적으로 리소스 라우팅을 사용해야 하지만 더 간단한 라우팅이 더 적절한 많은 경우가 있습니다. 모든 것을 리소스 프레임워크에 맞추려고 노력할 필요는 없습니다.
특히 간단한 라우팅을 사용하면 레거시 URL을 새 Rails 작업에 매핑하기가 매우 쉽습니다.
바운드 매개변수
일반 경로를 설정할 때 들어오는 HTTP 요청의 일부에 매핑되는 일련의 기호를 제공합니다. 예를 들어 다음과 같은 경로를 고려해 보겠습니다:
get 'photos(/:id)', to: 'photos#display'
들어오는 요청 /photos/1
이 이 경로(이전 경로와 일치하지 않은 경우)에 의해 처리되면 PhotosController
의 display
작업이 호출되고 최종 매개변수 "1"
이 params[:id]
로 사용할 수 있게 됩니다. 이 경로는 :id
가 선택적 매개변수(괄호로 표시)이므로 /photos
에 대한 요청도 PhotosController#display
로 라우팅됩니다.
동적 세그먼트
일반 경로에서 원하는 만큼 많은 동적 세그먼트를 설정할 수 있습니다. 모든 세그먼트는 params
의 일부로 작업에 사용할 수 있습니다. 다음과 같은 경로를 설정한 경우:
get 'photos/:id/:user_id', to: 'photos#show'
/photos/1/2
의 들어오는 경로가 PhotosController
의 show
작업으로 디스패치됩니다. params[:id]
는 "1"
이 되고 params[:user_id]
는 "2"
가 됩니다.
팁: 기본적으로 동적 세그먼트는 점을 허용하지 않습니다. 이는 점이 형식화된 경로의 구분 기호로 사용되기 때문입니다. 동적 세그먼트 내에서 점을 사용해야 하는 경우 이를 재정의하는 제약 조건을 추가하면 됩니다. 예: id: /[^\/]+/
는 슬래시 이외의 모든 것을 허용합니다.
정적 세그먼트
세그먼트 앞에 콜론을 붙이지 않으면 정적 세그먼트를 지정할 수 있습니다:
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' }
가 됩니다.
쿼리 문자열
params
에는 쿼리 문자열의 모든 매개변수도 포함됩니다. 예를 들어 다음과 같은 경로가 있는 경우:
get 'photos/:id', to: 'photos#show'
/photos/1?user_id=2
의 들어오는 경로가 Photos
컨트롤러의 show
작업으로 디스패치됩니다. params
는 { controller: 'photos', action: 'show', id: '1', user_id: '2' }
가 됩니다.
기본값 정의하기
:defaults
옵션에 해시를 제공하여 기본값을 경로에 정의할 수 있습니다. 이는 동적 세그먼트로 지정하지 않은 매개변수에도 적용됩니다. 예를 들어:
get 'photos/:id', to: 'photos#show', defaults: { format: 'jpg' }
Rails는 photos/12
를 PhotosController
의 show
작업에 매핑하고 params[:format]
을 "jpg"
로 설정합니다.
defaults
블록을 사용하여 여러 항목에 대한 기본값을 정의할 수도 있네, 계속해서 번역하겠습니다.
기본값 정의하기 (계속)
defaults format: :json do resources :photos end
참고: 쿼리 매개변수를 통해 기본값을 재정의할 수는 없습니다. 이는 보안상의 이유 때문입니다. 재정의할 수 있는 기본값은 URL 경로의 동적 세그먼트뿐입니다.
경로 이름 지정하기
:as
옵션을 사용하여 모든 경로에 이름을 지정할 수 있습니다:
get 'exit', to: 'sessions#destroy', as: :logout
이렇게 하면 애플리케이션에 logout_path
및 logout_url
이라는 명명된 경로 헬퍼가 생성됩니다. logout_path
를 호출하면 /exit
가 반환됩니다.
리소스에 의해 정의된 라우팅 메서드를 재정의하려면 사용자 정의 경로를 리소스 정의 전에 배치할 수 있습니다:
get ':username', to: 'users#show', as: :user resources :users
이렇게 하면 user_path
메서드가 생성되어 /bob
과 같은 경로로 이동할 수 있습니다. 매개변수 이름이 :username
이 아니기를 원하는 경우 경로 정의에서 이를 변경하면 됩니다.
HTTP 동사 제약 조건
일반적으로 get
, post
, put
, patch
, 및 delete
메서드를 사용하여 특정 동사에 경로를 제한해야 합니다. match
메서드와 :via
옵션을 사용하여 여러 동사를 한 번에 일치시킬 수 있습니다:
match 'photos', to: 'photos#show', via: [:get, :post]
:via: :all
을 사용하여 모든 동사에 대한 경로를 일치시킬 수 있습니다:
match 'photos', to: 'photos#show', via: :all
참고: GET
및 POST
요청을 단일 작업에 라우팅하면 보안 문제가 발생할 수 있습니다. 일반적으로 특별한 이유가 없다면 모든 동사를 작업에 라우팅하지 않는 것이 좋습니다.
참고: Rails의 GET
은 CSRF 토큰을 확인하지 않습니다. 데이터베이스에 쓰는 GET
요청은 절대 작성하지 마세요. 자세한 내용은 보안 가이드의 CSRF 대책을 참조하세요.
세그먼트 제약 조건
:constraints
옵션을 사용하여 동적 세그먼트에 대한 형식을 적용할 수 있습니다:
get 'photos/:id', to: 'photos#show', constraints: { id: /[A-Z]\d{5}/ }
이 경로는 /photos/A12345
와 같은 경로와 일치하지만 /photos/893
과는 일치하지 않습니다. 다음과 같이 더 간단하게 표현할 수 있습니다:
get 'photos/:id', to: 'photos#show', id: /[A-Z]\d{5}/
:constraints
는 정규식을 허용하지만 정규식 앵커는 사용할 수 없습니다. 예를 들어 다음과 같은 경로는 작동하지 않습니다:
get '/:id', to: 'articles#show', constraints: { id: /^\d/ }
그러나 모든 경로가 시작과 끝에 고정되어 있기 때문에 앵커를 사용할 필요가 없다는 점에 유의하세요.
예를 들어 다음과 같은 경로를 사용하면 to_param
값이 숫자로 시작하는 articles
와 숫자로 시작하지 않는 users
가 루트 네임스페이스를 공유할 수 있습니다:
get '/:id', to: 'articles#show', constraints: { id: /\d.+/ } get '/:username', to: 'users#show'
요청 기반 제약 조건
Request 객체의 모든 메서드 중 문자열을 반환하는 메서드를 기반으로 경로를 제한할 수도 있습니다.
요청 기반 제약 조건은 세그먼트 제약 조건과 동일한 방식으로 지정합니다:
get 'photos', to: 'photos#index', constraints: { subdomain: 'admin' }
constraints
블록을 사용하여 제약 조건을 지정할 수도 있습니다:
namespace :admin do constraints subdomain: 'admin' do resources :photos end end
참고: 요청 제약 조건은 Request 객체의 동일한 이름 메서드를 호출하고 반환 값을 해시 값과 비교하여 작동합니다. 따라서 제약 조건 값은 해당 Request 객체 메서드 반환 유형과 일치해야 합니다. 예: constraints: { subdomain: 'api' }
는 예상대로 api
하위 도메인과 일치하지만 기호 constraints: { subdomain: :api }
는 그렇지 않습니다. 왜냐하면 request.subdomain
은 문자열 'api'
를 반환하기 때문입니다.
참고: format
제약 조건에는 예외가 있습니다. Request 객체의 메서드이지만 모든 경로의 암시적 선택적 매개변수이기도 합니다. 세그먼트 제약 조건이 우선하며 format
제약 조건은 해시를 통해 적용된 경우에만 그렇게 적용됩니다. 예: get 'foo', constraints: { format: 'json' }
은 형식이 기본적으로 선택적이므로 GET /foo
와 일치합니다. 그러나 lambda
와 같은 것을 사용할 수 있습니다. get 'foo', constraints: lambda { |req| req.format == :json }
이면 경로가 명시적 JSON 요청에만 일치합니다.
고급 제약 조건
더 복잡한 제약 조건이 필요한 경우 matches?
에 응답하는 객체를 제공하여 Rails가 사용하도록 할 수 있습니다. 예를 들어 제한된 목록의 모든 사용자를 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
람다로 제약 조건을 지정할 수도 있습니다:
Rails.application.routes.draw do get '*path', to: 'restricted_list#index', constraints: lambda { |request| RestrictedList.retrieve_ips.include?(request.remote_ip) } end
matches?
메서드와 람다 모두 request
객체를 인수로 받습니다.
블록 형식의 제약 조건
제약 조건을 블록 형식으로 지정할 수 있습니다. 이는 동일한 규칙을 여러 경로에 적용해야 할 때 유용합니다. 예를 들어:
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
경로 글로빙 및 와일드카드 세그먼트
경로 글로빙은 특정 매개변수가 경로의 나머지 부분과 일치해야 한다는 것을 지정하는 방법입니다. 예를 들어:
get 'photos/*other', to: 'photos#unknown'
이 경로는 photos/12
또는 /photos/long/path/to/12
와 일치하며, params[:other]
를 "12"
또는 "long/path/to/12"
로 설정합니다. 별표로 시작하는 세그먼트를 “와일드카드 세그먼트"라고 합니다.
와일드카드 세그먼트는 경로 어디에나 나타날 수 있습니다. 예를 들어:
get 'books/*section/:title', to: 'books#show'
이 경로는 books/some/section/last-words-a-memoir
와 일치하며, params[:section]
은 'some/section'
, params[:title]
은 'last-words-a-memoir'
가 됩니다.
기술적으로 경로에 두 개 이상의 와일드카드 세그먼트가 있을 수 있습니다. 매처는 직관적인 방식으로 세그먼트를 매개변수에 할당합니다. 예를 들어:
get '*a/foo/*b', to: 'test#index'
이 경로는 zoo/woo/foo/bar/baz
와 일치하며, params[:a]
는 'zoo/woo'
, params[:b]
는 'bar/baz'
가 됩니다.
참고: '/foo/bar.json'
을 요청하면 params[:pages]
가 'foo/bar'
가 되고 요청 형식이 JSON이 됩니다. 3.0.x의 이전 동작을 원하는 경우 다음과 같이 format: false
를 제공할 수 있습니다:
get '*pages', to: 'pages#show', format: false
참고: 형식 세그먼트를 필수로 만들어 생략할 수 없게 하려면 format: true
를 제공하면 됩니다:
get '*pages', to: 'pages#show', format: true
리디렉션
redirect
헬퍼를 사용하여 모든 경로를 다른 경로로 리디렉션할 수 있습니다:
get '/stories', to: redirect('/articles')
동적 세그먼트를 재사용하여 경로를 리디렉션할 수도 있습니다:
get '/stories/:name', to: redirect('/articles/%{name}')
또한 redirect
에 블록을 제공하여 경로 매개변수와 요청 객체를 받을 수 있습니다:
get '/stories/:name', to: redirect { |path_params, req| "/articles/#{path_params[:name].pluralize}" } get '/stories', to: redirect { |path_params, req| "/articles/#{req.subdomain}" }
기본 리디렉션은 301 "영구 이동” 리디렉션임을 유의하세요. 일부 웹 브라우저 또는 프록시 서버가 이 유형의 리디렉션을 캐시하여 이전 페이지에 액세스할 수 없게 만들 수 있습니다. :status
옵션을 사용하여 응답 상태를 변경할 수 있습니다:
get '/stories/:name', to: redirect('/articles/%{name}', status: 302)
이러한 모든 경우에 선행 호스트(http://www.example.com
)를 제공하지 않으면 Rails는 현재 요청의 세부 정보를 사용합니다.
Rack 애플리케이션에 라우팅하기
'articles#index'
와 같은 문자열 대신 [Rack 애네, 계속해서 번역하겠습니다.
Rack 애플리케이션에 라우팅하기 (계속)
플리케이션](railsonrack.html)을 매처의 엔드포인트로 지정할 수 있습니다:
match '/application.js', to: MyRackApp, via: :all
MyRackApp
이 call
에 응답하고 [status, headers, body]
를 반환하는 한 라우터는 Rack 애플리케이션과 작업 간의 차이를 알지 못합니다. 이는 via: :all
을 사용하는 적절한 경우입니다. Rack 애플리케이션이 모든 동사를 적절하게 처리할 수 있기 때문입니다.
참고: 호기심 많은 분들을 위해 말씀드리면 'articles#index'
는 실제로 ArticlesController.action(:index)
로 확장되며, 이는 유효한 Rack 애플리케이션을 반환합니다.
참고: 프로시저/람다는 call
에 응답하는 객체이므로 매우 간단한 경로(예: 상태 확인)를 인라인으로 구현할 수 있습니다. get '/health', to: ->(env) { [204, {}, ['']] }
Rack 애플리케이션을 매처의 엔드포인트로 지정하는 경우 수신 애플리케이션에서 경로가 변경되지 않는다는 것을 기억하세요. 다음과 같은 경로가 있는 경우 Rack 애플리케이션은 /admin
을 예상해야 합니다:
match '/admin', to: AdminApp, via: :all
대신 Rack 애플리케이션이 루트 경로에서 요청을 받도록 하려면 mount
를 사용하세요:
mount AdminApp, at: '/admin'
root
사용하기
root
메서드를 사용하여 Rails가 '/'
로 라우팅해야 하는 것을 지정할 수 있습니다:
root to: 'pages#main' root 'pages#main' # 위의 축약형
root
경로를 파일 맨 위에 배치해야 합니다. 가장 많이 사용되는 경로이므로 먼저 일치해야 합니다.
참고: root
경로는 GET
요청만 main
작업으로 라우팅합니다.
네임스페이스와 범위 내에서도 root
를 사용할 수 있습니다. 예를 들어:
namespace :admin do root to: "admin#index" end root to: "home#index"
유니코드 문자 경로
유니코드 문자 경로를 직접 지정할 수 있습니다. 예를 들어:
get 'こんにちは', to: 'welcome#index'
직접 경로
direct
를 호출하여 사용자 정의 URL 헬퍼를 직접 만들 수 있습니다. 예를 들어:
direct :homepage do "https://rubyonrails.org" end # >> homepage_url # => "https://rubyonrails.org"
블록의 반환 값은 url_for
메서드에 대한 유효한 인수여야 합니다. 따라서 유효한 문자열 URL, 해시, 배열, Active Model 인스턴스 또는 Active Model 클래스를 전달할 수 있습니다.
direct :commentable do |model| [ model, anchor: model.dom_id ] end direct :main do { controller: 'pages', action: 'index', subdomain: 'www' } end
resolve
사용하기
resolve
메서드를 사용하면 모델의 다형성 매핑을 사용자 정의할 수 있습니다. 예를 들어:
resource :basket resolve("Basket") { [:basket] }
<%= form_with model: @basket do |form| %> <!-- basket form --> <% end %>
이렇게 하면 일반적인 /baskets/:id
대신 /basket
과 같은 단일 URL이 생성됩니다.
리소스 경로 사용자 정의하기
resources
에 의해 생성된 기본 경로와 헬퍼가 일반적으로 잘 작동하지만 때로는 이를 사용자 정의해야 할 수 있습니다. Rails를 사용하면 경로의 거의 모든 일반적인 부분을 사용자 정의할 수 있습니다.
사용할 컨트롤러 지정하기
:controller
옵션을 사용하면 리소스에 대해 명시적으로 사용할 컨트롤러를 지정할 수 있습니다. 예를 들어:
resources :photos, controller: 'images'
이렇게 하면 /photos
로 시작하는 들어오는 경로를 인식하지만 Images
컨트롤러로 라우팅합니다:
HTTP 동사 | 경로 | 컨트롤러#작업 | 명명된 경로 헬퍼 |
---|---|---|---|
GET | /photos | images#index | photos_path |
GET | /photos/new | images#new | newphotopath |
POST | /photos | images#create | photos_path |
GET | /photos/:id | images#show | photo_path(:id) |
GET | /photos/:id/edit | images#edit | editphotopath(:id) |
PATCH/PUT | /photos/:id | images#update | photo_path(:id) |
DELETE | /photos/:id | images#destroy | photo_path(:id) |
참고: photos_path
, new_photo_path
등을 사용하여 이 리소스에 대한 경로를 생성합니다.
네임스페이스가 지정된 컨트롤러의 경우 디렉토리 표기법을 사용할 수 있습니다. 예를 들어:
resources :user_permissions, controller: 'admin/user_permissions'
이렇게 하면 Admin::UserPermissions
컨트롤러로 라우팅됩니다.
참고: 디렉토리 표기법만 지원됩니다. Ruby 상수 표기법(예: controller: 'Admin::UserPermissions'
)으로 컨트롤러를 지정하면 라우팅 문제가 발생할 수 있으며 경고가 발생합니다.
제약 조건 지정하기
:constraints
옵션을 사용하여 암시적 id
에 필수 형식을 지정할 수 있습니다. 예를 들어:
resources :photos, constraints: { id: /[A-Z][A-Z][0-9]+/ }
이 선언은 :id
매개변수가 제공된 정규식과 일치해야 한다고 지정합니다. 따라서 이 경우 라우터는 /photos/1
과 더 이상 일치하지 않습니다. 대신 /photos/RR27
이 일치합니다.
여러 경로에 적용할 단일 제약 조건을 지정하려면 블록 형식을 사용할 수 있습니다:
constraints(id: /[A-Z][A-Z][0-9]+/) do resources :photos resources :accounts end
참고: 물론 비 리소스 경로에서 사용할 수 있는 더 고급 제약 조건을 이 컨텍스트에서 사용할 수 있습니다.
팁: 기본적으로 :id
매개변수는 점을 허용하지 않습니다. 이는 점이 형식화된 경로의 구분 기호로 사용되기 때문입니다. 점이 필요한 경우 이를 재정의하는 제약 조건을 추가하세요. 예: id: /[^\/]+/
는 슬래시 이외의 모든 것을 허용합니다.
명명된 경로 헬퍼 재정의하기
:as
옵션을 사용하면 일반적인 명명된 경로 헬퍼 이름을 재정의할 수 있습니다. 예를 들어:
resources :photos, as: 'images'
이렇게 하면 /photos
로 시작하는 들어오는 경로를 인식하고 PhotosController
로 라우팅하지만 :as
옵션의 값을 사용하여 헬퍼를 이름 지정합니다.
HTTP 동사 | 경로 | 컨트롤러#작업 | 명명된 경로 헬퍼 |
---|---|---|---|
GET | /photos | photos#index | images_path |
GET | /photos/new | photos#new | newimagepath |
POST | /photos | photos#create | images_path |
GET | /photos/:id | photos#show | image_path(:id) |
GET | /photos/:id/edit | photos#edit | editimagepath(:id) |
PATCH/PUT | /photos/:id | photos#update | image_path(:id) |
DELETE | /photos/:id | photos#destroy | image_path(:id) |
new
및 edit
세그먼트 재정의하기
:path_names
옵션을 사용하면 자동으로 생성된 new
및 edit
세그먼트를 재정의할 수 있습니다:
resources :photos, path_names: { new: 'make', edit: 'change' }
이렇게 하면 다음과 같은 경로를 인식하도록 라우팅이 변경됩니다:
/photos/make /photos/1/change
참고: 작업 이름은 이 옵션에 의해 변경되지 않습니다. 표시된 두 경로는 여전히 new
및 edit
작업으로 라우팅됩니다.
팁: 모든 경로에 대해 이 옵션을 일괄적으로 변경하려면 범위를 사용할 수 있습니다:
scope path_names: { new: 'make' } do # 나머지 경로 end
명명된 경로 헬퍼 접두사 지정하기
:as
옵션을 사용하여 Rails가 경로에 대해 생성하는 명명된 경로 헬퍼의 접두사를 지정할 수 있습니다. 경로 범위 간 이름 충돌을 방지하려면 이 옵션을 사용하세요. 예를 들어:
scope 'admin' do resources :photos, as: 'admin_photos' end resources :photos
이렇게 하면 /admin/photos
에 대한 경로 헬퍼가 photos_path
, new_photos_path
등 대신 admin_photos_path
, new_admin_photo_path
등이 됩니다. as: 'admin_photos'
를 resources :photos
에 추가하지 않으면 비범위 resources :photos
에 경로 헬퍼가 생성되지 않습니다.
그룹의 경로 헬퍼에 접두사를 지정하려면 scope
에 :as
를 사용하세요:
scope 'admin', as: 'admin' do resources :photos, :accounts end resources :photos, :accounts
마찬가지로 이렇게 하면 /admin
범위 리소스 헬퍼가 admin_photos_path
및 admin_accounts_path
가 되고, 범위 없는 리소스는 photos_path
및 accounts_path
를 사용할 수 있습니다.
참고: namespace
범위는 자동으로 :as
및 :module
, :path
접두사를 추가합니다.
매개변수화된 범위
경로를 명명된 매개변수로 접두사 지정할 수 있습니다:
scope ':account_id', as: 'account', constraints: { account_id: /\d+/ } do resources :articles end
이렇게 하면 /1/articles/9
와 같은 경로를 제공하고 params[:account_id]
에 경로네, 계속해서 번역하겠습니다.
명명된 매개변수로 경로 접두사 지정하기 (계속)
의 account_id
부분을 컨트롤러, 헬퍼 및 뷰에서 사용할 수 있게 됩니다.
또한 account_
로 시작하는 경로 및 URL 헬퍼를 생성하며, 여기에 객체를 예상대로 전달할 수 있습니다:
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" ...>
제약 조건을 사용하여 범위를 ID 유사 문자열로 제한하고 있습니다. 필요에 따라 제약 조건을 변경하거나 완전히 생략할 수 있습니다. :as
옵션도 엄격히 필요하지는 않지만, 이를 사용하지 않으면 url_for([@account, @article])
또는 form_with
과 같은 헬퍼를 평가할 때 오류가 발생합니다.
생성된 경로 제한하기
기본적으로 Rails는 각 RESTful 경로에 대해 7개의 기본 작업(index
, show
, new
, create
, edit
, update
및 destroy
)에 대한 경로를 생성합니다. :only
및 :except
옵션을 사용하여 이 동작을 미세 조정할 수 있습니다. :only
옵션은 Rails에 지정된 경로만 생성하도록 지시합니다:
resources :photos, only: [:index, :show]
이제 /photos
에 대한 GET
요청은 성공하지만 /photos
에 대한 POST
요청(일반적으로 create
작업으로 라우팅됨)은 실패합니다.
:except
옵션은 Rails가 생성하지 않을 경로 또는 경로 목록을 지정합니다:
resources :photos, except: :destroy
이 경우 Rails는 destroy
작업(즉, /photos/:id
에 대한 DELETE
요청)을 제외한 모든 일반적인 경로를 생성합니다.
팁: 애플리케이션에 많은 RESTful 경로가 있는 경우 :only
및 :except
를 사용하여 실제로 필요한 경로만 생성하면 메모리 사용량을 줄이고 라우팅 프로세스를 가속화할 수 있습니다.
번역된 경로
scope
를 사용하여 resources
에 의해 생성된 경로 이름을 변경할 수 있습니다:
scope(path_names: { new: 'neu', edit: 'bearbeiten' }) do resources :categories, path: 'kategorien' end
Rails는 이제 CategoriesController
에 대한 경로를 생성합니다.
HTTP 동사 | 경로 | 컨트롤러#작업 | 명명된 경로 헬퍼 |
---|---|---|---|
GET | /kategorien | categories#index | categories_path |
GET | /kategorien/neu | categories#new | newcategorypath |
POST | /kategorien | categories#create | categories_path |
GET | /kategorien/:id | categories#show | category_path(:id) |
GET | /kategorien/:id/bearbeiten | categories#edit | editcategorypath(:id) |
PATCH/PUT | /kategorien/:id | categories#update | category_path(:id) |
DELETE | /kategorien/:id | categories#destroy | category_path(:id) |
단일 형식 재정의하기
리소스의 단일 형식을 재정의하려면 inflections
를 통해 인플렉터에 추가 규칙을 추가해야 합니다:
ActiveSupport::Inflector.inflections do |inflect| inflect.irregular 'tooth', 'teeth' end
:as
를 중첩 리소스에서 사용하기
:as
옵션은 자동으로 생성된 중첩 경로 헬퍼의 리소스 이름을 재정의합니다. 예를 들어:
resources :magazines do resources :ads, as: 'periodical_ads' end
이렇게 하면 magazine_periodical_ads_url
및 edit_magazine_periodical_ad_path
와 같은 라우팅 헬퍼가 생성됩니다.
명명된 경로 매개변수 재정의하기
:param
옵션은 기본 리소스 식별자 :id
(경로를 생성하는 데 사용되는 동적 세그먼트)를 재정의합니다. 이 세그먼트는 params[<:param>]
에서 컨트롤러에 액세스할 수 있습니다.
resources :videos, param: :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(identifier: params[:identifier])
관련 모델의 ActiveRecord::Base#to_param
을 재정의하여 URL을 구성할 수 있습니다:
class Video < ApplicationRecord def to_param identifier end end
video = Video.find_by(identifier: "Roman-Holiday") edit_video_path(video) # => "/videos/Roman-Holiday/edit"
매우 큰 경로 파일을 여러 작은 파일로 나누기
대규모 애플리케이션에서 수천 개의 경로가 있는 경우 단일 config/routes.rb
파일이 번거롭고 읽기 어려워질 수 있습니다.
Rails는 draw
매크로를 사용하여 거대한 단일 routes.rb
파일을 여러 작은 파일로 나누는 방법을 제공합니다.
관리 영역에 대한 admin.rb
경로, API 관련 리소스에 대한 api.rb
파일 등을 가질 수 있습니다.
# config/routes.rb Rails.application.routes.draw do get 'foo', to: 'foo#bar' draw(:admin) # `config/routes/admin.rb`에 있는 다른 경로 파일을 로드합니다. end
# config/routes/admin.rb namespace :admin do resources :comments end
Rails.application.routes.draw
블록 내에서 draw(:admin)
을 호출하면 인수로 제공된 이름과 동일한 이름의 경로 파일(admin.rb
의 경우)을 로드하려고 시도합니다. 파일은 config/routes
디렉토리 또는 하위 디렉토리(config/routes/admin.rb
또는 config/routes/external/admin.rb
)에 있어야 합니다.
일반 config/routes.rb
파일과 달리 admin.rb
라우팅 파일 내에서 정상적인 라우팅 DSL을 사용할 수 있지만 Rails.application.routes.draw
블록으로 감싸서는 안 됩니다.
정말 필요한 경우가 아니라면 이 기능을 사용하지 마세요
여러 라우팅 파일을 사용하면 발견성과 이해도가 낮아집니다. 대부분의 애플리케이션(수백 개의 경로가 있는 경우에도)에서는 개발자가 단일 라우팅 파일을 가지는 것이 더 쉽습니다. Rails 라우팅 DSL은 이미 namespace
및 scope
를 통해 경로를 체계적으로 구분하는 방법을 제공합니다.
경로 검사 및 테스트
Rails는 경로를 검사하고 테스트하는 기능을 제공합니다.
기존 경로 나열하기
애플리케이션에서 사용 가능한 모든 경로 목록을 보려면 서버가 개발 환경에서 실행 중일 때 http://localhost:3000/rails/info/routes에 액세스하세요. 또한 터미널에서 bin/rails routes
명령을 실행하여 동일한 출력을 얻을 수 있습니다.
두 방법 모두 config/routes.rb
에 나타나는 순서대로 모든 경로를 나열합니다. 각 경로에 대해 다음이 표시됩니다:
- 경로 이름(있는 경우)
- 사용된 HTTP 동사(경로가 모든 동사에 응답하지 않는 경우)
- 일치시킬 URL 패턴
- 경로에 대한 라우팅 매개변수
예를 들어 RESTful 경로에 대한 작은 섹션은 다음과 같습니다:
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
--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
grep 옵션 -g
를 사용하여 경로를 검색할 수 있습니다. 이렇게 하면 URL 헬퍼 메서드 이름, HTTP 동사 또는 URL 경로와 부분적으로 일치하는 모든 경로가 출력됩니다.
$ bin/rails routes -g new_comment $ bin/rails routes -g POST $ bin/rails routes -g admin
특정 컨트롤러에 매핑되는 경로만 보려면 -c
옵션을 사용하세요.
$ bin/rails routes -c users $ bin/rails routes -c admin/users $ bin/rails routes -c Comments $ bin/rails routes -c Articles::CommentsController
팁: 터미널 창을 충분히 넓게 하면 bin/rails routes
출력의 가독성이 크게 향상됩니다.
경로 테스트하기
경로는 애플리케이션의 나머지 부분(컨트롤러, 모델 등)과 마찬가지로 테스트 전략에 포함되어야 합니다. Rails는 경로 테스트를 더 쉽게 만들기 위해 3개의 내장 어설션을 제공합니다:
assert_generates
어설션
assert_generates
는 특정 옵션 집합이 특정 경로를 생성한다고 어설션하며 기본 경로 또는 사용자 정의 경로에서 사용할 수 있습니다. 예를 들어:
assert_generates '/photos/1', { controller: 'photos', action: 'show', id: '1' } assert_generates '/about', controller: 'pages', action: 'about'
assert_recognizes
어설션
assert_recognizes
는 assert_generates
의 반대입니다. 주어진 경로가 인식되고 애플리케이션의 특정 위치로 라우팅된다고 어설네, 계속해서 번역하겠습니다.
경로 테스트하기 (계속)
션합니다. 예를 들어:
assert_recognizes({ controller: 'photos', action: 'show', id: '1' }, '/photos/1')
:method
인수를 제공하여 HTTP 동사를 지정할 수 있습니다:
assert_recognizes({ controller: 'photos', action: 'create' }, { path: 'photos', method: :post })
assert_routing
어설션
assert_routing
어설션은 경로를 양방향으로 확인합니다. 경로가 옵션을 생성하고 옵션이 경로를 생성한다는 것을 테스트합니다. 따라서 assert_generates
와 assert_recognizes
의 기능을 결합합니다:
assert_routing({ path: 'photos', method: :post }, { controller: 'photos', action: 'create' })