Chapter 9 : Rails Routing from the Outside In
이 글은 Rails 5.0 Guide 기준으로 작성됩니다.
https://guides.rubyonrails.org/v5.0/routing.html
- Rails Routing from the Outside In Intro
Rails 라우팅을 사용하면서 다루게 될 대면 기능을 서술합니다.
- The Purpose of the Rails Router
Rails 라우터는 URL을 인식하고, 이를 컨트롤러의 동작으로 발송합니다. 또한 View에서 문자열을 하드 코딩 할 필요없이 path와 URL을 생성 할 수 있습니다.
1. Connecting URLs to Code
만약 외부로부터 아래와 같은 URL에 접속 시(혹은 request 할 경우)
GET /patients/17
아래 요청과 매칭됩니다.
get '/patients/:id', to: 'patients#show'
요청은 patients controller 내 show Action으로 dispatch가 이루어지고, { id: '17' } 라는 parameters가 생성됩니다.
2. Generating Paths and URLs from Code
일부 라우터 규칙에 있어 path 이름을 따로 설정하고 싶을 때가 있습니다.
그럴 경우에는 아래와 같이 as 문법을 입력하면 됩니다.
get '/patients/:id', to: 'patients#show', as: 'patient'
그리고 View 코드에 표현에 있어, 아래와 같이 patient_path(@patient) 를 써주면 됩니다.
아래 코드는 @patient 객체가 가진 정보 중, ID값을 참고하여 이동됩니다. (link_to는 HTML의 a 태그와 같은 역할)
## Controller
@patient = Patient.find(17)
## View
<%= link_to 'Patient Record', patient_path(@patient) %>
- Resource Routing: the Rails Default
Resources 라우팅을 통해 index, show, new, edit, create, update, destroy Action(Restful API)에 대해 별도의 Route 규칙을 선언하는 대신 한 줄의 코드로 Restful API 규칙을 빠르게 선언할 수 있습니다.
1. Resources on the Web
브라우저는 GET, POST, PATCH, PUT 및 DELETE와 같은 특정 HTTP 메소드를 통해 URL을 요청하여 페이지를 요청합니다. 각 방법은 resources에 대한 작업을 수행하기 위한 요청입니다. resources 경로는 여러 관련 요청을 단일 컨트롤러의 작업에 매핑합니다.
예를들어, 아래의 요청에 대해서는
DELETE /photos/17
라우터의 아래 줄에 명시된 한 줄의 코드에 위의 DELETE Method에 대한 정의가 포함되어 있습니다.
resources :photos
Rails는 위 요청을 parameters: {id : '17'} 을 가지고 photos controller의 destroy Action으로 전달합니다.
2. CRUD, Verbs, and Actions
Rails에서 resourceful route는 HTTP 동사와 URL을 컨트롤러 Action에 매핑합니다. 일반적으로 각 작업은 데이터베이스의 특정 CRUD 작업에 매핑됩니다.
다음은 Rails route의 resources 문법이 CRUD작업과 매핑이 되는것을 보여주는 도표입니다.
(기본적으로 resources 맵핑은 Restful API 규칙을 따릅니다.)
HTTP Verb | Path | Controller#Action | 목적 |
GET | /photos | photos#index | photos의 목록을 보여줍니다. |
GET | /photos/new | photos#new | photo 데이터 생성을 위한 form 페이지로 이동됩니다. |
POST | /photos | photos#create | photo 데이터를 생성합니다. |
GET | /photos/:id | photos#show | 특정 photo의 id값 데이터를 보여줍니다. |
GET | /photos/:id/edit | photos#edit | 기존의 photo 데이터를 수정하기 위한 form 페이지로 이동합니다. |
PATCH/PUT | /photos/:id | photos#update | photo 데이터 수정 처리가 이루어집니다. |
DELETE | /photos/:id | photos#destroy | photo 데이터 삭제 처리가 이루어집니다. |
3. Path and URL Helpers
resourceful route를 생성 시, application 내의 많은 controller 및 헬퍼들이 노출됩니다.
- 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) returns /photos/:id (예를 들어, photo_path(10) = /photos/10)
4. Defining Multiple Resources at the Same Time
하나 이상의 resources에 대한 경로를 만들어야 함에 있어, 아래와 같이 resources를 한번만 호출 후 추가하고자 하는 resources에 대해 아래와 같이 작성하면 됩니다.
resources :photos, :books, :videos
이를테면 위 코드는 아래와 동일하게 작업이 이루어집니다.
resources :photos
resources :books
resources :videos
5. Singular Resources
때로는 resource 문법에 있어 ID값이 필요가 없을 수도 있습니다. (예를들어 마이페이지 기능) 그렇다보니 하나의 자원(resource)에 대해선 ID값이 표기되지 않습니다.
만약 아래와 같이 현재 로그인된 유저의 정보를 열람해야 한다면 아래와 같이 라우터에서 정의내릴 수 있습니다.
get 'profile', to: 'users#show'
이를테면, 본래 resources 에서라면 show 기능에는 :id 정보가 있어야 했으나, resource에는 :id 정보 없이 열람이 가능합니다.
위 코드와 같이 String을 전달하면 controller#action 형식이 필요하지만,
아래와 같이 Symbol을 전달하면 아래와 같이 컨트롤러도 지정해줘야 합니다.
get 'profile', to: :show, controller: 'users'
Route 내에서 resource 문법이 정의될 경우
resource :profile
resource 문법은 다음 도표의 6가지 경로와 맵핑이 됩니다.
참고 resources와 차이가 있다면, edit, update, show에는 id값을 받지 않는다는 점, index Action이 없다는 점입니다.
HTTP Verb | Path | Controller#Action | 목적 |
GET | /profile/new | profile#new | profile 데이터 생성을 위한 form 페이지로 이동됩니다. |
POST | /profile | profile#create | profile 데이터를 생성합니다. |
GET | /profile | profile#show | 특정 profile의 id값 데이터를 보여줍니다. |
GET | /profile/edit | profile#edit | 기존의 profile 데이터를 수정하기 위한 form 페이지로 이동합니다. |
PATCH/PUT | /profile | profile#update | profile 데이터 수정 처리가 이루어집니다. |
DELETE | /profile | profile#destroy | profile 데이터 삭제 처리가 이루어집니다. |
singular resourceful route는 아래 Path helper와 같은 이름이 정의됩니다.
- new_geocoder_path = /geocoder/new
- edit_geocoder_path = /geocoder/edit
- geocoder_path = /geocoder
참고 오랜 버그로 인해 form_for helper 에서는 단일 리소스를 자동으로 사용할 수 없습니다. 이 문제를 해결하려면 다음과 같이 URL을 직접 지정해야 합니다.
form_for @geocoder, url: geocoder_path do |f|
6. Controller Namespaces and Routing
1) Namespace
네임 스페이스 아래에서 컨트롤러 그룹을 구성 할 수 있습니다. 가장 일반적으로 Admin::namespace 아래에 여러 관리 컨트롤러를 그룹화 할 수 있습니다 .
namespace :admin do
resources :articles, :comments
end
위 코드를 토대로 컨트롤러는 app/controllers/admin 디렉토리 아래 에 놓고 라우터에서 그룹화 할 수 있습니다.
Admin::ArticlesControllerRails는 articles및 comments컨트롤러에 대해 아래와 같은 URI 패턴을 생성합니다.
2) Module
Controller은 namespace 방식으로 가리키되, Path는 기존의 resource(s) 방식으로 가리키고 싶을 경우, module 문법을 활용하면 됩니다.
scope module: 'admin' do
resources :articles, :comments
end
## 위 표현과 동일한 문법
resources :articles, module: 'admin'
HTTP Verb | Path | Controller#Action | Named Helper |
GET | /articles | admin/articles#index | articles_path |
GET | /articles/new | admin/articles#new | new_article_path |
POST | /articles | admin/articles#create | articles_path |
GET | /articles/:id | admin/articles#show | article_path(:id) |
GET | /articles/:id/edit | admin/articles#edit | edit_article_path(:id) |
PATCH/PUT | /articles/:id | admin/articles#update | article_path(:id) |
DELETE | /articles/:id | admin/articles#destroy | article_path(:id) |
3) Scope
Controller은 기존의 resource(s) 방식으로 가리키되, Path는 namespace 방식으로 변경하고 싶을 경우, scope 문법을 활용하면 됩니다.
scope '/admin' do
resources :articles, :comments
end
## 위 표현과 동일한 문법
resources :articles, path: '/admin/articles'
HTTP Verb | Path | Controller#Action | Named 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) |
7. Nested Resources
만약 resource(s) 안에 자식 resource(s)가 있는 경우, 라우터에서 block 형태로 다음과 같이 정의할 수 있습니다.
class Magazine < ApplicationRecord
has_many :ads
end
class Ad < ApplicationRecord
belongs_to :magazine
end
## config/routes.rb
resources :magazines do
resources :ads
end
HTTP Verb | Path | Controller#Action | Named Helper |
megazine resources들... (생략), 아래는 megazine resources에 종속된 ads의 양식들입니다. | |||
GET | /magazines/:magazine_id/ads | ads#index | magazine ID에 종속된 모든 ads를 보여줍니다. |
GET | /magazines/:magazine_id/ads/new | ads#new | magazine ID에 종속된 ad 생성을 위한 form 페이지로 이동합니다. |
POST | /magazines/:magazine_id/ads | ads#create | magazine ID에 종속된 ad 데이터를 생성합니다. |
GET | /magazines/:magazine_id/ads/:id | ads#show | magazine ID에 종속된 ad의 id값 데이터를 보여줍니다. |
GET | /magazines/:magazine_id/ads/:id/edit | ads#edit | 기존의 magazine ID에 종속된 ad 데이터를 수정하기 위한 form 페이지로 이동합니다. |
PATCH/PUT | /magazines/:magazine_id/ads/:id | ads#update | 기존의 magazine ID에 종속된 ad 데이터 수정 처리가 이루어집니다. |
DELETE | /magazines/:magazine_id/ads/:id | ads#destroy | 기존의 magazine ID에 종속된 ad 데이터 삭제 처리가 이루어집니다. |
1) Limits to Nesting
원하는 경우 resource(s) 중첩 내에 또 중첩을 할 수 있습니다. 예를 들면 아래와 같습니다.
## config/routes.rb
resources :publishers do
resources :magazines do
resources :photos
end
end
#=> /publishers/1/magazines/2/photos/3
2) Shallow Nesting
상위 계층의 Controller 내 Action들에 대해 대해서는 가만히 냅두나, 하위 resource(s)에서는 아래와 같이 특정 Action에 대해서만 URI를 열어두는 방법이 있습니다.
필요하지 않은 상위 수집 URL 규칙을 버려내는 작업으로서, :index , :create, :new Action만을 생성합니다.
resources :articles do
resources :comments, only: [:index, :new, :create]
end
resources :comments, only: [:show, :edit, :update, :destroy]
하지만 위 방법을 좀 더 간결히 표현할 수 있는 방법이 있습니다.
## 방법 1 : 블록 내 resources 중, 일부에 대해 shallow 옵션 적용
resources :articles do
resources :comments, shallow: true
end
## 방법 2 : 블록 내 resources 전체에 shallow 옵션 적용
resources :articles, shallow: true do
resources :comments
end
scope에도 다음과 같이 :shallow_path 옵션 통해 루트 ID에 종속된 자식 resources가 없는 URI를 생성할 수 있습니다.
scope shallow_path: "sekret" do
resources :articles do
resources :comments, shallow: true
end
end
:shallow_prefix 옵션을 통해서도 아래와 같이 적용할 수 있습니다.
Path Helper에 변화를 줍니다.
scope shallow_prefix: "sekret" do
resources :articles do
resources :comments, shallow: true
end
end
8. Routing concerns
만약 아래와 같은 라우터 정의 예제가 있다고 합시다. :
## config/routes.rb
resources :messages do
resources :comments
end
resources :articles do
resources :comments
resources :images, only: :index
end
위 라우터에서 보면 comments에 대해 공통적으로 중첩이 되어있는게 확인할 수 있습니다.
이러한 중복 문제를 해결할 수 있는 문법 중 하나가 concerns 로서, 다른 리소스 및 경로 내에서 문법을 재사용할 수 있게 해줍니다.
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]
scope, namespace에서도 다음과 같이 concern 문법을 활용할 수 있습니다.
namespace :articles do
concerns :commentable
end
9. Creating Paths and URLs From Objects
Rails는 라우팅 헬퍼를 사용하는 것 외에도 다양한 파라미터로부터 경로와 URL을 생성 할 수 있습니다. 예를 들어 다음과 같은 경로 집합이 있다고 가정합니다.
resources :magazines do
resources :ads
end
# [ad#show] magazine_ad_path
# /magazines/:magazine_id/ads/:id
magazine_ad_path를 사용하는 경우 숫자 ID 대신 Magazine 및 Ad 인스턴스를 전달할 수 있습니다.
<%= link_to 'Ad details', magazine_ad_path(@magazine, @ad) %>
url_for 문법을 통해 다음과 같이 자동으로 URI 경로위치가 지정되게 할 수 있습니다.
참고 url_for 내 대괄호 안에는 단순히 id값 만을 가진게 아닌, 객체 정보를 가진 변수 자체를 넣어줘야 합니다.
<%= link_to 'Ad details', url_for([@magazine, @ad]) %>
이 외에도 아래와 같이 다양하게 link_to 문법을 쓸 수 있습니다.
<%= link_to 'Ad details', [@magazine, @ad] %>
# /magazines/:magazine_id/ads/:id
<%= link_to 'Magazine details', @magazine %>
# /magazines/:id
<%= link_to 'Edit Ad', [:edit, @magazine, @ad] %>
# /magazines/:magazine_id/ads/:id/edit
10. Adding More RESTful Actions
1) member
RESTful API 외의 URI 생성에 있어, 복수(resources) URI를 생성하고 싶을 경우, 아래와 같이 collection 문법을 통해 URI 규칙을 생성해낼 수 있습니다.
resources :photos do
member do
get 'preview'
end
end
위의 라우트 코드를 아래와 같이 표현을 해낼 수도 있습니다.
resources :photos do
get 'preview', on: :member
end
HTTP Verb | Path | Controller#Action |
GET | /photos/:id/preview | photos#preview |
그 외 photos 관련 resources (index, show, new, edit, create, update, destroy) |
2) collection
RESTful API 외의 URI 생성에 있어, 단일(resource) URI를 생성하고 싶을 경우, 아래와 같이 collection 문법을 통해 URI 규칙을 생성해낼 수 있습니다.
resources :photos do
collection do
get 'search'
end
end
위의 라우트 코드를 아래와 같이 표현을 해낼 수도 있습니다.
resources :photos do
get 'search', on: :collection
end
HTTP Verb | Path | Controller#Action |
GET | /photos/search | photos#search |
그 외 photos 관련 resources (index, show, new, edit, create, update, destroy) |
3) Adding Routes for Additional New Actions
Controller의 새로운 Action 추가 및 URI에 대한 경로를 재정의 하고싶을 경우, 다음과 같이도 정의할 수 있습니다.
resources :comments do
get 'preview', on: :new
end
이를 통해 Rails는 [GET] /comments/new/preview 와 같은 경로를 인식하고 CommentsController의 preview Action으로 라우팅 할 수 있습니다. 또한 preview_new_comment_url 및 preview_new_comment_path 2가지의 path helper를 생성합니다.
- Non-Resourceful Routes
Rails는 resource(s) 라우팅 외에도 임의의 URL을 Controller의 Action으로 라우팅하는 기능을 지원합니다.
resource(s)가 많은 라우팅에 의해 자동으로 생성 된 경로 그룹을 얻지 못하나, 대신 application 내에서 각 경로를 별도로 설정해낼 수 있습니다.
일반적으로 resource(s) 문법을 통해 라우팅 정의를 많이 한다곤 하나, 때론 간단한 라우팅이 더 적합한 곳도 있으며, 특히 간단한 라우팅을 통해 레거시 URL에 대해 새로운 Action으로 쉽게 매핑 할 수 있습니다.
1. Bound Parameters
get ':controller(/:action(/:id))'
일반 경로를 설정할 때 Rails가 들어오는 HTTP 요청의 일부에 자동으로 라우터 규칙에 매핑하는 일련의 symbole을 제공합니다.
이러한 symbol에 있어 두 가지 특징이 있습니다.
1) :controller는 응용 프로그램의 컨트롤러 이름에 매핑
2) :action은 해당 컨트롤러 내의 작업 이름에 매핑
예를들어 /photos/show/1 로 홈페이지에 접속 시, Parameters: {"action"=>"show", "controller"=>"photos", "id"=>"1"} 로 맵핑됩니다.
2. Dynamic Segments
:controller 또는 :action 이외의 것은 매개 변수의 일부로 작업에 사용할 수 있습니다.
get ':controller/:action/:id/:user_id'
예를들어 /photos/show/1/2 로 홈페이지 접속 시, Parameters: {"action"=>"show", "controller"=>"photos", "id"=>"1", "user_id"=>"2"} 로 맵핑됩니다.
참고 namespace 및 module에는 :controller symbol 표현을 못합니다.
만약 namespace에서 :controller symbol을 표현하고 싶다면 아래와 같이 regex(정규식) 설정을 해줘야 합니다.
get ':controller(/:action(/:id))', controller: /admin\/[^\/]+/
3. Static Segments
get ':controller/:action/:id/with_user/:user_id'
콜론(:)을 조각 앞에 추가하지 않고 라우트를 작성할 때 정적 세그먼트를 지정할 수 있습니다.
4. The Query String
get ':controller/:action/:id'
위 URI 문법을 기반으로, params에는 query string으로 부터 Parameters도 가지고 있습니다.
예를들어 /photos/show/1?user_id=2 홈페이지 접속 시, Parameters: { controller: 'photos', action: 'show', id: '1', user_id: '2' }
5. Defining Defaults
get 'photos/:id', to: 'photos#show'
Route 내에서 :controller 및 :action symbol을 명시 적으로 사용할 필요는 없습니다.
위와같이 to 옵션을 통해 기본값으로 설정할 수 있습니다.
또한 아래 문법과 같이, 해시 문법을 통해 :defaults 옵션을 설정해서 경로에 다른 기본값을 정의 할 수도 있습니다. 이는 동적 세그먼트로 지정하지 않은 parameters에도 적용됩니다.
get 'photos/:id', to: 'photos#show', defaults: { format: 'jpg' }
위 라우터 예시를 기반으로 홈페이지에 접근 시, params 중 params[:format] = "jpg" 로 parameter가 전송됩니다.
6. Naming Routes
:as 옵션을 사용하여 path helper 이름을 지정할 수 있습니다.
get 'exit', to: 'sessions#destroy', as: :logout
7. HTTP Verb Constraints
match 'photos', to: 'photos#show', via: [:get, :post]
일반적으로 get, post, put, patch, delete 메소드를 사용하여 특정 동사(verb; URI 행위 이름)에 대한 경로를 제한해야합니다.
match 메소드를 :via 옵션과 함께 사용하여 여러 동사를 한 번에 일치시킬 수 있습니다.
또한 아래와 같이 모든 Method에 대해 허용시킬 수도 있습니다.
match 'photos', to: 'photos#show', via: :all
참고 1 GET 및 POST 요청을 single Action으로 라우팅시 보안에 영향을 미칩니다. 일반적으로 적절한 이유가없는 한 모든 동사를 동작으로 라우팅하지 않아야합니다.
참고 2 GET Method는 CSRF 취약점을 검사하지 않습니다. 만약 Database 접근(쓰기/삭제)을 행위하는 URI일 경우 GET 메소드를 써선 안됩니다.
8. Segment Constraints
get 'photos/:id', to: 'photos#show', constraints: { id: /[A-Z]\d{5}/ }
:constraints 옵션을 사용하여 동적 세그먼트에 형식을 적용 할 수 있습니다.
또한 정규식 표현을 통해 문자열 매칭을 시킬 수 있습니다.
예를들어 위 :constraints 에 명시된 정규식을 토대로 /photos/A12345 에 대해선 웹사이트 접근을 할 수 있으나, /photos/893 경로는 정규식 규칙과 비일치하므로 접근이 안됩니다.
9. Request-Based Constraints
get 'photos', to: 'photos#index', constraints: { subdomain: 'admin' }
String을 반환하는 Request 객체의 모든 Method를 기반으로 경로를 제한할 수 있습니다. Request 기반 제한 조건을 정합니다.
위 코드를 예를들어, http://admin.domain.com/photos 를 통해선 접근이 허용되나, http://domain.com/photos 와 같은 경로로 접근은 제한됩니다.
또한, 위의 표현을 아래와 같이 정의내릴 수 있습니다.
namespace :admin do
constraints subdomain: 'admin' do
resources :photos
end
end
참고 1 subdomain에 있어 string을 통한 표현('admin')에 대해선 허용이 되나, symbold 표현(:admin)은 허용이 안됩니다.
참고 2 format 설정에 있어 라우터에 get 'foo', constraints: { format: 'json' } 정의 후, request에 있어 format: json 을 주지 않아도 접속이 잘 됩니다. 이는 constraints: { format: 'json' } 는 단순히 선택사항(option)이기 때문입니다.
하지만 get 'foo', constraints: lambda { |req| req.format == :json } 을 정의할 경우, 이 때는 request에 있어 json 이어야지만 결과값이 return 됩니다.
10. Advanced Constraints
class BlacklistConstraint
def initialize
@ips = Blacklist.retrieve_ips
end
def matches?(request)
@ips.include?(request.remote_ip)
end
end
Rails.application.routes.draw do
get '*path', to: 'blacklist#index',
constraints: BlacklistConstraint.new
end
만약 타 class를 통해 constraints 검증을 해야할 경우, 위와같이 코드를 짜낼 수 있습니다.
위 코드는 Blacklist Model 내 retrive_ips 컬럼을 기반으로 접속된 유저(request)의 IP와 blacklists 테이블 내에 등록되어있는 블랙리스트 IP에 대해 검사하는 코드입니다.
Lambda를 통해서도 아래와 같이 constraints 옵션을 줄 수 있습니다.
## config/routes.rb
Rails.application.routes.draw do
get '*path', to: 'blacklist#index',
constraints: lambda { |request| Blacklist.retrieve_ips.include?(request.remote_ip) }
end
11. Route Globbing and Wildcard Segments
get 'photos/*other', to: 'photos#unknown'
글로빙(globbing) Route는 특정 parameter가 나머지 모든 부분과 일치하도록 지정하는 방법입니다.
여기서 other 앞에 붙은 *은 "wildcard segments" 라고 합니다.
1) /photos/12 로 접속 시, Parameters: {"other"=>"12"}
2) /photos/long/path/to/12 로 접속 시, Parameters: {"other"=>"long/path/to/12"}
참고 '/foo/bar.json'을 요청하면 params[:pages]는 요청 형식이 JSON 인 'foo/bar'와 같습니다.
12. Redirection
get '/stories', to: redirect('/articles')
get '/stories/:name', to: redirect('/articles/%{name}')
라우터의 Redirect helper을 통해 다른 경로로 리디렉션 할 수 있습니다.
참고 redirect helper은 기본적으로 301(Moved Permanently) 응답을 합니다.
만약 status code를 바꾸고 싶을 경우, 아래와 같이 :status 옵션을 줄 수 있습니다.
get '/stories/:name', to: redirect('/articles/%{name}', status: 302)
13. Routing to Rack Applications
match '/application.js', to: MyRackApp, via: :all
ArticlesController의 index Action에 해당하는 'articles#index'와 같은 문자열 표현 대신, 모든 Rack Application을 macher의 endpoint로 지정할 수 있습니다.
MyRackApp이 응답하고 [status, headers, body]을 return하는 한, router는 Rack Application과 Action의 사이의 차이점을 모릅니다. Rack Application이 적절하다고 간주되는 모든 동사를 처리 할 수 있도록하려면 via: :all 을 적절하게 사용합니다.
참고 'articles#index'가 실제로 ArticlesControlle의 action(:index)로 확장되어 유효한 Rack Application을 반환한다는 것입니다.
Rack Application이 루트 경로에서 요청을 받게 하려면. mount를 사용하면 됩니다.
mount AdminApp, at: '/admin'
14. Using root
## config/routes.rb
Rails.application.routes.draw do
root to: 'pages#main'
root 'pages#main' # 위 root to: 의 축약 표현
end
메인 페이지('/') 접근에 있어, 보여질 페이지에 대해 설정할 수 있습니다.
root 설정은 config/routes.rb 블록 내의 최상단에 표현되어야 합니다.
참고 root path 설정은 GET Method에 대해서만 설정 가능
다음과 같이 개별 URI 공간을 생성하는 namespace 내에서도 root 설정이 가능합니다.
Rails.application.routes.draw do
namespace :admin do
root to: "admin#index"
end
root to: "home#index"
end
15. Unicode character routes
get 'こんにちは', to: 'welcome#index'
라우터 경로설정에 있어, 단순히 unicode 문자에 대해서도 설정할 수 있습니다.
- Customizing Resourceful Routes
resources :articles 에 의해 생성되는 URI와 Path helper은 일반적으로 잘 작동하지만, 사용자 임의대로 설정할 수도 있습니다.
Rails를 사용하면 리소스가 많은 헬퍼의 거의 모든 부분을 사용자 정의 할 수 있습니다.
1. Specifying a Controller to Use
resources :photos, controller: 'images'
:controller 옵션을 사용하면 리소스에 사용할 컨트롤러를 정할 수 있습니다.
resources와 :controller 옵션을 사용한 Router 규칙은 아래와 같습니다.
HTTP Verb | Path | Controller#Action | Named 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) |
다음과 같은 표기로도 작성할 수 있습니다.
resources :user_permissions, controller: 'admin/user_permissions'
참고 디렉토리 표기법만 지원됩니다. Ruby 상수 표기법으로 컨트롤러를 지정하면 (예 - controller: 'Admin::UserPermissions') 라우팅 문제 및 경고가 발생할 수 있습니다.
2. Specifying Constraints
resources :photos, constraints: { id: /[A-Z][A-Z][0-9]+/ }
:constraints 옵션을 통해 params[:id] 에 정규식 형식을 지정할 수 있습니다.
아래와 같이 block 형식으로도 정의내릴 수 있습니다.
constraints(id: /[A-Z][A-Z][0-9]+/) do
resources :photos
resources :accounts
end
3. Overriding the Named Helpers
resources :photos, as: 'images'
:as 옵션을 통해 Path Helper 이름을 재정의 할 수 있습니다.
HTTP Verb | Path | Controller#Action | Named 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. Overriding the new and edit Segments
resources :photos, path_names: { new: 'make', edit: 'change' }
:path_names 옵션을 통해 Path 이름이 override 됩니다.
참고 1 실제 Controller 내 Action 이름은 변경되지 않습니다.
참고 2 모든 경로에 대해이 옵션을 균일하게 변경하려는 경우 scope 문법을 활용할 수 있습니다. (7번 째 : Translated Paths 참고)
scope path_names: { new: 'make' } do
# rest of your routes
end
5. Prefixing the Named Route Helpers
scope 'admin' do
resources :photos, as: 'admin_photos'
end
resources :photos
:as 옵션을 사용하여 기존의 Path Helper를 as 이름에 맞추어 접두어로 사용할 수 있습니다. 경로 간의 이름 충돌을 방지하려면이 옵션을 사용하세요. (사용 예시는 위와 같음.)
아래와 같이 scope 블록 전체에도 적용해낼 수 있습니다.
scope 'admin', as: 'admin' do
resources :photos, :accounts
end
resources :photos, :accounts
prefix router에 대해선 아래와 같이도 작성할 수 있습니다.
scope ':username' do
resources :articles
end
참고 만약 /kcm/articles 로 접속 시, parameters: {"controller"=>"articles", "action"=>"index", "username"=>"kcm"}
6. Restricting the Routes Created
## [GET] photos, [GET] photos/:id 만 생성
resources :photos, only: [:index, :show]
## 전체 RESTful API에서 [DELETE] photos/:id 만 제거
resources :photos, except: :destroy
기본적으로 Rails는 애플리케이션의 모든 RESTful 경로에 대해 7 가지 기본 작업(index, show, new, create, edit, update, destroy; resources 기준)에 대한 경로를 만듭니다.
:only 및 :except 옵션을 사용하여 라우터 경로를 설정합니다.
1) :only Resftul API에서 지정된 Action에 대해서만 생성합니다.
2) :except Resftul API에서 지정된 Action에 대해 제거합니다.
참고 Application에 많은 RESTful 경로가 있는 경우, :only, :except 옵션을 통해 실제 필요한 URI만 생성 시, 메모리 사용을 줄이고 라우팅 프로세스 속도를 높일 수 있습니다.
7. Translated Paths
scope(path_names: { new: 'neu', edit: 'bearbeiten' }) do
resources :categories, path: 'kategorien'
end
scope 문법을 통해 resources에서 생성 된 Path 이름을 변경할 수 있습니다.
HTTP Verb | Path | Controller#Action | Named 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) |
8. Overriding the Singular Form
ActiveSupport::Inflector.inflections do |inflect|
inflect.irregular 'tooth', 'teeth'
end
singular form of resource(단일 형태의 resource)을 정의하려면 Inflector에 규칙을 추가해야합니다.
라우터에서 Path Helper 네이밍 표현에 있어, URI의 역할에 따라 단수/복수 구분을 하여 네이밍을 하곤 합니다.
이는 ActiveSupport::Inflector.inflections 에서 이름에 대한 교정을 자동으로 해주기 때문입니다.
이 기능을 이용해서 개발자가 임의의 단수-복수 네이밍을 설정해줘야 할 경우 아래과 같이 해낼 수 있습니다.
ActiveSupport::Inflector.inflections do |inflect|
# inflect.irregular '(singular; 단수)', '(plural; 복수)'
inflect.irregular 'ping', 'pong'
end
Dash (Rails API) ActiveSupport::Inflector
class의 singleton instance는 ActiveSupport::Inflector#inflections에 의해 생성되며, 추가 inflection 규칙을 지정하는 데 사용할 수 있습니다. locale(Application 언어설정)을 전달하면 다른 언어에 대한 규칙을 지정할 수 있습니다. 기본 locale은 :en (영어)로서, 영어 규칙만 제공됩니다.
9. Using :as in Nested Resources
resources :magazines do
resources :ads, as: 'periodical_ads'
end
:as 옵션은 resources를 통해 정의된 Path Helper 이름을 재정의 합니다.
위 예시를 보면 Path Helper 이름이 ads 에서 periodical_ads 로 재정의 되어있는걸 볼 수 있습니다.
10. Overriding Named Route Parameters
resources :videos, param: :identifier
:param 옵션은 기본 resource 식별자인 :id (라우트를 생성하는 데 사용되는 동적 세그먼트의 이름)를 재정의합니다.
params[<:param>]을 사용하여 컨트롤러에서 해당 세그먼트에 액세스 할 수 있습니다.
기존에 URI에서 ID를 받는 인자가 params[:id] 이었지만, :params 옵션으로 인해 params[:identifier] 로 바뀌어져 있음.
ActiveRecord::Base#to_param 에서 아래와 같이 override를 해낼 수 있습니다.
class Video < ApplicationRecord
def to_param
identifier
end
end
video = Video.find_by(identifier: "Roman-Holiday")
edit_videos_path(video) # => "/videos/Roman-Holiday"
- Inspecting and Testing Routes
Rails에서는 경로 검사 및 테스트를 위한 기능을 제공합니다.
1. Listing Existing Routes
1) Route의 전체 URI 목록을 보려면 서버가 켜진 상태에서 http://localhost:3000/rails/info/routes 를 방문하면 됩니다.
2) 혹은 터미널에서 rails routes 명령을 실행하여 동일한 결과를 볼 수 있습니다.
홈페이지 접속 혹은 명령어 방법 모두 config/routes.rb 에 작성된 순서대로 모든 라우터 경로가 보여집니다.
grep 옵션을 사용하여 경로를 검색 할 수 있습니다 : [옵션] -g
URL의 Path Helper 이름, HTTP 동사, URL 경로와 부분적으로 일치하는 경로를 출력합니다.
만약 특정 Controller를 가리키는 라우터를 탐색하고 싶을 경우, -c 옵션을 활용하면 됩니다.
2. Testing Routes
Rails는 route를 간단하게 테스트 하기 위해 3가지 built-in assertion을 제공합니다.
- assert_generates
- assert_recognizes
- assert_routing
1) The assert_generates Assertion
assert_generates 은 특정 옵션 설정이 경로(path)를 생성하고 기본 routes 또는 사용자 정의 routes와 함께 사용될 수 있습니다.
assert_generates '/photos/1', { controller: 'photos', action: 'show', id: '1' }
assert_generates '/about', controller: 'pages', action: 'about'
2) The assert_recognizes Assertion
assert_recognizes는 assert_generates의 반대적인 특징을 가집니다.
주어진 경로를 인식하고 Application의 특정 지점으로 경로를 지정합니다.
assert_recognizes({ controller: 'photos', action: 'show', id: '1' }, '/photos/1')
HTTP 동사를 지정하기 위해 Method을 설정할 수 있습니다.
assert_recognizes({ controller: 'photos', action: 'create' }, { path: 'photos', method: :post })
3) The assert_routing Assertion
assert_routing assertion은 route를 두 가지 방법으로 경로를 확인합니다. :
Path가 Option을 생성하는지, Option이 Path를 생성하는지 테스트
또한, The assert_routing Assertion은 위에 언급됐던 assert_generates와 assert_recognizes 두 기능의 특징을 가지고 있습니다.
assert_routing({ path: 'photos', method: :post }, { controller: 'photos', action: 'create' })
- 자료 참고