Ruby on Rails
маршрутизация
Поиск…
Вступление
замечания
«Маршрутизация» в целом - это то, как URL-адреса «обрабатываются» вашим приложением. В случае Rails обычно это контроллер, и какое действие этого контроллера будет обрабатывать определенный входящий URL. В приложениях Rails маршруты обычно помещаются в файл config/routes.rb
.
Маршрутизация ресурсов (основная)
Маршруты определяются в config/routes.rb
. Они часто определяются как группа связанных маршрутов, используя resources
или методы resource
.
resources :users
создают следующие семь маршрутов, все сопоставление с действиями UsersController
:
get '/users', to: 'users#index'
post '/users', to: 'users#create'
get '/users/new', to: 'users#new'
get '/users/:id/edit', to: 'users#edit'
get '/users/:id', to: 'users#show'
patch/put '/users/:id', to: 'users#update'
delete '/users/:id', to: 'users#destroy'
Названия действий отображаются после #
в to
параметра выше. Методы с теми же именами должны быть определены в app/controllers/users_controller.rb
следующим образом:
class UsersController < ApplicationController
def index
end
def create
end
# continue with all the other methods…
end
Вы можете ограничить действия, которые генерируются only
или except
:
resources :users, only: [:show]
resources :users, except: [:show, :index]
Вы можете просмотреть все маршруты своего приложения в любое время, запустив:
$ rake routes
$ rake routes
# OR
$ 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
user GET /users/:id(.:format) users#show
PATCH /users/:id(.:format) users#update
PUT /users/:id(.:format) users#update
DELETE /users/:id(.:format) users#destroy
Чтобы увидеть только маршруты, которые отображаются на конкретный контроллер:
$ rake routes -c static_pages
static_pages_home GET /static_pages/home(.:format) static_pages#home
static_pages_help GET /static_pages/help(.:format) static_pages#help
$ rake routes -c static_pages
static_pages_home GET /static_pages/home(.:format) static_pages#home
static_pages_help GET /static_pages/help(.:format) static_pages#help
# OR
$ rails routes -c static_pages
static_pages_home GET /static_pages/home(.:format) static_pages#home
static_pages_help GET /static_pages/help(.:format) static_pages#help
Вы можете выполнять поиск по маршрутам с помощью опции -g
. Это показывает любой маршрут, который частично соответствует имени вспомогательного метода, URL-адресу или HTTP-глаголу:
$ rake routes -g new_user # Matches helper method
$ rake routes -g POST # Matches HTTP Verb POST
$ rake routes -g new_user # Matches helper method
$ rake routes -g POST # Matches HTTP Verb POST
# OR
$ rails routes -g new_user # Matches helper method
$ rails routes -g POST # Matches HTTP Verb POST
Кроме того, при запуске сервера rails
в режиме разработки вы можете получить доступ к веб-странице, которая отображает все ваши маршруты с фильтром поиска, соответствующим приоритету сверху вниз, в <hostname>/rails/info/routes
. Это будет выглядеть так:
помощник | HTTP-глагол | Дорожка | Контроллер # Действие |
---|---|---|---|
Путь / URL | [Матч по пути] | ||
users_path | ПОЛУЧИТЬ | /users(.:format) | пользователи индекс # |
СООБЩЕНИЕ | /users(.:format) | пользователей # создать | |
new_user_path | ПОЛУЧИТЬ | /users/new(.:format) | пользователи # новых |
edit_user_path | ПОЛУЧИТЬ | /users/:id/edit(.:format) | пользователи # редактировать |
user_path | ПОЛУЧИТЬ | /users/:id(.:format) | Пользователи # показать |
PATCH | /users/:id(.:format) | пользователи # обновление | |
ПОЛОЖИЛ | /users/:id(.:format) | пользователи # обновление | |
УДАЛЯТЬ | /users/:id(.:format) | пользователей # уничтожить |
Маршруты могут быть объявлены доступными только для членов (а не коллекций) с использованием resource
метода вместо resources
в routes.rb
. С resource
маршрут index
создается не по умолчанию, а только при явном запросе такого типа:
resource :orders, only: [:index, :create, :show]
Ограничения
Вы можете фильтровать маршруты, используя ограничения.
Существует несколько способов использования ограничений, в том числе:
Например, запрошенное ограничение на ограничение позволяет только конкретному IP-адресу разрешить доступ к маршруту:
constraints(ip: /127\.0\.0\.1$/) do
get 'route', to: "controller#action"
end
См. Другие аналогичные примеры ActionDispatch :: Routing :: Mapper :: Scoping .
Если вы хотите сделать что-то более сложное, вы можете использовать более сложные ограничения и создать класс для переноса логики:
# lib/api_version_constraint.rb
class ApiVersionConstraint
def initialize(version:, default:)
@version = version
@default = default
end
def version_header
"application/vnd.my-app.v#{@version}"
end
def matches?(request)
@default || request.headers["Accept"].include?(version_header)
end
end
# config/routes.rb
require "api_version_constraint"
Rails.application.routes.draw do
namespace :v1, constraints: ApiVersionConstraint.new(version: 1, default: true) do
resources :users # Will route to app/controllers/v1/users_controller.rb
end
namespace :v2, constraints: ApiVersionConstraint.new(version: 2) do
resources :users # Will route to app/controllers/v2/users_controller.rb
end
end
Одна форма, несколько кнопок отправки
Вы также можете использовать значение тегов отправки формы как ограничение для перехода к другому действию. Если у вас есть форма с несколькими кнопками отправки (например, «предварительный просмотр» и «отправка»), вы можете зафиксировать это ограничение непосредственно на своих routes.rb
вместо того, чтобы писать javascript для изменения URL-адреса формы. Например, с камнем commit_param_routing вы можете воспользоваться rails submit_tag
Первый параметр Rails submit_tag
позволяет изменить значение параметра фиксации формы
# app/views/orders/mass_order.html.erb
<%= form_for(@orders, url: mass_create_order_path do |f| %>
<!-- Big form here -->
<%= submit_tag "Preview" %>
<%= submit_tag "Submit" %>
# => <input name="commit" type="submit" value="Preview" />
# => <input name="commit" type="submit" value="Submit" />
...
<% end %>
# config/routes.rb
resources :orders do
# Both routes below describe the same POST URL, but route to different actions
post 'mass_order', on: :collection, as: 'mass_order',
constraints: CommitParamRouting.new('Submit'), action: 'mass_create' # when the user presses "submit"
post 'mass_order', on: :collection,
constraints: CommitParamRouting.new('Preview'), action: 'mass_create_preview' # when the user presses "preview"
# Note the `as:` is defined only once, since the path helper is mass_create_order_path for the form url
# CommitParamRouting is just a class like ApiVersionContraint
end
Маршрутные маршруты
Rails предоставляет несколько способов организации ваших маршрутов.
Объем по URL-адресу :
scope 'admin' do
get 'dashboard', to: 'administration#dashboard'
resources 'employees'
end
Это генерирует следующие маршруты
get '/admin/dashboard', to: 'administration#dashboard'
post '/admin/employees', to: 'employees#create'
get '/admin/employees/new', to: 'employees#new'
get '/admin/employees/:id/edit', to: 'employees#edit'
get '/admin/employees/:id', to: 'employees#show'
patch/put '/admin/employees/:id', to: 'employees#update'
delete '/admin/employees/:id', to: 'employees#destroy'
На стороне сервера может иметь смысл хранить некоторые представления в другой подпапке, чтобы отделять просмотры администраторов от пользовательских представлений.
Объем по модулю
scope module: :admin do
get 'dashboard', to: 'administration#dashboard'
end
module
ищет файлы контроллера под подпапкой данного имени
get '/dashboard', to: 'admin/administration#dashboard'
Вы можете переименовать префикс помощника пути, добавив параметр as
scope 'admin', as: :administration do
get 'dashboard'
end
# => administration_dashboard_path
Rails обеспечивает удобный способ сделать все вышеописанное, используя метод namespace
. Следующие объявления эквивалентны
namespace :admin do
end
scope 'admin', module: :admin, as: :admin
Область применения контроллера
scope controller: :management do
get 'dashboard'
get 'performance'
end
Это генерирует эти маршруты
get '/dashboard', to: 'management#dashboard'
get '/performance', to: 'management#performance'
Неглубокое гнездование
Маршруты ресурсов допускают :shallow
параметр, который помогает, по возможности, сократить URL-адреса. Ресурсы не должны быть вложены более чем на один уровень. Один из способов избежать этого - создать мелкие маршруты. Цель состоит в том, чтобы оставить сегменты сегментов родительской коллекции, где они не нужны. Конечным результатом является то, что только генерируемые вложенные маршруты предназначены для :index
:create
и :new
действий. Остальные сохраняются в собственном неглубоком контексте URL. Существует два варианта возможностей для настраиваемых неглубоких маршрутов:
: shallow_path: Префикс пути элемента с заданным параметром
scope shallow_path: "sekret" do resources :articles do resources :comments, shallow: true end end
: shallow_prefix : добавьте указанные параметры в именованные помощники
scope shallow_prefix: "sekret" do resources :articles do resources :comments, shallow: true end end
Мы также можем проиллюстрировать shallow
маршруты:
resources :auctions, shallow: true do
resources :bids do
resources :comments
end
end
альтернативно кодируется следующим образом (если вы счастливы с блоком):
resources :auctions do
shallow do
resources :bids do
resources :comments
end
end
end
Результирующие маршруты:
Префикс | глагол | Шаблон URI |
---|---|---|
bid_comments | ПОЛУЧИТЬ | /bids/:bid_id/comments(.:format) |
СООБЩЕНИЕ | /bids/:bid_id/comments(.:format) | |
new_bid_comment | ПОЛУЧИТЬ | /bids/:bid_id/comments/new(.:format) |
edit_comment | ПОЛУЧИТЬ | /comments/:id/edit(.:format) |
комментарий | ПОЛУЧИТЬ | /comments/:id(.:format) |
PATCH | /comments/:id(.:format) | |
ПОЛОЖИЛ | /comments/:id(.:format) | |
УДАЛЯТЬ | /comments/:id(.:format) | |
auction_bids | ПОЛУЧИТЬ | /auctions/:auction_id/bids(.:format) |
СООБЩЕНИЕ | /auctions/:auction_id/bids(.:format) | |
new_auction_bid | ПОЛУЧИТЬ | /auctions/:auction_id/bids/new(.:format) |
edit_bid | ПОЛУЧИТЬ | /bids/:id/edit(.:format) |
предложение | ПОЛУЧИТЬ | /bids/:id(.:format) |
PATCH | /bids/:id(.:format) | |
ПОЛОЖИЛ | /bids/:id(.:format) | |
УДАЛЯТЬ | /bids/:id(.:format) | |
аукционы | ПОЛУЧИТЬ | /auctions(.:format) |
СООБЩЕНИЕ | /auctions(.:format) | |
new_auction | ПОЛУЧИТЬ | /auctions/new(.:format) |
edit_auction | ПОЛУЧИТЬ | /auctions/:id/edit(.:format) |
торг | ПОЛУЧИТЬ | /auctions/:id(.:format) |
PATCH | /auctions/:id(.:format) | |
ПОЛОЖИЛ | /auctions/:id(.:format) | |
УДАЛЯТЬ | /auctions/:id(.:format) |
Если вы тщательно проанализируете маршруты, вы заметите, что вложенные части URL-адреса включены только тогда, когда они необходимы для определения того, какие данные будут отображаться.
Обеспокоенность
Чтобы избежать повторения на вложенных маршрутах, проблемы обеспечивают отличный способ совместного использования общих ресурсов, которые можно повторно использовать. Чтобы создать беспокойство использовать метод concern
внутри routes.rb
файла. Метод ожидает символ и блок:
concern :commentable do
resources :comments
end
Не создавая никаких маршрутов, этот код позволяет использовать атрибут :concerns
ресурса. Самый простой пример:
resource :page, concerns: :commentable
Эквивалентный вложенный ресурс будет выглядеть так:
resource :page do
resource :comments
end
Это создало бы, например, следующие маршруты:
/pages/#{page_id}/comments
/pages/#{page_id}/comments/#{comment_id}
Чтобы проблемы были значимыми, необходимо наличие нескольких ресурсов, которые используют эту проблему. Дополнительные ресурсы могут использовать любой из следующих синтаксисов для вызова проблемы:
resource :post, concerns: %i(commentable)
resource :blog do
concerns :commentable
end
Перенаправление
Вы можете перенаправлять маршруты Rails следующим образом:
get '/stories', to: redirect('/posts')
match "/abc" => redirect("http://example.com/abc")
Вы также можете перенаправить все неизвестные маршруты на заданный путь:
match '*path' => redirect('/'), via: :get
# or
get '*path' => redirect('/')
match '*path' => redirect('/')
Маршруты участников и коллекций
Определение блока-члена внутри ресурса создает маршрут, который может действовать на отдельном члене этого маршрута на основе ресурсов:
resources :posts do
member do
get 'preview'
end
end
Это генерирует следующий маршрут участника:
get '/posts/:id/preview', to: 'posts#preview'
# preview_post_path
Маршруты сбора позволяют создавать маршруты, которые могут действовать в коллекции объектов ресурсов:
resources :posts do
collection do
get 'search'
end
end
Это создает следующий маршрут сбора:
get '/posts/search', to: 'posts#search'
# search_posts_path
Альтернативный синтаксис:
resources :posts do
get 'preview', on: :member
get 'search', on: :collection
end
URL-параметры с периодом
Если вы хотите поддерживать параметр url более сложным, чем номер id, вы можете столкнуться с проблемой с парсером, если значение содержит период. Все, что следует за периодом, будет считаться форматом (т.е. json, xml).
Вы можете обойти это ограничение, используя ограничение для расширения принятого ввода.
Например, если вы хотите ссылаться на запись пользователя по адресу электронной почты в URL-адресе:
resources :users, constraints: { id: /.*/ }
Корневой маршрут
Вы можете добавить маршрут домашней страницы в свое приложение с помощью root
метода.
# config/routes.rb
Rails.application.routes.draw do
root "application#index"
# equivalent to:
# get "/", "application#index"
end
# app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
def index
render "homepage"
end
end
А в терминале rake routes
( rake routes
rails routes
в Rails 5) будут производить:
root GET / application#index
Поскольку главная страница, как правило, является самым важным маршрутом, а маршруты приоритетны в том порядке, в котором они появляются, root
маршрут обычно должен быть первым в вашем файле маршрутов.
Дополнительные действия RESTful
resources :photos do member do get 'preview' end collection do get 'dashboard' end end
Это создает следующие маршруты в дополнение к маршрутам RESTful по умолчанию 7 :
get '/photos/:id/preview', to: 'photos#preview'
get '/photos/dashboards', to: 'photos#dashboard'
Если вы хотите сделать это для отдельных строк, вы можете использовать:
resources :photos do get 'preview', on: :member get 'dashboard', on: :collection end
Вы также можете добавить действие к /new
пути:
resources :photos do get 'preview', on: :new end
Что создаст:
get '/photos/new/preview', to: 'photos#preview'
Будьте внимательны при добавлении действий на маршруты RESTful, возможно, вам не хватает другого ресурса!
Область доступных областей
Если ваше приложение доступно на разных языках, вы обычно показываете текущую локаль в URL-адресе.
scope '/(:locale)', locale: /#{I18n.available_locales.join('|')}/ do
root 'example#root'
# other routes
end
Ваш корень будет доступен через локали, определенные в I18n.available_locales
.
Смонтировать другое приложение
mount используется для монтирования другого приложения (в основном, стойки) или рельсовых двигателей, которые будут использоваться в текущем приложении
синтаксис:
mount SomeRackApp, at: "some_route"
Теперь вы можете получить доступ к установленному выше приложению с помощью вспомогательного маршрута some_rack_app_path
или some_rack_app_url
.
Но если вы хотите переименовать это имя помощника, вы можете сделать это как:
mount SomeRackApp, at: "some_route", as: :myapp
Это создаст myapp_path
и myapp_url
помощники, которые можно использовать для перехода к этому подключенному приложению.
Перенаправления и подстановочные маршруты
Если вы хотите предоставить URL-адрес из удобства для своего пользователя, но сопоставьте его напрямую с другим, который вы уже используете. Используйте перенаправление:
# config/routes.rb
TestApp::Application.routes.draw do
get 'courses/:course_name' => redirect('/courses/%{course_name}/lessons'), :as => "course"
end
Ну, это стало интересно быстро. Основной принцип здесь заключается в том, чтобы просто использовать метод #redirect
для отправки одного маршрута на другой маршрут. Если ваш маршрут довольно прост, это действительно простой метод. Но если вы хотите также отправить исходные параметры, вам нужно сделать немного гимнастики, взяв параметр внутри %{here}
. Обратите внимание на одиночные кавычки вокруг всего.
В приведенном выше примере мы также переименовали маршрут для удобства, используя псевдоним с параметром: as. Это позволяет использовать это имя в методах, таких как помощники #_path. Опять же, проверьте свои $ rake routes
с вопросами.
Разделить маршруты на несколько файлов
Если ваш файл маршрутов чрезвычайно большой, вы можете поместить свои маршруты в несколько файлов и включить каждый из файлов с помощью метода require_relative
Ruby:
config/routes.rb
: YourAppName::Application.routes.draw do
require_relative 'routes/admin_routes'
require_relative 'routes/sidekiq_routes'
require_relative 'routes/api_routes'
require_relative 'routes/your_app_routes'
end
config/routes/api_routes.rb
: YourAppName::Application.routes.draw do
namespace :api do
# ...
end
end
Вложенные маршруты
Если вы хотите добавить вложенные маршруты, вы можете написать следующий код в routes.rb
.
resources :admins do
resources :employees
end
Это создаст следующие маршруты:
admin_employees GET /admins/:admin_id/employees(.:format) employees#index
POST /admins/:admin_id/employees(.:format) employees#create
new_admin_employee GET /admins/:admin_id/employees/new(.:format) employees#new
edit_admin_employee GET /admins/:admin_id/employees/:id/edit(.:format) employees#edit
admin_employee GET /admins/:admin_id/employees/:id(.:format) employees#show
PATCH /admins/:admin_id/employees/:id(.:format) employees#update
PUT /admins/:admin_id/employees/:id(.:format) employees#update
DELETE /admins/:admin_id/employees/:id(.:format) employees#destroy
admins GET /admins(.:format) admins#index
POST /admins(.:format) admins#create
new_admin GET /admins/new(.:format) admins#new
edit_admin GET /admins/:id/edit(.:format) admins#edit
admin GET /admins/:id(.:format) admins#show
PATCH /admins/:id(.:format) admins#update
PUT /admins/:id(.:format) admins#update
DELETE /admins/:id(.:format) admins#destroy