Convenciones básicas de enrutamiento
Echemos un vistazo a nuestras rutas tal como están ahora, utilizando rake routes
:
$ rake routes Prefix Verb URI Pattern Controller#Action list_posts GET /list_posts(.:format) application#list_posts GET /show_post/:id(.:format) application#show_post new_post GET /new_post(.:format) application#new_post create_post POST /create_post(.:format) application#create_post GET /edit_post/:id(.:format) application#edit_post POST /update_post/:id(.:format) application#update_post POST /delete_post/:id(.:format) application#delete_post POST /create_comment_for_post/:post_id(.:format) application#create_comment POST /list_posts/:post_id/delete_comment/:comment_id(.:format) application#delete_comment list_comments GET /list_comments(.:format) application#list_comments
Una de las ideas clave para las convenciones de Rails es que las aplicaciones centradas en datos (o aplicaciones crudas) tienden a tener formas muy similares para permitir que los usuarios interactúen con la aplicación, que son:
- una página para ver una lista de algo
- ver algo
- mostrar un formulario para crear una nueva instancia de algo
- crear realmente algo
- mostrar un formulario para editar una instancia de algo
- actualizar realmente algo
- eliminar algo
Esos siete «patrones de interacción» son tan comunes que Rails proporciona un conjunto sólido de convenciones, desde enrutamiento a controladores, vistas y formularios, para ayudar a simplificar esos flujos de trabajo. Vamos a centrarnos en la parte de enrutamiento ahora.
Para el enrutamiento, la convención es que en lugar de tener que idear los patrones de URL, Rails recomienda que estructuremos las URL y las acciones del controlador correspondientes de la siguiente manera:
Flujo de trabajo | VERBO HTTP | RUTA | Acción del controlador |
---|---|---|---|
Mostrar una lista de publicaciones | OBTENER | / publicaciones | índice de publicaciones |
Mostrar una publicación | OBTENER | /publicaciones/:id | posts#show |
Mostrar la página para crear post | GET | /posts/nuevo | posts#nuevo |
Crear un puesto de | POST | /posts | posts#crear |
Mostrar la página a editar un post | GET | /posts/:id/editar | posts#editar |
Actualización de un post | PONER/PATCH | /posts/:id | posts#actualización |
Borrar un post | ELIMINAR | /posts/:id | mensajes # destruir |
Podemos cambiar la parte post
de nuestro enrutamiento actual para seguir esta convención:
# posts GET /list_posts -> GET /posts posts#index GET /show_post/:id -> GET /posts/:id posts#show GET /new_post -> GET /posts/new posts#new POST /create_post -> POST /posts posts#create GET /edit_post/:id -> GET /posts/:id/edit posts#edit POST /update_post/:id -> PUT/PATCH /posts/:id posts#update POST /delete_post/:id -> DELETE /posts/:id posts#destroy
Y en el archivo routes.rb
,
Rails.application.routes.draw do ### posts ### get '/posts' => 'posts#index' get '/posts/new' => 'posts#new' get '/posts/:id' => 'posts#show' post '/posts' => 'posts#create' get '/posts/:id/edit' => 'posts#edit' patch '/posts/:id' => 'posts#update' put '/posts/:id' => 'posts#update' delete '/posts/:id' => 'posts#destroy' # comments later.. ... end
Observe que con este nuevo patrón, hay muchos menos verbos en la propia URL, pero confiamos en los verbos HTTP(GET
/POST
/PUT
/PATCH
/DELETE
) para proporcionar la semántica para los mismos patrones de URL, por ejemplo /posts/:id
.
Tenga en cuenta que PUT
se había utilizado para actualizar recursos hasta hace poco, cuando PATCH
se determinó que era una mejor coincidencia semántica para esta acción. Desde entonces, Rails se ha movido a preferir PATCH
, pero permitiendo ambos verbos para actualizaciones.
Otro cambio que veremos más adelante es que enrutaremos todas las URL relacionadas con publicaciones a PostsController
en lugar de manejar todo en ApplicationController
. Los nombres de acción de PostController
- nuevo
- índice
- mostrar
- crear
- editar
- actualizar
- destruir
también son convenciones correspondientes a la interacción 7 patrones.
Este es el conjunto de convenciones más sólido que Rails le impone como desarrollador de aplicaciones. Le pediremos que haga un esfuerzo para memorizarlo. Revisaremos esto muchas veces a lo largo del libro para ayudarlo a hacer eso también.
Enrutamiento para Múltiples Recursos
A menudo necesitamos tener múltiples recursos presentes en la URL. Por ejemplo, para nuestra aplicación de blog, siempre que necesitemos tener una ruta para crear un comentario, es muy importante que sepamos en qué publicación se crea este comentario.
actualmente estamos haciendo esto:
post 'create_comment_for_post/:post_id' => 'application#create_comment'
La convención Rails de una URL con múltiples recursos asociados es comenzar con el recurso » conteniendo «hasta el recurso» más interno». Por ejemplo, nuestras rutas para comentarios cambiarían a:
post '/posts/:id/comments' => 'comments#create' delete '/posts/:post_id/comments/:id' => 'comments#destroy' get '/comments' => 'comments#index'
La semántica de esas URL representa: «Crear un comentario en una publicación específica» y «eliminar un comentario en una publicación específica». La última ruta, «mostrar todos los comentarios en el sistema», no necesita estar» delimitada «bajo una publicación, por lo que la URL no tiene que aparecer con»/posts».
Si necesitamos tener múltiples recursos en la URL con sus ID, la convención es tal que el último recurso usará el marcador de posición :id
y todo el resto será :resource_id
, como :post_id
.
Restful
REST significa «Transferencia de Estado de representación». Es un estilo de arquitectura de software y una guía para crear servicios web escalables. REST, como una forma de estructurar las aplicaciones web, tiene muchas facetas, pero veamos cómo se aplica a la interfaz que usamos para interactuar con las aplicaciones web, las URL.
Para ver cómo REST simplifica la semántica de las URL, veamos un ejemplo. Digamos que estamos construyendo un servicio de pedidos de pizza en línea. Una implementación ingenua de las interfaces del servicio (URLs) sería:
/check_order?order_id=2 /place_new_order /pizza_details?type=1 /pay_for_my_order?order_id=12 /cancel_order?order_id=3 /expedite_order?order_id=13
Un diseño de interfaz reparador se vería así:
GET /orders/2 POST /orders GET /pizzas/1 POST /orders/12/payments DELETE /orders/3 POST /orders/13/expeditions
Puede ver que las interfaces RESTful se centran en «sustantivos» o «recursos», eliminando «verbos» de las interfaces, pero confiando en los verbos HTTP estandarizados(GET
/POST
/PUT
/DELETE
) proporcionar semántica de CRUD para las acciones. Verbos como check
, place
, cancel
se asignan directamente a verbos HTTP de GET
para recuperar, POST
para crear y DELETE
para destruir el recurso order
. pay
y expedite
se estructuran como creación (HTTP POST) de sub recursos de payments
y expeditions
en recursos orders
.
Interfaces RESTful patrones de interacción de aplicaciones web estandarizados para que sean más fáciles de entender y de programar. Debido a que las interfaces se centran en la manipulación de recursos, las respuestas son mucho más predecibles. Una analogía de cómo el patrón de arquitectura RESTful simplifica la interacción con los servicios web sería cómo la base de datos Relacional y el lenguaje SQL simplifican el almacenamiento de datos. Antes de la Base de datos Relacional y SQL, los datos se almacenaban normalmente en sistemas propietarios con una lógica específica para interactuar con ellos, lo que significaba que en cada proyecto tendría que aprender un conjunto diferente de instrucciones para interactuar con los datos. Las bases de datos relacionales y SQL dieron una estructura de datos común (registros de datos como filas y columnas almacenadas en tablas) y un conjunto de interfaces comunes: cuatro verbos simples de SELECT
, INSERT
, UPDATE
y DELETE
que puede admitir todo tipo de aplicaciones.
La adopción de una interfaz RESTful para su aplicación web también optimizará su aplicación para alinearla con la forma en que se almacenan los datos del backend en las bases de datos, y facilita el desarrollo. Lo veremos en los siguientes capítulos.
Notación de recursos
Hemos hablado sobre las convenciones de enrutamiento de Rails y los patrones de URL RESTful. Ahora nuestro archivo routes.rb
se vería como el siguiente:
### config/routes.rb ### Rails.application.routes.draw do ### posts ### get '/posts' => 'posts#index' get '/posts/new' => 'posts#new' get '/posts/:id' => 'posts#show' post '/posts' => 'posts#create' get '/posts/:id/edit' => 'posts#edit' patch '/posts/:id' => 'posts#update' put '/posts/:id' => 'posts#update' delete '/posts/:id' => 'posts#destroy' ### comments ### get '/comments' => 'comments#index' post '/posts/:id/comments' => 'comments#create' delete '/posts/:post_id/comments/:id' => 'comments#destroy' end
De hecho, las rutas como las que tenemos en la sección posts
son muy comunes, por lo que Rails proporciona una notación resources
especial que ayuda a generarlas para usted.
Podemos simplemente hacer:
resources :posts
Esta línea generará automáticamente las 8 líneas que teníamos antes. Tenga en cuenta que para la acción update
, Rails permite verbos PUT
y PATCH
, por razones de compatibilidad.
Puede ejecutar bundle exec rake routes
en su entorno de línea de comandos para verificar que genera exactamente el mismo conjunto de rutas.
Tenga en cuenta que esta sola línea generará 8 rutas. En nuestro caso, necesitamos todas las rutas aquí, pero si solo necesita un subconjunto de las rutas, puede definirlas de manera más explícita como:
resources :posts, only:
Esta línea de arriba solo generaría 3 rutas para usted: escriba bundle exec rake routes
para comprobarlo.
Recursos anidados
Rails también nos permite anidar recursos para crear patrones de URL con múltiples recursos, consulte a continuación:
### config/routes.rb ### Rails.application.routes.draw do resources :posts do resources :comments, only: end resources :comments, only: :index end
Ejecute bundle exec rake routes
y vea la salida, debería ser la misma que teníamos antes.
Ayudantes de ruta
Cuando ejecute bundle exec rake routes
, observe la columna Prefix
para algunas de estas rutas. Estos están aquí para ayudarnos a saber cómo usar los ayudantes de caminos proporcionados por Rails para nuestras rutas. Podemos usar estos prefijos seguidos de _path
en nuestros controladores y vistas para construir rutas fácilmente.
Por ejemplo:
posts_path # => '/posts' post_id = 123 post_comments_path(post_id) # => '/posts/123/comments'
¿Cuál es la ventaja de usar ayudantes de URL, en lugar de codificar las rutas como /posts/123/comments
directamente en su código? (por ejemplo, en la acción del controlador?) La razón por la que desea usar ayudantes de ruta es que si desea cambiar los patrones de URL en su aplicación, es mucho más fácil usar los ayudantes de URL para devolver una ruta diferente , veamos un ejemplo:
get '/register', to: 'users#new', as: 'register'
Cuando agregamos la cláusula » as » a esta ruta, si ejecuta bundle exec rake routes
, verá la columna Prefix
con register
, y puede usar register_path
para obtener /register
la ruta. Ahora, si queremos cambiar la ruta a /login
, todo lo que tenemos que hacer es:
get '/login', to: 'users#new', as: 'register'
Ahora nuestro register_path
nos da /login
. No tenemos que cambiar nuestro código en la aplicación Rails en absoluto.
Más convenciones de enrutamiento
Antes de continuar, echemos un vistazo rápido a un par de variaciones de lo que ya hemos visto, así como algunas otras características disponibles para nosotros en el enrutamiento de Rails:
### config/routes.rb ### Rails.application.routes.draw do # pointing our homepage (root path) to posts#index root to: 'posts#index' # `match` & `via:` allow us to define one route and use several HTTP verbs # `as:` lets us define the name of the route prefix match '/authors/:id' => 'authors#update', via: , as: :update_author # update_author PUT|PATCH /authors/:id(.:format) authors#update resources :posts do # define extra params to pass for requests to a route get 'popular', on: :collection, action: :index, popular: true # popular_posts GET /posts/popular(.:format) posts#index {:popular=>true} get 'preview', on: :member # ... end # we can even use routes to redirect get '/home', to: redirect('/') end
Vamos a desglosar todas las características enumeradas anteriormente de una en una.
-
root:
root
se usa para especificar qué acción se asigna a «/ » (la URL de nivel superior de nuestro sitio que no tiene ruta).La URL raíz de su sitio web/aplicación es la más utilizada, debido a estoroot
debe especificarse en la parte superior del archivo de rutas. -
partido + vía:
match
se usa para hacer coincidir patrones de URL con una o más rutas. También podemos especificar qué verbo HTTP se puede usar para emparejar con una URL con este patrón. Hacemos esto pasando un hash al métodomatch
. La clave para este hash esvia
, y el valor es una matriz de verbos HTTP.match
es una forma de propósito más general de algunos métodos de enrutamiento HTTP más utilizados, comoget
,post
ydelete
. Puede tomar todas las mismas opciones que esos métodos, pero, en comparación con esos métodos, da un poco más de flexibilidad.
Por ejemplo, al usarmatch
podemos especificar una URL que coincida con dos rutas diferentes, cada una correspondiente a dos verbos HTTP diferentes. Normalmente, hacer esto requeriría dos comandos, en lugar de uno. Podemos ver esto en nuestro ejemplo anterior, donde coincidimos el patrón de URL'/authors/:id'
con la acción'authors#update'
. Luego especificamos qué verbos HTTP se pueden usar para emitir la solicitud de esa URL convia:
. Especifique siempre un método HTTP cuando usematch
, no hacerlo puede tener implicaciones negativas en la seguridad de su aplicación.
match
presenta otra opción para enrutar a ciertas acciones en Rails. En general, es mejor seguir los métodosHttpHelpers
más utilizados, comoget
ypost
. -
as: Mencionamos un poco antes que la opción
as:
se puede usar con nuestra declaración de ruta para cambiar el prefijo de nuestros ayudantes de URL. Esto se puede usar de varias maneras. Podemos usaras:
para que nuestros ayudantes de URL coincidan mejor con las URL personalizadas. Otro uso es cambiar el ayudante de ruta de URL actual por algo más intuitivo o algo que coincida mejor con los recursos de una aplicación. -
ruta de recolección: Vea cómo anidamos nuestra ruta
/popular
en el recursoposts
. Luego usamoson: :collection
para especificar en qué parte de un recurso anidamos esta ruta. Tenemos muchos posts por lo que se considera una colección. Al especificaron: :collection
estamos diciendo, » Haga coincidir una URL con la ruta/posts/popular
.»Si no agregamoson: :collection
, Rails asumirá que esta ruta corresponde a otro recurso asociado a un solo miembro de nuestra colección de publicaciones. En ese caso, nuestra ruta se convertiría en/posts/:id/popular
. También podemos especificar varias rutas de colección utilizando un formato de bloque.
collection do get 'popular' end
- pasar un parámetro adicional: Podemos especificar un parámetro predeterminado que siempre se pasa con nuestro hash
params
cuando coincidimos con ciertas URL. Hay dos formas de especificar esto; una es la misma forma en que lo hacemos anteriormente:
get 'popular', on: :collection, action: :index, popular: true
popular: true
se pasará a nuestra acción con la que coincida la ruta popular a través del hash params
. Tendrá una clave de :popular
y un valor de true
. También podemos usar una sintaxis más explícita pasando un hash a nuestro método de ruta get
, donde la clave es defaults:
y el valor es otro hash que contiene el nombre del parámetro que queremos pasar a nuestra acción.
get 'popular', on: :collection, action: :index, defaults: { popular: true}
-
ruta de miembro: Podemos usar
on: member
para especificar que nuestra ruta coincide con un miembro de una colección. Si usamos esto, el segmento dinámico se mostrará como:id
. También se creará un ayudante de URL comopreview_post
. Al especificar esta ruta conon: member
, le estamos diciendo a Rails que este es un miembro de este recurso en particular. Que no es solo otro recurso anidado en posts, sino más estrechamente vinculado o relacionado con nuestros posts en esta aplicación. Se pueden definir varias rutas de miembros utilizando un formato de bloque; este formato utiliza la misma sintaxis que el formato de bloque para definir varias rutas de colección, simplemente reemplacecollection
pormember
. -
redirección: Hay otro concepto del que hablar que se muestra en nuestro ejemplo anterior, y es la redirección. Rails nos da la capacidad de redirigir de una ruta a otra mediante el uso de un ayudante de redirección junto con una ruta.
get '/home', to: redirect('/')
. Si alguien intenta acceder a la ruta/home
, se redireccionará inmediatamente a la ruta raíz/
. Esto no está restringido a una sola ruta de URL, por supuesto; también podríamos tener algo como esto:get '/home', to: redirect('/travel')
.
Revisión
Las rutas de rails se colocan en la parte delantera de una aplicación. Una ruta interpreta una solicitud HTTP entrante y:
- hace coincidir una solicitud con una acción del controlador basada en la combinación de un verbo HTTP y el patrón de URL de solicitud
- captura datos en la URL que estará disponible en
params
en acciones del controlador - Rails alienta a los desarrolladores a usar patrones de URL REST al configurar rutas, con conceptualización de la manipulación de recursos con verbos HTTP.
- Puede usar la macro
resources
para generar rutas RESTful muy rápidamente.