1 El Propósito del Router de Rails
El router de Rails reconoce URLs y las envía a la acción de un controlador, o a una aplicación Rack. También puede generar rutas y URLs, evitando la necesidad de codificar cadenas en tus vistas.
1.1 Conectando URLs al Código
Cuando tu aplicación Rails recibe una solicitud entrante para:
GET /patients/17
le pide al router que la empareje con una acción del controlador. Si la primera ruta coincidente es:
get '/patients/:id', to: 'patients#show'
la solicitud se envía a la acción show
del controlador patients
con { id: '17' }
en params
.
NOTA: Rails usa snake_case para los nombres de los controladores aquí, si tienes un controlador de varias palabras como MonsterTrucksController
, querrás usar monster_trucks#show
por ejemplo.
1.2 Generando Rutas y URLs desde el Código
También puedes generar rutas y URLs. Si la ruta anterior se modifica para ser:
get '/patients/:id', to: 'patients#show', as: 'patient'
y tu aplicación contiene este código en el controlador:
@patient = Patient.find(params[:id])
y esto en la vista correspondiente:
<%= link_to 'Patient Record', patient_path(@patient) %>
entonces el router generará la ruta /patients/17
. Esto reduce la fragilidad de tu vista y hace que tu código sea más fácil de entender. Ten en cuenta que el id no necesita ser especificado en el helper de la ruta.
1.3 Configurando el Router de Rails
Las rutas para tu aplicación o motor viven en el archivo config/routes.rb
y típicamente se ven así:
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
Dado que este es un archivo fuente Ruby regular, puedes usar todas sus características para ayudarte a definir tus rutas, pero ten cuidado con los nombres de las variables ya que pueden chocar con los métodos DSL del router.
NOTA: El bloque Rails.application.routes.draw do ... end
que envuelve tus definiciones de ruta es necesario para establecer el alcance del DSL del router y no debe ser eliminado.
2 Rutas de Recursos: el Predeterminado de Rails
Las rutas de recursos te permiten declarar rápidamente todas las rutas comunes para un controlador de recursos dado. Una sola llamada a resources
puede declarar todas las rutas necesarias para tus acciones index
, show
, new
, edit
, create
, update
y destroy
.
2.1 Recursos en la Web
Los navegadores solicitan páginas de Rails haciendo una solicitud para una URL usando un método HTTP específico, como GET
, POST
, PATCH
, PUT
y DELETE
. Cada método es una solicitud para realizar una operación en el recurso. Una ruta de recurso mapea una serie de solicitudes relacionadas a acciones en un solo controlador.
Cuando tu aplicación Rails recibe una solicitud entrante para:
DELETE /photos/17
le pide al router que la mapee a una acción del controlador. Si la primera ruta coincidente es:
resources :photos
Rails enviaría esa solicitud a la acción destroy
en el controlador photos
con { id: '17' }
en params
.
2.2 CRUD, Verbos y Acciones
En Rails, una ruta de recurso proporciona un mapeo entre verbos HTTP y URLs a acciones del controlador. Por convención, cada acción también se mapea a una operación CRUD específica en una base de datos. Una sola entrada en el archivo de rutas, como:
resources :photos
crea siete rutas diferentes en tu aplicación, todas mapeando al controlador Photos
:
Verbo HTTP | Ruta | Controlador#Acción | Usado para |
---|---|---|---|
GET | /photos | photos#index | mostrar una lista de todas las fotos |
GET | /photos/new | photos#new | devolver un formulario HTML para crear una nueva foto |
POST | /photos | photos#create | crear una nueva foto |
GET | /photos/:id | photos#show | mostrar una foto específica |
GET | /photos/:id/edit | photos#edit | devolver un formulario HTML para editar una foto |
PATCH/PUT | /photos/:id | photos#update | actualizar una foto específica |
DELETE | /photos/:id | photos#destroy | eliminar una foto específica |
NOTA: Debido a que el router usa el verbo HTTP y la URL para emparejar solicitudes entrantes, cuatro URLs se mapean a siete acciones diferentes.
NOTA: Las rutas de Rails se emparejan en el orden en que se especifican, por lo que si tienes un resources :photos
encima de un get 'photos/poll'
, la ruta de la acción show
para la línea resources
se emparejará antes que la línea get
. Para solucionar esto, mueve la línea get
encima de la línea resources
para que se empareje primero.
2.3 Helpers de Ruta y URL
Crear una ruta de recurso también expondrá una serie de helpers a los controladores en tu aplicación. En el caso de resources :photos
:
photos_path
devuelve/photos
new_photo_path
devuelve/photos/new
edit_photo_path(:id)
devuelve/photos/:id/edit
(por ejemplo,edit_photo_path(10)
devuelve/photos/10/edit
)photo_path(:id)
devuelve/photos/:id
(por ejemplo,photo_path(10)
devuelve/photos/10
)
Cada uno de estos helpers tiene un helper _url
correspondiente (como photos_url
) que devuelve la misma ruta con el prefijo del host, puerto y prefijo de ruta actuales.
CONSEJO: Para encontrar los nombres de los helpers de ruta para tus rutas, consulta Listado de rutas existentes a continuación.
2.4 Definiendo Múltiples Recursos al Mismo Tiempo
Si necesitas crear rutas para más de un recurso, puedes ahorrar un poco de escritura definiéndolos todos con una sola llamada a resources
:
resources :photos, :books, :videos
Esto funciona exactamente igual que:
resources :photos
resources :books
resources :videos
2.5 Recursos Singulares
A veces, tienes un recurso que los clientes siempre buscan sin hacer referencia a un ID. Por ejemplo, te gustaría que /profile
siempre muestre el perfil del usuario actualmente conectado. En este caso, puedes usar un recurso singular para mapear /profile
(en lugar de /profile/:id
) a la acción show
:
get 'profile', to: 'users#show'
Pasar una String
a to:
esperará un formato controller#action
. Al usar un Symbol
, la opción to:
debe ser reemplazada con action:
. Al usar una String
sin un #
, la opción to:
debe ser reemplazada con controller:
:
get 'profile', action: :show, controller: 'users'
Esta ruta de recurso:
resource :geocoder
resolve('Geocoder') { [:geocoder] }
crea seis rutas diferentes en tu aplicación, todas mapeando al controlador Geocoders
:
Verbo HTTP | Ruta | Controlador#Acción | Usado para |
---|---|---|---|
GET | /geocoder/new | geocoders#new | devolver un formulario HTML para crear el geocoder |
POST | /geocoder | geocoders#create | crear el nuevo geocoder |
GET | /geocoder | geocoders#show | mostrar el único recurso geocoder |
GET | /geocoder/edit | geocoders#edit | devolver un formulario HTML para editar el geocoder |
PATCH/PUT | /geocoder | geocoders#update | actualizar el único recurso geocoder |
DELETE | /geocoder | geocoders#destroy | eliminar el recurso geocoder |
NOTA: Debido a que podrías querer usar el mismo controlador para una ruta singular (/account
) y una ruta plural (/accounts/45
), los recursos singulares se mapean a controladores plurales. Así que, por ejemplo, resource :photo
y resources :photos
crean tanto rutas singulares como plurales que se mapean al mismo controlador (PhotosController
).
Una ruta de recurso singular genera estos helpers:
new_geocoder_path
devuelve/geocoder/new
edit_geocoder_path
devuelve/geocoder/edit
geocoder_path
devuelve/geocoder
NOTA: La llamada a resolve
es necesaria para convertir instancias del Geocoder
a rutas a través de identificación de registro.
Al igual que con los recursos plurales, los mismos helpers que terminan en _url
también incluirán el host, puerto y prefijo de ruta.
2.6 Nombres de Controladores y Rutas
Es posible que desees organizar grupos de controladores bajo un namespace. Más comúnmente, podrías agrupar varios controladores administrativos bajo un namespace Admin::
, y colocar estos controladores bajo el directorio app/controllers/admin
. Puedes enrutar a tal grupo usando un bloque namespace
:
namespace :admin do
resources :articles, :comments
end
Esto creará una serie de rutas para cada uno de los controladores articles
y comments
. Para Admin::ArticlesController
, Rails creará:
Verbo HTTP | Ruta | Controlador#Acción | Helper de Ruta Nombrada |
---|---|---|---|
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) |
Si en cambio quieres enrutar /articles
(sin el prefijo /admin
) a Admin::ArticlesController
, puedes especificar el módulo con un bloque scope
:
scope module: 'admin' do
resources :articles, :comments
end
Esto también se puede hacer para una sola ruta:
resources :articles, module: 'admin'
Si en cambio quieres enrutar /admin/articles
a ArticlesController
(sin el prefijo de módulo Admin::
), puedes especificar la ruta con un bloque scope
:
scope '/admin' do
resources :articles, :comments
end
Esto también se puede hacer para una sola ruta:
resources :articles, path: '/admin/articles'
En ambos casos, los helpers de ruta nombrados permanecen iguales como si no hubieras usado scope
. En el último caso, las siguientes rutas se mapean a ArticlesController
:
Verbo HTTP | Ruta | Controlador#Acción | Helper de Ruta Nombrada |
---|---|---|---|
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) |
CONSEJO: Si necesitas usar un namespace de controlador diferente dentro de un bloque namespace
, puedes especificar una ruta de controlador absoluta, por ejemplo: get '/foo', to: '/foo#index'
.
2.7 Recursos Anidados
Es común tener recursos que son lógicamente hijos de otros recursos. Por ejemplo, supongamos que tu aplicación incluye estos modelos:
class Magazine < ApplicationRecord
has_many :ads
end
class Ad < ApplicationRecord
belongs_to :magazine
end
Las rutas anidadas te permiten capturar esta relación en tu enrutamiento. En este caso, podrías incluir esta declaración de ruta:
resources :magazines do
resources :ads
end
Además de las rutas para revistas, esta declaración también enviará anuncios a un AdsController
. Las URLs de anuncios requieren una revista:
Verbo HTTP | Ruta | Controlador#Acción | Usado para |
---|---|---|---|
GET | /magazines/:magazine_id/ads | ads#index | mostrar una lista de todos los anuncios para una revista específica |
GET | /magazines/:magazine_id/ads/new | ads#new | devolver un formulario HTML para crear un nuevo anuncio para una revista específica |
POST | /magazines/:magazine_id/ads | ads#create | crear un nuevo anuncio para una revista específica |
GET | /magazines/:magazine_id/ads/:id | ads#show | mostrar un anuncio específico para una revista específica |
GET | /magazines/:magazine_id/ads/:id/edit | ads#edit | devolver un formulario HTML para editar un anuncio para una revista específica |
PATCH/PUT | /magazines/:magazine_id/ads/:id | ads#update | actualizar un anuncio específico para una revista específica |
DELETE | /magazines/:magazine_id/ads/:id | ads#destroy | eliminar un anuncio específico para una revista específica |
Esto también creará helpers de ruta como magazine_ads_url
y edit_magazine_ad_path
. Estos helpers toman una instancia de Magazine como el primer parámetro (magazine_ads_url(@magazine)
).
2.7.1 Límites de Anidación
Puedes anidar recursos dentro de otros recursos anidados si lo deseas. Por ejemplo:
resources :publishers do
resources :magazines do
resources :photos
end
end
Los recursos anidados profundamente rápidamente se vuelven engorrosos. En este caso, por ejemplo, la aplicación reconocería rutas como:
/publishers/1/magazines/2/photos/3
El helper de ruta correspondiente sería publisher_magazine_photo_url
, requiriendo que especifiques objetos en los tres niveles. De hecho, esta situación es lo suficientemente confusa como para que un artículo popular de Jamis Buck proponga una regla empírica para un buen diseño en Rails:
CONSEJO: Los recursos nunca deben anidarse más de 1 nivel de profundidad.
2.7.2 Anidación Superficial
Una forma de evitar la anidación profunda (como se recomienda arriba) es generar las acciones de colección bajo el ámbito del padre, para obtener una idea de la jerarquía, pero no anidar las acciones de miembro. En otras palabras, construir rutas solo con la cantidad mínima de información para identificar de manera única el recurso, así:
resources :articles do
resources :comments, only: [:index, :new, :create]
end
resources :comments, only: [:show, :edit, :update, :destroy]
Esta idea encuentra un equilibrio entre rutas descriptivas y anidación profunda. Existe una sintaxis abreviada para lograr precisamente eso, a través de la opción :shallow
:
resources :articles do
resources :comments, shallow: true
end
Esto generará exactamente las mismas rutas que el primer ejemplo. También puedes especificar la opción :shallow
en el recurso padre, en cuyo caso todos los recursos anidados serán superficiales:
resources :articles, shallow: true do
resources :comments
resources :quotes
resources :drafts
end
El recurso articles aquí tendrá las siguientes rutas generadas para él:
Verbo HTTP | Ruta | Controlador#Acción | Helper de Ruta Nombrada |
---|---|---|---|
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/:article_id/drafts(.:format) | drafts#index | article_drafts_path |
POST | /articles/:article_id/drafts(.:format) | drafts#create | article_drafts_path |
GET | /articles/:article_id/drafts/new(.:format) | drafts#new | new_article_draft_path |
GET | /drafts/:id/edit(.:format) | drafts#edit | edit_draft_path |
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 | 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 |
El método shallow
del DSL crea un ámbito dentro del cual cada anidación es superficial. Esto genera las mismas rutas que el ejemplo anterior:
shallow do
resources :articles do
resources :comments
resources :quotes
resources :drafts
end
end
Existen dos opciones para scope
para personalizar las rutas superficiales. :shallow_path
prefija las rutas de miembro con el parámetro especificado:
scope shallow_path: "sekret" do
resources :articles do
resources :comments, shallow: true
end
end
El recurso comments aquí tendrá las siguientes rutas generadas para él:
Verbo HTTP | Ruta | Controlador#Acción | Helper de Ruta Nombrada |
---|---|---|---|
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 |
La opción :shallow_prefix
agrega el parámetro especificado a los helpers de ruta nombrados:
scope shallow_prefix: "sekret" do
resources :articles do
resources :comments, shallow: true
end
end
El recurso comments aquí tendrá las siguientes rutas generadas para él:
Verbo HTTP | Ruta | Controlador#Acción | Helper de Ruta Nombrada |
---|---|---|---|
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 Preocupaciones de Enrutamiento
Las preocupaciones de enrutamiento te permiten declarar rutas comunes que pueden ser reutilizadas dentro de otros recursos y rutas. Para definir una preocupación, usa un bloque concern
:
concern :commentable do
resources :comments
end
concern :image_attachable do
resources :images, only: :index
end
Estas preocupaciones pueden ser usadas en recursos para evitar la duplicación de código y compartir comportamiento a través de rutas:
resources :messages, concerns: :commentable
resources :articles, concerns: [:commentable, :image_attachable]
Lo anterior es equivalente a:
resources :messages do
resources :comments
end
resources :articles do
resources :comments
resources :images, only: :index
end
También puedes usarlas en cualquier lugar llamando a concerns
. Por ejemplo, en un bloque scope
o namespace
:
namespace :articles do
concerns :commentable
end
2.9 Creando Rutas y URLs desde Objetos
Además de usar los helpers de enrutamiento, Rails también puede crear rutas y URLs desde un array de parámetros. Por ejemplo, supongamos que tienes este conjunto de rutas:
resources :magazines do
resources :ads
end
Al usar magazine_ad_path
, puedes pasar instancias de Magazine
y Ad
en lugar de los IDs numéricos:
<%= link_to 'Ad details', magazine_ad_path(@magazine, @ad) %>
También puedes usar url_for
con un conjunto de objetos, y Rails determinará automáticamente qué ruta deseas:
<%= link_to 'Ad details', url_for([@magazine, @ad]) %>
En este caso, Rails verá que @magazine
es una Magazine
y @ad
es un Ad
y, por lo tanto, usará el helper magazine_ad_path
. En helpers como link_to
, puedes especificar solo el objeto en lugar de la llamada completa a url_for
:
<%= link_to 'Ad details', [@magazine, @ad] %>
Si quisieras enlazar solo a una revista:
<%= link_to 'Magazine details', @magazine %>
Para otras acciones, solo necesitas insertar el nombre de la acción como el primer elemento del array:
<%= link_to 'Edit Ad', [:edit, @magazine, @ad] %>
Esto te permite tratar instancias de tus modelos como URLs, y es una ventaja clave de usar el estilo de recurso.
2.10 Agregando Más Acciones RESTful
No estás limitado a las siete rutas que el enrutamiento RESTful crea por defecto. Si lo deseas, puedes agregar rutas adicionales que se apliquen a la colección o a miembros individuales de la colección.
2.10.1 Agregando Rutas de Miembro
Para agregar una ruta de miembro, solo agrega un bloque member
dentro del bloque de recursos:
resources :photos do
member do
get 'preview'
end
end
Esto reconocerá /photos/1/preview
con GET, y enrutará a la acción preview
del PhotosController
, con el valor de ID del recurso pasado en params[:id]
. También creará los helpers preview_photo_url
y preview_photo_path
.
Dentro del bloque de rutas de miembro, cada nombre de ruta especifica el verbo HTTP que será reconocido. Puedes usar get
, patch
, put
, post
, o delete
aquí. Si no tienes múltiples rutas de member
, también puedes pasar :on
a una ruta, eliminando el bloque:
resources :photos do
get 'preview', on: :member
end
Puedes omitir la opción :on
, esto creará la misma ruta de miembro, excepto que el valor de ID del recurso estará disponible en params[:photo_id]
en lugar de params[:id]
. Los helpers de ruta también se renombrarán de preview_photo_url
y preview_photo_path
a photo_preview_url
y photo_preview_path
.
2.10.2 Agregando Rutas de Colección
Para agregar una ruta a la colección, usa un bloque collection
:
resources :photos do
collection do
get 'search'
end
end
Esto permitirá a Rails reconocer rutas como /photos/search
con GET, y enrutará a la acción search
del PhotosController
. También creará los helpers de ruta search_photos_url
y search_photos_path
.
Al igual que con las rutas de miembro, puedes pasar :on
a una ruta:
resources :photos do
get 'search', on: :collection
end
NOTA: Si estás definiendo rutas de recursos adicionales con un símbolo como el primer argumento posicional, ten en cuenta que no es equivalente a usar una cadena. Los símbolos infieren acciones del controlador mientras que las cadenas infieren rutas.
2.10.3 Agregando Rutas para Acciones Nuevas Adicionales
Para agregar una acción nueva alternativa usando el atajo :on
:
resources :comments do
get 'preview', on: :new
end
Esto permitirá a Rails reconocer rutas como /comments/new/preview
con GET, y enrutará a la acción preview
del CommentsController
. También creará los helpers de ruta preview_new_comment_url
y preview_new_comment_path
.
CONSEJO: Si te encuentras agregando muchas acciones adicionales a una ruta de recurso, es momento de detenerte y preguntarte si estás disfrazando la presencia de otro recurso.
3 Rutas No-Resursivas
Además del enrutamiento de recursos, Rails tiene un soporte poderoso para enrutar URLs arbitrarias a acciones. Aquí, no obtienes grupos de rutas generadas automáticamente por el enrutamiento de recursos. En cambio, configuras cada ruta por separado dentro de tu aplicación.
Si bien generalmente deberías usar el enrutamiento de recursos, todavía hay muchos lugares donde el enrutamiento más simple es más apropiado. No hay necesidad de intentar encajar hasta el último pedazo de tu aplicación en un marco de recursos si no es una buena opción.
En particular, el enrutamiento simple hace que sea muy fácil mapear URLs heredadas a nuevas acciones de Rails.
3.1 Parámetros Vinculados
Cuando configuras una ruta regular, proporcionas una serie de símbolos que Rails mapea a partes de una solicitud HTTP entrante. Por ejemplo, considera esta ruta:
get 'photos(/:id)', to: 'photos#display'
Si una solicitud entrante de /photos/1
es procesada por esta ruta (porque no ha coincidido con ninguna ruta anterior en el archivo), el resultado será invocar la acción display
del PhotosController
, y hacer que el parámetro final "1"
esté disponible como params[:id]
. Esta ruta también enrutará la solicitud entrante de /photos
al PhotosController#display
, ya que :id
es un parámetro opcional, denotado por paréntesis.
3.2 Segmentos Dinámicos
Puedes configurar tantos segmentos dinámicos dentro de una ruta regular como desees. Cualquier segmento estará disponible para la acción como parte de params
. Si configuras esta ruta:
get 'photos/:id/:user_id', to: 'photos#show'
Una ruta entrante de /photos/1/2
será enviada a la acción show
del PhotosController
. params[:id]
será "1"
, y params[:user_id]
será "2"
.
CONSEJO: Por defecto, los segmentos dinámicos no aceptan puntos - esto se debe a que el punto se usa como un separador para rutas con formato. Si necesitas usar un punto dentro de un segmento dinámico, agrega una restricción que anule esto – por ejemplo, id: /[^\/]+/
permite cualquier cosa excepto una barra.
3.3 Segmentos Estáticos
Puedes especificar segmentos estáticos al crear una ruta al no anteponer un colon a un segmento:
get 'photos/:id/with_user/:user_id', to: 'photos#show'
Esta ruta respondería a rutas como /photos/1/with_user/2
. En este caso, params
sería { controller: 'photos', action: 'show', id: '1', user_id: '2' }
.
3.4 La Cadena de Consulta
Los params
también incluirán cualquier parámetro de la cadena de consulta. Por ejemplo, con esta ruta:
get 'photos/:id', to: 'photos#show'
Una ruta entrante de /photos/1?user_id=2
será enviada a la acción show
del controlador Photos
. params
será { controller: 'photos', action: 'show', id: '1', user_id: '2' }
.
3.5 Definiendo Valores Predeterminados
Puedes definir valores predeterminados en una ruta proporcionando un hash para la opción :defaults
. Esto incluso se aplica a parámetros que no especificas como segmentos dinámicos. Por ejemplo:
get 'photos/:id', to: 'photos#show', defaults: { format: 'jpg' }
Rails emparejaría photos/12
con la acción show
del PhotosController
, y establecería params[:format]
en "jpg"
.
También puedes usar un bloque defaults
para definir los valores predeterminados para múltiples elementos:
defaults format: :json do
resources :photos
end
NOTA: No puedes anular los valores predeterminados a través de parámetros de consulta - esto es por razones de seguridad. Los únicos valores predeterminados que se pueden anular son los segmentos dinámicos a través de la sustitución en la ruta de URL.
3.6 Nombrando Rutas
Puedes especificar un nombre para cualquier ruta usando la opción :as
:
get 'exit', to: 'sessions#destroy', as: :logout
Esto creará logout_path
y logout_url
como helpers de ruta nombrados en tu aplicación. Llamar a logout_path
devolverá /exit
También puedes usar esto para anular métodos de enrutamiento definidos por recursos colocando rutas personalizadas antes de que se defina el recurso, así:
get ':username', to: 'users#show', as: :user
resources :users
Esto definirá un método user_path
que estará disponible en controladores, helpers y vistas que irán a una ruta como /bob
. Dentro de la acción show
del UsersController
, params[:username]
contendrá el nombre de usuario del usuario. Cambia :username
en la definición de la ruta si no deseas que el nombre de tu parámetro sea :username
.
3.7 Restricciones de Verbos HTTP
En general, deberías usar los métodos get
, post
, put
, patch
, y delete
para restringir una ruta a un verbo en particular. Puedes usar el método match
con la opción :via
para emparejar múltiples verbos a la vez:
match 'photos', to: 'photos#show', via: [:get, :post]
Puedes emparejar todos los verbos a una ruta en particular usando via: :all
:
match 'photos', to: 'photos#show', via: :all
NOTA: Enrutar tanto solicitudes GET
como POST
a una sola acción tiene implicaciones de seguridad. En general, deberías evitar enrutar todos los verbos a una acción a menos que tengas una buena razón para hacerlo.
NOTA: GET
en Rails no verificará el token CSRF. Nunca deberías escribir en la base de datos desde solicitudes GET
, para más información consulta la guía de seguridad sobre contramedidas CSRF.
3.8 Restricciones de Segmentos
Puedes usar la opción :constraints
para imponer un formato para un segmento dinámico:
get 'photos/:id', to: 'photos#show', constraints: { id: /[A-Z]\d{5}/ }
Esta ruta emparejaría rutas como /photos/A12345
, pero no /photos/893
. Puedes expresar la misma ruta de manera más concisa de esta manera:
get 'photos/:id', to: 'photos#show', id: /[A-Z]\d{5}/
:constraints
toma expresiones regulares con la restricción de que no se pueden usar anclas de regexp. Por ejemplo, la siguiente ruta no funcionará:
get '/:id', to: 'articles#show', constraints: { id: /^\d/ }
Sin embargo, ten en cuenta que no necesitas usar anclas porque todas las rutas están ancladas al inicio y al final.
Por ejemplo, las siguientes rutas permitirían articles
con valores to_param
como 1-hello-world
que siempre comienzan con un número y users
con valores to_param
como david
que nunca comienzan con un número para compartir el namespace raíz:
get '/:id', to: 'articles#show', constraints: { id: /\d.+/ }
get '/:username', to: 'users#show'
3.9 Restricciones Basadas en Solicitudes
También puedes restringir una ruta basada en cualquier método en el objeto Request que devuelva una String
.
Especificas una restricción basada en solicitudes de la misma manera que especificas una restricción de segmento:
get 'photos', to: 'photos#index', constraints: { subdomain: 'admin' }
También puedes especificar restricciones usando un bloque constraints
:
namespace :admin do
constraints subdomain: 'admin' do
resources :photos
end
end
NOTA: Las restricciones de solicitud funcionan llamando a un método en el objeto Request con el mismo nombre que la clave del hash y luego comparando el valor de retorno con el valor del hash. Por lo tanto, los valores de restricción deben coincidir con el tipo de retorno del método del objeto Request correspondiente. Por ejemplo: constraints: { subdomain: 'api' }
coincidirá con un subdominio api
como se espera. Sin embargo, usar un símbolo constraints: { subdomain: :api }
no lo hará, porque request.subdomain
devuelve 'api'
como una String.
NOTA: Hay una excepción para la restricción format
: aunque es un método en el objeto Request, también es un parámetro opcional implícito en cada ruta. Las restricciones de segmento tienen prioridad y la restricción format
solo se aplica como tal cuando se aplica a través de un hash. Por ejemplo, get 'foo', constraints: { format: 'json' }
coincidirá con GET /foo
porque el formato es opcional por defecto. Sin embargo, puedes usar un lambda como en get 'foo', constraints: lambda { |req| req.format == :json }
y la ruta solo coincidirá con solicitudes JSON explícitas.
3.10 Restricciones Avanzadas
Si tienes una restricción más avanzada, puedes proporcionar un objeto que responda a matches?
que Rails debería usar. Digamos que querías enrutar a todos los usuarios en una lista restringida al RestrictedListController
. Podrías hacer:
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
También puedes especificar restricciones como un lambda:
Rails.application.routes.draw do
get '*path', to: 'restricted_list#index',
constraints: lambda { |request| RestrictedList.retrieve_ips.include?(request.remote_ip) }
end
Tanto el método matches?
como el lambda reciben el objeto request
como argumento.
3.10.1 Restricciones en Forma de Bloque
Puedes especificar restricciones en forma de bloque. Esto es útil cuando necesitas aplicar la misma regla a varias rutas. Por ejemplo:
class RestrictedListConstraint
# ...Igual que el ejemplo anterior
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
También puedes usar un 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
3.11 Globbing de Rutas y Segmentos Comodín
El globbing de rutas es una forma de especificar que un parámetro particular debe coincidir con todas las partes restantes de una ruta. Por ejemplo:
get 'photos/*other', to: 'photos#unknown'
Esta ruta coincidiría con photos/12
o /photos/long/path/to/12
, estableciendo params[:other]
en "12"
o "long/path/to/12"
. Los segmentos prefijados con un asterisco se llaman "segmentos comodín".
Los segmentos comodín pueden ocurrir en cualquier lugar de una ruta. Por ejemplo:
get 'books/*section/:title', to: 'books#show'
coincidiría con books/some/section/last-words-a-memoir
con params[:section]
igual a 'some/section'
, y params[:title]
igual a 'last-words-a-memoir'
.
Técnicamente, una ruta puede tener incluso más de un segmento comodín. El emparejador asigna segmentos a parámetros de manera intuitiva. Por ejemplo:
get '*a/foo/*b', to: 'test#index'
coincidiría con zoo/woo/foo/bar/baz
con params[:a]
igual a 'zoo/woo'
, y params[:b]
igual a 'bar/baz'
.
NOTA: Al solicitar '/foo/bar.json'
, tu params[:pages]
será igual a 'foo/bar'
con el formato de solicitud de JSON. Si deseas el comportamiento anterior de 3.0.x de vuelta, podrías suministrar format: false
así:
get '*pages', to: 'pages#show', format: false
NOTA: Si deseas hacer que el segmento de formato sea obligatorio, de modo que no se pueda omitir, puedes suministrar format: true
así:
get '*pages', to: 'pages#show', format: true
3.12 Redirección
Puedes redirigir cualquier ruta a otra ruta usando el helper redirect
en tu router:
get '/stories', to: redirect('/articles')
También puedes reutilizar segmentos dinámicos del emparejamiento en la ruta a la que redirigir:
get '/stories/:name', to: redirect('/articles/%{name}')
También puedes proporcionar un bloque a redirect
, que recibe los parámetros de ruta simbolizados y el objeto de solicitud:
get '/stories/:name', to: redirect { |path_params, req| "/articles/#{path_params[:name].pluralize}" }
get '/stories', to: redirect { |path_params, req| "/articles/#{req.subdomain}" }
Ten en cuenta que la redirección predeterminada es una redirección 301 "Movido Permanentemente". Ten en cuenta que algunos navegadores web o servidores proxy almacenarán en caché este tipo de redirección, haciendo que la página antigua sea inaccesible. Puedes usar la opción :status
para cambiar el estado de la respuesta:
get '/stories/:name', to: redirect('/articles/%{name}', status: 302)
En todos estos casos, si no proporcionas el host principal (http://www.example.com
), Rails tomará esos detalles de la solicitud actual.
3.13 Enrutando a Aplicaciones Rack
En lugar de una cadena como 'articles#index'
, que corresponde a la acción index
en el ArticlesController
, puedes especificar cualquier aplicación Rack como el endpoint para un emparejador:
match '/application.js', to: MyRackApp, via: :all
Siempre que MyRackApp
responda a call
y devuelva un [status, headers, body]
, el router no sabrá la diferencia entre la aplicación Rack y una acción. Este es un uso apropiado de via: :all
, ya que querrás permitir que tu aplicación Rack maneje todos los verbos como lo considere apropiado.
NOTA: Para los curiosos, 'articles#index'
en realidad se expande a ArticlesController.action(:index)
, que devuelve una aplicación Rack válida.
NOTA: Dado que los procs/lambdas son objetos que responden a call
, puedes implementar rutas muy simples (por ejemplo, para verificaciones de salud) en línea:get '/health', to: ->(env) { [204, {}, ['']] }
Si especificas una aplicación Rack como el endpoint para un emparejador, recuerda que la ruta no cambiará en la aplicación receptora. Con la siguiente ruta, tu aplicación Rack debería esperar que la ruta sea /admin
:
match '/admin', to: AdminApp, via: :all
Si prefieres que tu aplicación Rack reciba solicitudes en la ruta raíz en su lugar, usa mount
:
mount AdminApp, at: '/admin'
3.14 Usando root
Puedes especificar a qué debería enrutar Rails '/'
con el método root
:
root to: 'pages#main'
root 'pages#main' # atajo para lo anterior
Deberías colocar la ruta root
en la parte superior del archivo, porque es la ruta más popular y debería coincidir primero.
NOTA: La ruta root
solo enruta solicitudes GET
a la acción.
También puedes usar root dentro de namespaces y scopes. Por ejemplo:
namespace :admin do
root to: "admin#index"
end
root to: "home#index"
3.15 Rutas de Caracteres Unicode
Puedes especificar rutas de caracteres unicode directamente. Por ejemplo:
get 'こんにちは', to: 'welcome#index'
3.16 Rutas Directas
Puedes crear helpers de URL personalizados directamente llamando a direct
. Por ejemplo:
direct :homepage do
"https://rubyonrails.org"
end
# >> homepage_url
# => "https://rubyonrails.org"
El valor de retorno del bloque debe ser un argumento válido para el método url_for
. Por lo tanto, puedes pasar una URL de cadena válida, Hash, Array, una instancia de Active Model o una clase de Active Model.
direct :commentable do |model|
[ model, anchor: model.dom_id ]
end
direct :main do
{ controller: 'pages', action: 'index', subdomain: 'www' }
end
3.17 Usando resolve
El método resolve
permite personalizar el mapeo polimórfico de modelos. Por ejemplo:
resource :basket
resolve("Basket") { [:basket] }
<%= form_with model: @basket do |form| %>
<!-- formulario de cesta -->
<% end %>
Esto generará la URL singular /basket
en lugar de la habitual /baskets/:id
.
4 Personalizando Rutas de Recursos
Si bien las rutas y helpers predeterminados generados por resources
generalmente te servirán bien, es posible que desees personalizarlos de alguna manera. Rails te permite personalizar prácticamente cualquier parte genérica de los helpers de recursos.
4.1 Especificando un Controlador a Usar
La opción :controller
te permite especificar explícitamente un controlador para usar con el recurso. Por ejemplo:
resources :photos, controller: 'images'
reconocerá rutas entrantes que comiencen con /photos
pero enrutará al controlador Images
:
Verbo HTTP | Ruta | Controlador#Acción | Helper de Ruta Nombrada |
---|---|---|---|
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) |
NOTA: Usa photos_path
, new_photo_path
, etc. para generar rutas para este recurso.
Para controladores en un namespace, puedes usar la notación de directorio. Por ejemplo:
resources :user_permissions, controller: 'admin/user_permissions'
Esto enrutará al controlador Admin::UserPermissions
.
NOTA: Solo se admite la notación de directorio. Especificar el controlador con la notación de constante Ruby (por ejemplo, controller: 'Admin::UserPermissions'
) puede llevar a problemas de enrutamiento y resulta en una advertencia.
4.2 Especificando Restricciones
Puedes usar la opción :constraints
para especificar un formato requerido en el id
implícito. Por ejemplo:
resources :photos, constraints: { id: /[A-Z][A-Z][0-9]+/ }
Esta declaración restringe el parámetro :id
para que coincida con la expresión regular suministrada. Entonces, en este caso, el router ya no coincidiría con /photos/1
para esta ruta. En su lugar, /photos/RR27
coincidiría.
Puedes especificar una sola restricción para aplicar a varias rutas usando la forma de bloque:
constraints(id: /[A-Z][A-Z][0-9]+/) do
resources :photos
resources :accounts
end
NOTA: Por supuesto, puedes usar las restricciones más avanzadas disponibles en rutas no-resursivas en este contexto.
CONSEJO: Por defecto, el parámetro :id
no acepta puntos - esto se debe a que el punto se usa como un separador para rutas con formato. Si necesitas usar un punto dentro de un :id
, agrega una restricción que anule esto - por ejemplo, id: /[^\/]+/
permite cualquier cosa excepto una barra.
4.3 Anulando los Helpers de Ruta Nombrada
La opción :as
te permite anular la nomenclatura normal para los helpers de ruta nombrada. Por ejemplo:
resources :photos, as: 'images'
reconocerá rutas entrantes que comiencen con /photos
y enrutará las solicitudes al PhotosController
, pero usará el valor de la opción :as
para nombrar los helpers.
Verbo HTTP | Ruta | Controlador#Acción | Helper de Ruta Nombrada |
---|---|---|---|
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 Anulando los Segmentos new
y edit
La opción :path_names
te permite anular los segmentos new
y edit
generados automáticamente en las rutas:
resources :photos, path_names: { new: 'make', edit: 'change' }
Esto haría que el enrutamiento reconozca rutas como:
/photos/make
/photos/1/change
NOTA: Los nombres de acción reales no se cambian con esta opción. Las dos rutas mostradas todavía enrutarían a las acciones new
y edit
.
CONSEJO: Si te encuentras queriendo cambiar esta opción de manera uniforme para todas tus rutas, puedes usar un scope, como a continuación:
scope path_names: { new: 'make' } do
# resto de tus rutas
end
4.5 Prefijando los Helpers de Ruta Nombrada
Puedes usar la opción :as
para prefijar los helpers de ruta nombrada que Rails genera para una ruta. Usa esta opción para evitar colisiones de nombres entre rutas usando un scope de ruta. Por ejemplo:
scope 'admin' do
resources :photos, as: 'admin_photos'
end
resources :photos
Esto cambia los helpers de ruta para /admin/photos
de photos_path
, new_photos_path
, etc. a admin_photos_path
, new_admin_photo_path
, etc. Sin la adición de as: 'admin_photos'
en el recurso resources :photos
con scope, los recursos no con scope no tendrán ningún helper de ruta.
Para prefijar un grupo de helpers de ruta, usa :as
con scope
:
scope 'admin', as: 'admin' do
resources :photos, :accounts
end
resources :photos, :accounts
Al igual que antes, esto cambia los helpers de recurso con scope /admin
a admin_photos_path
y admin_accounts_path
, y permite que los recursos sin scope usen photos_path
y accounts_path
.
NOTA: El scope namespace
agregará automáticamente prefijos :as
así como prefijos de :module
y :path
.
4.5.1 Scopes Paramétricos
Puedes prefijar rutas con un parámetro nombrado:
scope ':account_id', as: 'account', constraints: { account_id: /\d+/ } do
resources :articles
end
Esto te proporcionará rutas como /1/articles/9
y te permitirá referenciar la parte account_id
de la ruta como params[:account_id]
en controladores, helpers y vistas.
También generará helpers de ruta y URL prefijados con account_
, en los que puedes pasar tus objetos como se espera:
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" ...>
Estamos usando una restricción para limitar el scope para que coincida solo con cadenas similares a IDs. Puedes cambiar la restricción para adaptarla a tus necesidades, o omitirla por completo. La opción :as
tampoco es estrictamente necesaria, pero sin ella, Rails generará un error al evaluar url_for([@account, @article])
u otros helpers que dependen de url_for
, como form_with
.
4.6 Restringiendo las Rutas Creadas
Por defecto, Rails crea rutas para las siete acciones predeterminadas (index
, show
, new
, create
, edit
, update
y destroy
) para cada ruta RESTful en tu aplicación. Puedes usar las opciones :only
y :except
para afinar este comportamiento. La opción :only
le dice a Rails que cree solo las rutas especificadas:
resources :photos, only: [:index, :show]
Ahora, una solicitud GET
a /photos
tendría éxito, pero una solicitud POST
a /photos
(que normalmente se enviaría a la acción create
) fallará.
La opción :except
especifica una ruta o lista de rutas que Rails no debería crear:
resources :photos, except: :destroy
En este caso, Rails creará todas las rutas normales excepto la ruta para destroy
(una solicitud DELETE
a /photos/:id
).
CONSEJO: Si tu aplicación tiene muchas rutas RESTful, usar :only
y :except
para generar solo las rutas que realmente necesitas puede reducir el uso de memoria y acelerar el proceso de enrutamiento.
4.7 Rutas Traducidas
Usando scope
, podemos alterar los nombres de ruta generados por resources
:
scope(path_names: { new: 'neu', edit: 'bearbeiten' }) do
resources :categories, path: 'kategorien'
end
Rails ahora crea rutas para el CategoriesController
.
Verbo HTTP | Ruta | Controlador#Acción | Helper de Ruta Nombrada |
---|---|---|---|
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.8 Anulando la Forma Singular
Si deseas anular la forma singular de un recurso, debes agregar reglas adicionales al inflector a través de inflections
:
ActiveSupport::Inflector.inflections do |inflect|
inflect.irregular 'tooth', 'teeth'
end
4.9 Usando :as
en Recursos Anidados
La opción :as
anula el nombre generado automáticamente para el recurso en los helpers de ruta anidada. Por ejemplo:
resources :magazines do
resources :ads, as: 'periodical_ads'
end
Esto creará helpers de ruta como magazine_periodical_ads_url
y edit_magazine_periodical_ad_path
.
4.10 Anulando Parámetros de Ruta Nombrados
La opción :param
anula el identificador de recurso predeterminado :id
(nombre del segmento dinámico utilizado para generar las rutas). Puedes acceder a ese segmento desde tu controlador usando 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])
Puedes anular ActiveRecord::Base#to_param
del modelo asociado para construir una 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"
5 Dividiendo un Archivo de Rutas Muy Grande en Múltiples Archivos Pequeños
Si trabajas en una aplicación grande con miles de rutas, un solo archivo config/routes.rb
puede volverse engorroso y difícil de leer.
Rails ofrece una forma de dividir un archivo único gigantesco de routes.rb
en múltiples archivos pequeños usando la macro draw
.
Podrías tener una ruta admin.rb
que contenga todas las rutas para el área de administración, otro archivo api.rb
para recursos relacionados con la API, etc.
# config/routes.rb
Rails.application.routes.draw do
get 'foo', to: 'foo#bar'
draw(:admin) # Cargará otro archivo de ruta ubicado en `config/routes/admin.rb`
end
# config/routes/admin.rb
namespace :admin do
resources :comments
end
Llamar a draw(:admin)
dentro del bloque Rails.application.routes.draw
intentará cargar un archivo de ruta que tenga el mismo nombre que el argumento dado (admin.rb
en este ejemplo). El archivo debe estar ubicado dentro del directorio config/routes
o cualquier subdirectorio (es decir, config/routes/admin.rb
o config/routes/external/admin.rb
).
Puedes usar el DSL de enrutamiento normal dentro del archivo de enrutamiento admin.rb
, pero no deberías rodearlo con el bloque Rails.application.routes.draw
como lo hiciste en el archivo principal config/routes.rb
.
5.1 No Uses Esta Función a Menos que Realmente la Necesites
Tener múltiples archivos de enrutamiento hace que la descubribilidad y comprensión sean más difíciles. Para la mayoría de las aplicaciones, incluso aquellas con algunas centenas de rutas, es más fácil para los desarrolladores tener un solo archivo de enrutamiento. El DSL de enrutamiento de Rails ya ofrece una forma de organizar rutas de manera organizada con namespace
y scope
.
6 Inspeccionando y Probando Rutas
Rails ofrece facilidades para inspeccionar y probar tus rutas.
6.1 Listando Rutas Existentes
Para obtener una lista completa de las rutas disponibles en tu aplicación, visita http://localhost:3000/rails/info/routes en tu navegador mientras tu servidor está funcionando en el entorno de desarrollo. También puedes ejecutar el comando bin/rails routes
en tu terminal para producir la misma salida.
Ambos métodos enumerarán todas tus rutas, en el mismo orden en que aparecen en config/routes.rb
. Para cada ruta, verás:
- El nombre de la ruta (si lo hay)
- El verbo HTTP usado (si la ruta no responde a todos los verbos)
- El patrón de URL a coincidir
- Los parámetros de enrutamiento para la ruta
Por ejemplo, aquí hay una pequeña sección de la salida bin/rails routes
para una ruta 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
También puedes usar la opción --expanded
para activar el modo de formato de tabla expandida.
$ 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
Puedes buscar a través de tus rutas con la opción grep: -g. Esto genera cualquier ruta que coincida parcialmente con el nombre del método helper de URL, el verbo HTTP o la ruta URL.
$ bin/rails routes -g new_comment
$ bin/rails routes -g POST
$ bin/rails routes -g admin
Si solo deseas ver las rutas que mapean a un controlador específico, existe la opción -c.
$ bin/rails routes -c users
$ bin/rails routes -c admin/users
$ bin/rails routes -c Comments
$ bin/rails routes -c Articles::CommentsController
CONSEJO: Encontrarás que la salida de bin/rails routes
es mucho más legible si amplías la ventana de tu terminal hasta que las líneas de salida no se envuelvan.
6.2 Probando Rutas
Las rutas deben estar incluidas en tu estrategia de pruebas (al igual que el resto de tu aplicación). Rails ofrece tres afirmaciones integradas diseñadas para hacer que probar rutas sea más simple:
6.2.1 La Afirmación assert_generates
assert_generates
afirma que un conjunto particular de opciones genera una ruta particular y puede usarse con rutas predeterminadas o rutas personalizadas. Por ejemplo:
assert_generates '/photos/1', { controller: 'photos', action: 'show', id: '1' }
assert_generates '/about', controller: 'pages', action: 'about'
6.2.2 La Afirmación assert_recognizes
assert_recognizes
es el inverso de assert_generates
. Afirma que una ruta dada es reconocida y la enruta a un lugar particular en tu aplicación. Por ejemplo:
assert_recognizes({ controller: 'photos', action: 'show', id: '1' }, '/photos/1')
Puedes suministrar un argumento :method
para especificar el verbo HTTP:
assert_recognizes({ controller: 'photos', action: 'create' }, { path: 'photos', method: :post })
6.2.3 La Afirmación assert_routing
La afirmación assert_routing
verifica la ruta en ambos sentidos: prueba que la ruta genera las opciones, y que las opciones generan la ruta. Por lo tanto, combina las funciones de assert_generates
y assert_recognizes
:
assert_routing({ path: 'photos', method: :post }, { controller: 'photos', action: 'create' })
Comentarios
Se te anima a ayudar a mejorar la calidad de esta guía.
Por favor contribuye si ves algún error tipográfico o errores fácticos. Para comenzar, puedes leer nuestra sección de contribuciones a la documentación.
También puedes encontrar contenido incompleto o cosas que no están actualizadas. Por favor agrega cualquier documentación faltante para main. Asegúrate de revisar Guías Edge primero para verificar si los problemas ya están resueltos o no en la rama principal. Revisa las Guías de Ruby on Rails para estilo y convenciones.
Si por alguna razón detectas algo que corregir pero no puedes hacerlo tú mismo, por favor abre un issue.
Y por último, pero no menos importante, cualquier tipo de discusión sobre la documentación de Ruby on Rails es muy bienvenida en el Foro oficial de Ruby on Rails.