1 El propósito del enrutador de Rails
El enrutador de Rails reconoce las URLs y las envía a una acción del controlador o a una aplicación de Rack. También puede generar rutas y URLs, evitando la necesidad de codificar cadenas en tus vistas.
1.1 Conexión de URLs con código
Cuando tu aplicación de Rails recibe una solicitud entrante para:
GET /patients/17
le pide al enrutador que lo 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 utiliza snake_case para los nombres de los controladores aquí, si tienes un controlador de varias palabras como MonsterTrucksController
, debes usar monster_trucks#show
, por ejemplo.
1.2 Generación de rutas y URLs desde el código
También puedes generar rutas y URLs. Si la ruta anterior se modifica de la siguiente manera:
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 'Registro del paciente', patient_path(@patient) %>
entonces el enrutador 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 especificarse en el ayudante de ruta.
1.3 Configuración del enrutador de Rails
Las rutas de tu aplicación o motor se encuentran 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 regular de Ruby, puedes utilizar todas sus características para ayudarte a definir tus rutas, pero ten cuidado con los nombres de las variables, ya que pueden entrar en conflicto con los métodos DSL del enrutador.
NOTA: El bloque Rails.application.routes.draw do ... end
que envuelve tus definiciones de ruta es necesario para establecer el alcance del DSL del enrutador y no debe eliminarse.
2 Enrutamiento de recursos: el predeterminado de Rails
El enrutamiento de recursos te permite 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 a Rails haciendo una solicitud de una URL utilizando 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 asigna varias solicitudes relacionadas a acciones en un solo controlador.
Cuando tu aplicación de Rails recibe una solicitud entrante para:
DELETE /photos/17
le pide al enrutador que lo asigne a una acción del controlador. Si la primera ruta coincidente es:
resources :photos
Rails enviaría esa solicitud a la acción destroy
del controlador photos
con { id: '17' }
en params
.
2.2 CRUD, verbos y acciones
En Rails, una ruta de recursos proporciona una asignación entre los verbos HTTP y las URLs a las acciones del controlador. Por convención, cada acción también se asigna a una operación CRUD específica en una base de datos. Una sola entrada en el archivo de enrutamiento, como:
resources :photos
crea siete rutas diferentes en tu aplicación, todas asignadas 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 enrutador utiliza el verbo HTTP y la URL para coincidir con las solicitudes entrantes, cuatro URLs se asignan 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
arriba de la línea resources
para que se empareje primero.
2.3 Helpers de Ruta y URL
Al crear una ruta de recursos, también se exponen varios helpers a los controladores de 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 correspondiente _url
(como photos_url
) que devuelve la misma ruta con el prefijo del host actual, el puerto y el prefijo de la ruta.
CONSEJO: Para encontrar los nombres de los helpers de ruta para tus rutas, consulta Listar rutas existentes a continuación.
2.4 Definir 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 que ha iniciado sesión actualmente. En este caso, puedes usar un recurso singular para asignar /profile
(en lugar de /profile/:id
) a la acción show
:
get 'profile', to: 'users#show'
Al pasar una String
a to:
, se espera un formato controller#action
. Cuando se utiliza un Symbol
, la opción to:
debe reemplazarse por action:
. Cuando se utiliza una String
sin un #
, la opción to:
debe reemplazarse por controller:
:
get 'profile', action: :show, controller: 'users'
Esta ruta de recursos:
resource :geocoder
resolve('Geocoder') { [:geocoder] }
crea seis rutas diferentes en tu aplicación, todas asignadas al controlador Geocoders
:
Verbo HTTP | Ruta | Controlador#Acción | Utilizado para |
---|---|---|---|
GET | /geocoder/new | geocoders#new | devuelve un formulario HTML para crear el geocodificador |
POST | /geocoder | geocoders#create | crea el nuevo geocodificador |
GET | /geocoder | geocoders#show | muestra el único recurso geocodificador |
GET | /geocoder/edit | geocoders#edit | devuelve un formulario HTML para editar el geocodificador |
PATCH/PUT | /geocoder | geocoders#update | actualiza el único recurso geocodificador |
DELETE | /geocoder | geocoders#destroy | elimina el recurso geocodificador |
NOTA: Debido a que es posible que desees utilizar el mismo controlador para una ruta singular (/account
) y una ruta plural (/accounts/45
), los recursos singulares se asignan a controladores plurales. Por ejemplo, resource :photo
y resources :photos
crean rutas tanto singulares como plurales que se asignan al mismo controlador (PhotosController
).
Una ruta de recursos 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 de Geocoder
en rutas a través de identificación de registros.
Al igual que con los recursos plurales, los mismos helpers que terminan en _url
también incluirán el host, el puerto y el prefijo de la ruta.
2.6 Espacios de Nombres de Controladores y Enrutamiento
Es posible que desees organizar grupos de controladores bajo un espacio de nombres. Lo más común es agrupar varios controladores administrativos bajo un espacio de nombres Admin::
y colocar estos controladores en el directorio app/controllers/admin
. Puedes enrutarte a este grupo utilizando un bloque namespace
:
namespace :admin do
resources :articles, :comments
end
Esto creará varias rutas para cada uno de los controladores articles
y comments
. Para Admin::ArticlesController
, Rails creará:
Verbo HTTP | Ruta | Controlador#Acción | Helper de Ruta Nombrado |
---|---|---|---|
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 del 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 ayudantes de ruta con nombre siguen siendo los mismos que si no usaste scope
. En el último caso, las siguientes rutas se asignan a ArticlesController
:
Verbo HTTP | Ruta | Controlador#Acción | Ayudante de ruta con nombre |
---|---|---|---|
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 espacio de nombres 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 las revistas, esta declaración también enrutará los anuncios a un AdsController
. Las URL de los anuncios requieren una revista:
Verbo HTTP | Ruta | Controlador#Acción | Utilizado para |
---|---|---|---|
GET | /magazines/:magazine_id/ads | ads#index | mostrar una lista de todos los anuncios de una revista específica |
GET | /magazines/:magazine_id/ads/new | ads#new | devolver un formulario HTML para crear un nuevo anuncio perteneciente a una revista específica |
POST | /magazines/:magazine_id/ads | ads#create | crear un nuevo anuncio perteneciente a una revista específica |
GET | /magazines/:magazine_id/ads/:id | ads#show | mostrar un anuncio específico perteneciente a una revista específica |
GET | /magazines/:magazine_id/ads/:id/edit | ads#edit | devolver un formulario HTML para editar un anuncio perteneciente a una revista específica |
PATCH/PUT | /magazines/:magazine_id/ads/:id | ads#update | actualizar un anuncio específico perteneciente a una revista específica |
DELETE | /magazines/:magazine_id/ads/:id | ads#destroy | eliminar un anuncio específico perteneciente a una revista específica |
Esto también creará ayudantes de enrutamiento como magazine_ads_url
y edit_magazine_ad_path
. Estos ayudantes toman una instancia de Magazine como el primer parámetro (magazine_ads_url(@magazine)
).
2.7.1 Límites para la 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 ayudante de ruta correspondiente sería publisher_magazine_photo_url
, lo que requeriría 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 general para un buen diseño de 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 anteriormente) es generar las acciones de colección con ámbito bajo el padre, para tener una idea de la jerarquía, pero no anidar las acciones de miembro. En otras palabras, solo construir rutas con la cantidad mínima de información para identificar de manera única el recurso, como esto:
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 exactamente eso, a través de la opción :shallow
:
resources :articles do
resources :comments, shallow: true
end
Esto generará las mismas rutas exactas 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 de artículos aquí tendrá las siguientes rutas generadas:
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
de la DSL crea un ámbito dentro del cual cada anidamiento 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
agrega un prefijo a las rutas de miembros con el parámetro especificado:
scope shallow_path: "sekret" do
resources :articles do
resources :comments, shallow: true
end
end
El recurso de comentarios aquí tendrá las siguientes rutas generadas:
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 ayudantes de ruta nombrados:
scope shallow_prefix: "sekret" do
resources :articles do
resources :comments, shallow: true
end
end
El recurso de comentarios aquí tendrá las siguientes rutas generadas:
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 se pueden reutilizar dentro de otros recursos y rutas. Para definir una preocupación, utiliza un bloque concern
:
concern :commentable do
resources :comments
end
concern :image_attachable do
resources :images, only: :index
end
Estas preocupaciones se pueden utilizar en recursos para evitar la duplicación de código y compartir comportamiento en las 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 usarlos en cualquier lugar llamando a concerns
. Por ejemplo, en un bloque scope
o namespace
:
namespace :articles do
concerns :commentable
end
2.9 Creación de rutas y URLs a partir de objetos
Además de utilizar los ayudantes de enrutamiento, Rails también puede crear rutas y URLs a partir de una matriz de parámetros. Por ejemplo, supongamos que tienes este conjunto de rutas:
resources :magazines do
resources :ads
end
Cuando uses magazine_ad_path
, puedes pasar instancias de Magazine
y Ad
en lugar de los IDs numéricos:
<%= link_to 'Detalles del anuncio', magazine_ad_path(@magazine, @ad) %>
También puedes usar url_for
con un conjunto de objetos, y Rails determinará automáticamente qué ruta quieres:
<%= link_to 'Detalles del anuncio', url_for([@magazine, @ad]) %>
En este caso, Rails verá que @magazine
es un Magazine
y @ad
es un Ad
y utilizará el ayudante magazine_ad_path
. En ayudantes como link_to
, puedes especificar solo el objeto en lugar de la llamada completa a url_for
:
<%= link_to 'Detalles del anuncio', [@magazine, @ad] %>
Si quisieras enlazar solo a una revista:
<%= link_to 'Detalles de la revista', @magazine %>
Para otras acciones, solo necesitas insertar el nombre de la acción como el primer elemento de la matriz:
<%= link_to 'Editar anuncio', [:edit, @magazine, @ad] %>
Esto te permite tratar las instancias de tus modelos como URLs, y es una ventaja clave de usar el estilo de recursos.
2.10 Agregar más acciones RESTful
No estás limitado a las siete rutas que el enrutamiento RESTful crea de forma predeterminada. Si lo deseas, puedes agregar rutas adicionales que se apliquen a la colección o a los miembros individuales de la colección.
2.10.1 Agregar rutas de miembros
Para agregar una ruta de miembro, simplemente 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 controlador PhotosController
, con el valor del ID del recurso pasado en params[:id]
. También creará los ayudantes preview_photo_url
y preview_photo_path
.
Dentro del bloque de rutas de miembros, cada nombre de ruta especifica el verbo HTTP que se reconocerá. 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 del ID del recurso estará disponible en params[:photo_id]
en lugar de params[:id]
. Los ayudantes 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 Agregar rutas de colección
Para agregar una ruta a la colección, utiliza un bloque collection
:
resources :photos do
collection do
get 'search'
end
end
Esto permitirá que Rails reconozca rutas como /photos/search
con GET y enrute a la acción search
del controlador PhotosController
. También creará los ayudantes de ruta search_photos_url
y search_photos_path
.
Al igual que con las rutas de miembros, 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 Agregar rutas para acciones nuevas adicionales
Para agregar una acción nueva alternativa utilizando el atajo :on
:
resources :comments do
get 'preview', on: :new
end
Esto permitirá que Rails reconozca rutas como /comments/new/preview
con GET y enrute a la acción preview
del controlador CommentsController
. También creará los ayudantes de ruta preview_new_comment_url
y preview_new_comment_path
.
CONSEJO: Si te encuentras agregando muchas acciones adicionales a una ruta de recursos, es hora de detenerte y preguntarte si estás disfrazando la presencia de otro recurso.
3 Rutas no relacionadas con recursos
Además del enrutamiento de recursos, Rails tiene un soporte poderoso para enrutamiento de URLs arbitrarias a acciones. Aquí, no obtienes grupos de rutas generados automáticamente por el enrutamiento de recursos. En su lugar, configuras cada ruta por separado dentro de tu aplicación.
Si bien generalmente debes usar el enrutamiento de recursos, todavía hay muchos lugares donde el enrutamiento más simple es más apropiado. No es necesario tratar de encajar cada último detalle de tu aplicación en un marco de recursos si no es adecuado. En particular, el enrutamiento simple hace que sea muy fácil asignar URL heredadas a nuevas acciones de Rails.
3.1 Parámetros vinculados
Cuando configuras una ruta regular, proporcionas una serie de símbolos que Rails asigna 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 coincide con ninguna ruta anterior en el archivo), entonces el resultado será invocar la acción display
del controlador PhotosController
y hacer que el parámetro final "1"
esté disponible como params[:id]
. Esta ruta también enrutaría la solicitud entrante de /photos
a PhotosController#display
, ya que :id
es un parámetro opcional, indicado por paréntesis.
3.2 Segmentos dinámicos
Puedes configurar tantos segmentos dinámicos como desees dentro de una ruta regular. 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
se enviará a la acción show
del controlador 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 utiliza como separador para las rutas formateadas. 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 diagonal.
3.3 Segmentos estáticos
Puedes especificar segmentos estáticos al crear una ruta sin anteponer dos puntos 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
params
también incluirá 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
se enviará a la acción show
del controlador Photos
. params
será { controller: 'photos', action: 'show', id: '1', user_id: '2' }
.
3.5 Definir valores predeterminados
Puedes definir valores predeterminados en una ruta proporcionando un hash para la opción :defaults
. Esto también se aplica a los parámetros que no especificas como segmentos dinámicos. Por ejemplo:
get 'photos/:id', to: 'photos#show', defaults: { format: 'jpg' }
Rails coincidiría photos/12
con la acción show
de PhotosController
y establecería params[:format]
en "jpg"
.
También puedes usar un bloque defaults
para definir los valores predeterminados para varios 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 mediante la sustitución en la ruta URL.
3.6 Nombres de rutas
Puedes especificar un nombre para cualquier ruta utilizando la opción :as
:
get 'exit', to: 'sessions#destroy', as: :logout
Esto creará logout_path
y logout_url
como ayudantes de ruta con nombre en tu aplicación. Llamar a logout_path
devolverá /exit
.
También puedes usar esto para anular los métodos de enrutamiento definidos por los recursos colocando rutas personalizadas antes de que se defina el recurso, de esta manera:
get ':username', to: 'users#show', as: :user
resources :users
Esto definirá un método user_path
que estará disponible en controladores, ayudantes y vistas y que irá a una ruta como /bob
. Dentro de la acción show
de UsersController
, params[:username]
contendrá el nombre de usuario del usuario. Cambia :username
en la definición de la ruta si no quieres que el nombre del parámetro sea :username
.
3.7 Restricciones de verbo HTTP
En general, debes usar los métodos get
, post
, put
, patch
y delete
para restringir una ruta a un verbo particular. Puedes usar el método match
con la opción :via
para coincidir con múltiples verbos a la vez:
match 'photos', to: 'photos#show', via: [:get, :post]
Puedes hacer coincidir todos los verbos con una ruta particular usando via: :all
:
match 'photos', to: 'photos#show', via: :all
NOTA: Enrutar tanto las solicitudes GET
como POST
a una sola acción tiene implicaciones de seguridad. En general, debes 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 debes escribir en la base de datos desde solicitudes GET
, para obtener más información, consulta la guía de seguridad sobre las contramedidas CSRF.
3.8 Restricciones de segmentos
Puede utilizar 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 coincidiría con rutas como /photos/A12345
, pero no con /photos/893
. Puede expresar de manera más concisa la misma ruta 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 utilizar anclas de expresiones regulares. Por ejemplo, la siguiente ruta no funcionará:
get '/:id', to: 'articles#show', constraints: { id: /^\d/ }
Sin embargo, tenga en cuenta que no es necesario utilizar anclas porque todas las rutas están ancladas al principio y al final.
Por ejemplo, las siguientes rutas permitirían que los articles
con valores to_param
como 1-hello-world
que siempre comienzan con un número y los users
con valores to_param
como david
que nunca comienzan con un número compartan el espacio de nombres raíz:
get '/:id', to: 'articles#show', constraints: { id: /\d.+/ }
get '/:username', to: 'users#show'
3.9 Restricciones basadas en la solicitud
También puede restringir una ruta en función de cualquier método en el objeto Request que devuelva una String
.
Especifica una restricción basada en la solicitud de la misma manera que especificas una restricción de segmento:
get 'photos', to: 'photos#index', constraints: { subdomain: 'admin' }
También puede especificar restricciones utilizando 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 correspondiente del objeto Request. Por ejemplo: constraints: { subdomain: 'api' }
coincidirá con un subdominio api
como se espera. Sin embargo, el uso de un símbolo constraints: { subdomain: :api }
no lo hará, porque request.subdomain
devuelve 'api'
como una cadena.
NOTA: Existe una excepción para la restricción de formato
: 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 de formato
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 de forma predeterminada. Sin embargo, puede usar una 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 tiene una restricción más avanzada, puede proporcionar un objeto que responda a matches?
que Rails debe utilizar. Digamos que desea enrutar a todos los usuarios en una lista restringida al RestrictedListController
. Podrías hacer esto:
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 puede especificar restricciones como una 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 la lambda reciben el objeto request
como argumento.
3.10.1 Restricciones en forma de bloque
Puede especificar restricciones en forma de bloque. Esto es útil cuando necesita 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 puede usar una 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 Segmentos de comodín y restricciones
La segmentación de rutas es una forma de especificar que un parámetro en 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 con un asterisco como prefijo se llaman "segmentos de comodín".
Los segmentos de comodín pueden aparecer 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 de comodín. El emparejador asigna segmentos a parámetros de una 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'
, tus params[:pages]
será igual a 'foo/bar'
con el formato de solicitud JSON. Si deseas recuperar el comportamiento antiguo de la versión 3.0.x, puedes proporcionar format: false
de esta manera:
get '*pages', to: 'pages#show', format: false
NOTA: Si deseas que el segmento de formato sea obligatorio y no se pueda omitir, puedes proporcionar format: true
de esta manera:
get '*pages', to: 'pages#show', format: true
3.12 Redirección
Puedes redirigir cualquier ruta a otra ruta utilizando el ayudante redirect
en tu enrutador:
get '/stories', to: redirect('/articles')
También puedes reutilizar segmentos dinámicos de la coincidencia 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 pueden almacenar en caché este tipo de redirección, lo que hace que la página antigua sea inaccesible. Puedes usar la opción :status
para cambiar el estado de 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 Enrutamiento 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 punto final para una coincidencia:
match '/application.js', to: MyRackApp, via: :all
Siempre que MyRackApp
responda a call
y devuelva una tupla [status, headers, body]
, el enrutador 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 según 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 proc/lambdas son objetos que responden a call
, puedes implementar rutas muy simples (por ejemplo, para comprobaciones de salud) en línea:get '/health', to: ->(env) { [204, {}, ['']] }
Si especificas una aplicación Rack como el punto final para una coincidencia, 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 las solicitudes en la ruta raíz en su lugar, utiliza mount
:
mount AdminApp, at: '/admin'
3.14 Uso de root
Puedes especificar a qué debe dirigir Rails '/'
con el método root
:
root to: 'pages#main'
root 'pages#main' # atajo para lo anterior
Debes colocar la ruta root
en la parte superior del archivo, ya que es la ruta más popular y debe coincidir primero.
NOTA: La ruta root
solo enruta las solicitudes GET
a la acción.
También puedes usar root
dentro de espacios de nombres y alcances. 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 ayudantes 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 cadena URL válida, un Hash válido, un 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 Uso de resolve
El método resolve
permite personalizar la asignación polimórfica de modelos. Por ejemplo:
resource :basket
resolve("Basket") { [:basket] }
<%= form_with model: @basket do |form| %>
<!-- formulario de la cesta -->
<% end %>
Esto generará la URL singular /basket
en lugar de la habitual /baskets/:id
.
4 Personalización de rutas de recursos
Si bien las rutas y ayudantes 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 ayudantes de recursos.
4.1 Especificar un controlador a utilizar
La opción :controller
te permite especificar explícitamente un controlador para usar en el recurso. Por ejemplo:
resources :photos, controller: 'images'
reconocerá las rutas entrantes que comiencen con /photos
pero se dirigirán al controlador Images
:
Verbo HTTP | Ruta | Controlador#Acción | Helper de Ruta Nombrado |
---|---|---|---|
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: Utiliza photos_path
, new_photo_path
, etc. para generar las rutas de este recurso.
Para controladores con nombres de espacio, puedes utilizar la notación de directorio. Por ejemplo:
resources :user_permissions, controller: 'admin/user_permissions'
Esto se dirigirá 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 causar problemas de enrutamiento y dar lugar a una advertencia.
4.2 Especificar Restricciones
Puedes utilizar 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 proporcionada. Por lo tanto, en este caso, el enrutador ya no coincidiría /photos/1
con esta ruta. En cambio, /photos/RR27
coincidiría.
Puedes especificar una restricción única para aplicar a varias rutas utilizando la forma de bloque:
constraints(id: /[A-Z][A-Z][0-9]+/) do
resources :photos
resources :accounts
end
NOTA: Por supuesto, puedes utilizar las restricciones más avanzadas disponibles en las rutas no basadas en recursos en este contexto.
CONSEJO: Por defecto, el parámetro :id
no acepta puntos, esto se debe a que el punto se utiliza como separador para las rutas formateadas. Si necesitas utilizar 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 Nombrados
La opción :as
te permite anular el nombre normal de los helpers de ruta nombrados. Por ejemplo:
resources :photos, as: 'images'
reconocerá las rutas entrantes que comiencen con /photos
y dirigirá las solicitudes al controlador PhotosController
, pero utilizará el valor de la opción :as
para nombrar los helpers.
Verbo HTTP | Ruta | Controlador#Acción | Helper de Ruta Nombrado |
---|---|---|---|
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 reales de las acciones no se cambian con esta opción. Las dos rutas mostradas aún se dirigirían a las acciones new
y edit
.
CONSEJO: Si te encuentras queriendo cambiar esta opción de manera uniforme para todas tus rutas, puedes utilizar un scope, como se muestra a continuación:
scope path_names: { new: 'make' } do
# el resto de tus rutas
end
4.5 Prefijar los Helpers de Ruta Nombrados
Puedes utilizar la opción :as
para prefijar los helpers de ruta nombrados que Rails genera para una ruta. Utiliza esta opción para evitar colisiones de nombres entre rutas que utilizan un ámbito 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 con ámbito resources :photos
, el recurso sin ámbito resources :photos
no tendrá ningún helper de ruta.
Para prefijar un grupo de helpers de ruta, utiliza :as
con scope
:
scope 'admin', as: 'admin' do
resources :photos, :accounts
end
resources :photos, :accounts
Como antes, esto cambia los helpers de recursos con ámbito /admin
a
admin_photos_path
y admin_accounts_path
, y permite que los recursos sin ámbito utilicen photos_path
y accounts_path
.
NOTA: El ámbito namespace
agregará automáticamente los prefijos :as
, :module
y :path
.
4.5.1 Ámbitos paramétricos
Puede agregar un parámetro con nombre a las rutas:
scope ':account_id', as: 'account', constraints: { account_id: /\d+/ } do
resources :articles
end
Esto proporcionará rutas como /1/articles/9
y le permitirá hacer referencia a la parte account_id
de la ruta como params[:account_id]
en controladores, helpers y vistas.
También generará helpers de ruta y URL con el prefijo account_
, a los cuales puede pasar sus 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 ámbito para que solo coincida con cadenas similares a ID. Puede cambiar la restricción según sus 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 Restricción de 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 su aplicación. Puede utilizar las opciones :only
y :except
para ajustar este comportamiento. La opción :only
le indica a Rails que solo cree 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 enrutaría a la acción create
) fallará.
La opción :except
especifica una ruta o lista de rutas que Rails no debe 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 su aplicación tiene muchas rutas RESTful, el uso de :only
y :except
para generar solo las rutas que realmente necesita puede reducir el uso de memoria y acelerar el proceso de enrutamiento.
4.7 Rutas traducidas
Usando scope
, podemos modificar los nombres de las rutas generadas 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 con nombre |
---|---|---|---|
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 Anulación de la forma singular
Si desea anular la forma singular de un recurso, debe agregar reglas adicionales al inflector a través de inflections
:
ActiveSupport::Inflector.inflections do |inflect|
inflect.irregular 'tooth', 'teeth'
end
4.9 Uso de :as
en recursos anidados
La opción :as
anula el nombre generado automáticamente para el recurso en los helpers de ruta anidados. Por ejemplo:
resources :magazines do
resources :ads, as: 'periodical_ads'
end
Esto creará helpers de enrutamiento como magazine_periodical_ads_url
y edit_magazine_periodical_ad_path
.
4.10 Anulación de los parámetros con nombre de la ruta
La opción :param
anula el identificador de recurso predeterminado :id
(nombre del segmento dinámico utilizado para generar las rutas). Puede acceder a ese segmento desde su controlador utilizando 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])
Puede 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 Dividir un archivo de rutas muy grande en varios archivos pequeños
Si trabaja en una aplicación grande con miles de rutas, un único archivo config/routes.rb
puede volverse engorroso y difícil de leer.
Rails ofrece una forma de dividir un archivo routes.rb
gigantesco en varios archivos pequeños utilizando la macro draw
.
Podría tener un archivo de ruta admin.rb
que contenga todas las rutas para el área de administración, otro archivo api.rb
para los 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 (por ejemplo, config/routes/admin.rb
o config/routes/external/admin.rb
).
Puede utilizar el DSL de enrutamiento normal dentro del archivo de enrutamiento admin.rb
, pero no debe rodearlo con el bloque Rails.application.routes.draw
como lo hizo en el archivo principal config/routes.rb
.
5.1 No utilice esta función a menos que realmente la necesite
Tener varios archivos de enrutamiento dificulta la capacidad de descubrimiento y comprensión. Para la mayoría de las aplicaciones, incluso aquellas con cientos 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 dividir las rutas de manera organizada con namespace
y scope
.
6 Inspección y prueba de rutas
Rails ofrece herramientas para inspeccionar y probar sus rutas.
6.1 Listar las rutas existentes
Para obtener una lista completa de las rutas disponibles en su aplicación, visite http://localhost:3000/rails/info/routes en su navegador mientras su servidor se esté ejecutando en el entorno development. También puede ejecutar el comando bin/rails routes
en su terminal para obtener la misma salida.
Ambos métodos listarán todas sus rutas, en el mismo orden en que aparecen en config/routes.rb
. Para cada ruta, verá:
- El nombre de la ruta (si tiene alguno)
- El verbo HTTP utilizado (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 de 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 puede usar la opción --expanded
para activar el modo de formato de tabla expandido.
$ bin/rails routes --expanded
--[ Ruta 1 ]----------------------------------------------------
Prefijo | users
Verbo | GET
URI | /users(.:format)
Controlador#Acción | users#index
--[ Ruta 2 ]----------------------------------------------------
Prefijo |
Verbo | POST
URI | /users(.:format)
Controlador#Acción | users#create
--[ Ruta 3 ]----------------------------------------------------
Prefijo | new_user
Verbo | GET
URI | /users/new(.:format)
Controlador#Acción | users#new
--[ Ruta 4 ]----------------------------------------------------
Prefijo | edit_user
Verbo | GET
URI | /users/:id/edit(.:format)
Controlador#Acción | users#edit
Puede buscar en sus rutas con la opción grep: -g. Esto muestra cualquier ruta que coincida parcialmente con el nombre del método auxiliar 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 desea ver las rutas que se asignan 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á que la salida de bin/rails routes
es mucho más legible si amplía la ventana de su terminal hasta que las líneas de salida no se envuelvan.
6.2 Prueba de rutas
Las rutas deben incluirse en su estrategia de pruebas (como el resto de su aplicación). Rails ofrece tres aserciones incorporadas diseñadas para facilitar las pruebas de rutas:
6.2.1 La aserción assert_generates
assert_generates
afirma que un conjunto particular de opciones genera una ruta particular y se puede utilizar 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 aserción assert_recognizes
assert_recognizes
es el inverso de assert_generates
. Asegura que se reconozca una ruta dada y la enrutará a un lugar específico en su aplicación. Por ejemplo:
assert_recognizes({ controller: 'photos', action: 'show', id: '1' }, '/photos/1')
Puede proporcionar un argumento :method
para especificar el verbo HTTP:
assert_recognizes({ controller: 'photos', action: 'create' }, { path: 'photos', method: :post })
6.2.3 La aserción assert_routing
La aserció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 encuentras algún error tipográfico o factual. Para empezar, puedes leer nuestra contribución a la documentación sección.
También puedes encontrar contenido incompleto o desactualizado. Por favor, añade cualquier documentación faltante para main. Asegúrate de revisar Edge Guides primero para verificar si los problemas ya están resueltos o no en la rama principal. Consulta las Directrices de las Guías de Ruby on Rails para el estilo y las convenciones.
Si por alguna razón encuentras algo que corregir pero no puedes solucionarlo tú mismo, por favor abre un problema.
Y por último, cualquier tipo de discusión sobre la documentación de Ruby on Rails es muy bienvenida en el Foro oficial de Ruby on Rails.