ror rails links link_to link how _blank ruby-on-rails routes nested-resources

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?



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 :

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

  1. clase de @user porque es un registro activo
  2. convertir a cadena porque símbolo
  3. agregar como argumento de llamada porque el registro activo

Eso construye el buen método de ayuda.