ruby on rails - links - Rails-link_to, rutas y recursos anidados
rails link_to block (4)
Como mi comprensión sobre los recursos anidados, en los rieles de borde, no debería
link_to ''User posts'', @user.posts
apunta a
/users/:id/posts
?
El archivo routes.rb contiene
map.resources :users, :has_many => :posts
Si este no es el comportamiento predeterminado, ¿se puede lograr haciendo otra cosa?
Esto debería funcionar:
link_to "User Posts", user_posts_path(@user)
para más detalles visite:
En la misma línea que Rishav:
link_to "User Posts", [@user, :posts]
Aquí hay una explicación de mi blog .
Muy pronto en Rails, escribirías rutas como esta:
redirect_to :controller => "posts", :action => "show", :id => @post.id
Lo que esto haría es redirigir diligentemente a la acción de show
dentro de PostsController
y pasar el parámetro id
con un valor de lo que sea que @post.id
Respuesta típica 302.
Luego apareció Rails 1.2 y le permitió usar ayudantes de enrutamiento, como este:
redirect_to post_path(@post)
Y la gente se regocijó.
Esto haría efectivamente lo mismo. post_path
aquí construiría una ruta usando el objeto @post
que se vería como /posts/1
y luego redirect_to
devolvería una respuesta 302 a esa ruta y el navegador la seguiría.
Luego, las versiones posteriores (no recuerdo cuál) permitieron una sintaxis como esta:
redirect_to @post
Y la gente se regocijó por segunda vez.
Magia, pero no realmente
Cualquier tecnología suficientemente avanzada es indistinguible de la magia.
Si bien esto parece mágico, no lo es. Lo que está haciendo esto es muy, muy claro. El método redirect_to
, al igual que sus primos link_to
y form_for
all, usa un método común para crear URL, llamado url_for
. El método url_for
toma muchas variedades diferentes de objetos, como cadenas, hashes o incluso instancias de modelos, como en el ejemplo anterior.
Lo que hace con estos objetos entonces, es bastante limpio. En el caso de la llamada redirect_to @post
anterior, inspecciona el objeto @post
, ve que es un objeto de la clase Post
(suponemos, de todos modos) y verifica si ese objeto se ha conservado en una base de datos en alguna parte llamando persisted?
en eso.
Por "persistido", quiero decir que un objeto Ruby tiene un registro coincidente en la base de datos en alguna parte. persisted?
método en Active Record se implementa de esta manera:
def persisted?
!(new_record? || destroyed?)
end
Si el objeto no se creó a través de una llamada como Model.new
entonces no será un nuevo registro, y si no se ha invocado el método de destroy
, tampoco se destruirá. Si ambos casos son verdaderos, entonces eso hace que el objeto se haya conservado en la base de datos en forma de registro.
Si se ha conservado, entonces url_for
sabe que este objeto se puede encontrar en alguna parte, y que el lugar en el que se puede encontrar es muy probablemente con un método llamado post_path
. Por lo tanto, llama a este método y to_param
valor to_param
de este objeto, que generalmente es el id
.
En resumen, efectivamente está haciendo esto:
#{@post.class.downcase}_path(@post.to_param)
Que resulta ser esto:
post_path(1)
Y cuando se llame a ese método, obtendrás esta pequeña cadena:
"/posts/1"
¡Encantador!
Esto se llama enrutamiento polimórfico . Puede pasar un objeto a métodos como redirect_to
, link_to
y form_for
e intentará calcular la URL correcta de qué usar.
La forma de form_for
Ahora, cuando estás codificando Rails, puedes haber usado form_for
como este hace mucho tiempo:
<% form_for @post, :url => { :controller => "posts", :action => "create" } do |f| %>
Por supuesto, con los avances en Rails puedes simplificarlo a esto:
<% form_for @post, :url => posts_path do |f| %>
Debido a que el formulario va a tener un método POST
HTTP por defecto y, por lo tanto, una solicitud a posts_path
irá a la acción create
de PostsController
, en lugar de a la acción index
, que es lo que resultaría si fuera una solicitud GET
.
Pero ¿por qué detenerse allí? ¿Por qué no solo escribir esto?
<%= form_for @post do |f| %>
Personalmente, no veo ninguna razón para no ... si es algo tan simple como esto. El método form_for
usa url_for
debajo, al igual que redirect_to
para determinar dónde debe ir el formulario. Sabe que el objeto @post
es de la clase Post
(de nuevo, suponemos) y comprueba si el objeto persiste. Si es así, usará post_path(@post)
. Si no es así, entonces posts_path
.
El método form_for
verifica si el objeto pasado también es persistente, y si lo es, se configurará por defecto como un método PUT
HTTP, de lo contrario un POST
.
Así es como form_for
puede ser lo suficientemente flexible como para tener una sintaxis idéntica en una vista new
y de edit
. En la actualidad, cada vez es más común que la gente coloque toda su form_for
tags en un solo parcial e incluirlo en las páginas new
y de edit
.
Una forma más compleja
Entonces form_for
es bastante simple para cuando pasas por un objeto normal, pero ¿qué pasa si pasas una serie de objetos? Así, por ejemplo:
<%= form_for [@post, @comment] do |f| %>
Bueno, tanto url_for
como form_for
te han cubierto allí.
El método url_for
detecta que se trata de una matriz y separa cada parte y las inspecciona individualmente. Primero, ¿qué es esto de @post
? Bueno, en este caso supongamos que es una instancia de Post
que se conserva y tiene el id de 1. En segundo lugar, ¿qué es este objeto @comment
? Es una instancia de Comment
que aún no se ha conservado en la base de datos.
Lo que url_for
hará aquí es construir el método de ayuda de URL pieza por pieza colocando cada parte en una matriz, uniéndola en un método de enrutamiento y luego llamando a ese método de enrutamiento con los argumentos necesarios.
En primer lugar, sabe que el objeto @post
es de la clase Post
y se conserva, por lo tanto, el asistente de URL comenzará con la post
. En segundo lugar, sabe que el objeto @comment
la clase Comment
y no se conserva y, por lo tanto, los comments
seguirán post
en la compilación de helper de URL. Las partes que url_for
ahora conocen son [:post, :comments]
url_for
[:post, :comments]
.
El método url_for
combina estas partes individuales con un guión bajo, de modo que se convierte en post_comments
y luego agrega _path
al final de eso, lo que da como resultado la post_comments_path
. Luego pasa solo los objetos persistentes a la llamada a ese método, lo que da como resultado una llamada como esta:
post_comments_path(@post)
Llamar a ese método da como resultado esto:
"/posts/1/comments"
¿Mejor parte? form_for
aún sabrá usar POST
si el objeto @comment
no es un objeto persistente, y PUT
si lo es. Una buena cosa para recordar es que form_for
es siempre para el último objeto especificado en la matriz. Los objetos anteriores son solo su anidación, nada más.
url_for
más objetos se agreguen, más veces url_for
hará las yardas duras y construirá la ruta de salida ... aunque le recomiendo que la mantenga en solo dos partes.
Una forma simbólica
Ahora que hemos cubierto el uso de una matriz que contiene objetos para form_for
, echemos un vistazo a otro uso común. Una matriz que contiene al menos un objeto Symbol, como este:
<%= form_for [:admin, @post, @comment] do |f| %>
Lo que el método url_for
hace aquí es muy simple. Ve que hay un Symbol
y lo toma tal como es. La primera parte de la url
simplemente será la misma que el símbolo: admin
. La URL que url_for
conoce en este momento es solo [:admin]
.
Luego url_for
recorre las partes restantes de la matriz. En este caso, supongamos que tanto @post
como @comment
son persistentes y que tienen los ids de 1 y 2 respectivamente. Las mismas clases que antes. url_for
luego agrega una post
a la URL que está creando y también comment
, lo que da como resultado [:admin, :post, :comment]
url_for
post
url_for
[:admin, :post, :comment]
.
A continuación, se produce la unión, lo que da como resultado un método de admin_post_comment_path
, y dado que tanto @post
como @comment
se conservan aquí, se transfieren, lo que da como resultado esta llamada a método:
admin_post_comment_path(@post, @comment)
Que (por lo general) se convierte en esta ruta:
/admin/posts/1/comments/2
Puede usar la forma de matriz de enrutamiento polimórfico con los métodos redirect_to
, link_to
y form_for
. Probablemente haya otros métodos que no recuerdo ahora mismo que puedan hacerlo ... generalmente, cualquier cosa en Rails normalmente tomaría una URL.
No es necesario crear sus URL en ninguna versión de Rails mayor que 2 utilizando hashes; eso es bastante vieja escuela.
En cambio, experimente con su nuevo conocimiento de enrutamiento polimórfico y úselo de la mejor manera posible.
Esta es la forma de vincular a un recurso anidado en los últimos Rails:
link_to ''Destroy Comment'', post_comment_path (comment.post, comment)
Nota: Esto está en un parcial así que no hay un @
.
link_to
usa url_for
which usa polymorphic_url
.
polymorphic_url
:
construye el método auxiliar , utilizando el nombre de clase de los objetos de registro activos
llama al ayudante con los objetos de registro activos como argumentos
Por lo tanto, como otros dijeron, debes usar:
link_to ''User Posts'', [@user, :posts]
para lo cual el camino es:
user_posts_path(@user)
^^^^ ^^^^^ ^^^^^
1 2 3
- clase de
@user
porque es un registro activo - convertir a cadena porque símbolo
- agregar como argumento de llamada porque el registro activo
Eso construye el buen método de ayuda.