shallow rails namespace examples concern ruby-on-rails api rest ruby-on-rails-4 nested-routes

ruby-on-rails - namespace - routes rails examples



Rails 4[Mejores prácticas] Recursos anidados y superficiales: verdadero (5)

Aunque puede complicar las cosas si solo lo necesita para algunos modelos, podría ser bueno consultar Recursos heredados (IR). Es compatible con la anidación de recursos, polimórficos pertenece a, y puede generar automáticamente los métodos de ruta y url auxiliar más cortos que está buscando. La razón por la que ya no escuchas mucho sobre IR es que su autor original y algunos otros desarrolladores lo han abandonado por las complicaciones que surgen cuando intentas extender tus controladores. Sin embargo, todavía tiene una comunidad, y hemos tratado de ampliarlo un poco más y centrarnos más en la facilidad de las extensiones de los controladores con Irie .

La "mejor práctica" en Rails depende de con quién hables.

Rails ha sido tradicionalmente dirigido principalmente a CRUD básico para recursos (no anidados). Sí, permite recuperar y actualizar recursos anidados, pero se supone que esto no ocurre con la misma frecuencia.

Sin embargo, lo que ha estado surgiendo en la comunidad de Rails es el enfoque ActiveModel::Serializers / json-api . En esto, generalmente no se produce más de un nivel de anidación de recursos, y el recurso anidado es una lista de enlaces o una versión pequeña de los recursos secundarios que se puede cargar en un lado y que luego puede consultar en ese recurso para obtener más datos. Esto también ha sido adoptado por Ember / Ember Data .

También hay roar y una serie de otros proyectos que apuntan a implementar algo más cercano a su comprensión de algo cercano a la visión original de Roy Fielding de REST.

Creo que solo depende de lo que es tu diseño y lo que necesitas. Si la eficiencia es un objetivo, entonces el tiempo adicional para desarrollarse para ser explícito y anidar más puede dar resultado. Actualmente usamos AngularJS e Irie , por ejemplo. Pero a cada cual lo suyo.

Como en la última nota, asegúrese de evitar n + 1 búsquedas mediante el uso de includes(...) (o similar) en sus consultas, de lo contrario, toda esa anidación podría afectarle en el rendimiento.

La siguiente publicación se basa en Rails 4.

En realidad, estoy buscando buenas prácticas recomendadas sobre los múltiples recursos anidados (más de 1) y la opción superficial: verdadera.

Primero en mis rutas, había esto:

resources :projects do resources :collections end

Las rutas asociadas son:

project_collections GET /projects/:project_id/collections(.:format) collections#index POST /projects/:project_id/collections(.:format) collections#create new_project_collection GET /projects/:project_id/collections/new(.:format) collections#new edit_project_collection GET /projects/:project_id/collections/:id/edit(.:format) collections#edit project_collection GET /projects/:project_id/collections/:id(.:format) collections#show PATCH /projects/:project_id/collections/:id(.:format) collections#update PUT /projects/:project_id/collections/:id(.:format) collections#update DELETE /projects/:project_id/collections/:id(.:format) collections#destroy projects GET /projects(.:format) projects#index POST /projects(.:format) projects#create new_project GET /projects/new(.:format) projects#new edit_project GET /projects/:id/edit(.:format) projects#edit project GET /projects/:id(.:format) projects#show PATCH /projects/:id(.:format) projects#update PUT /projects/:id(.:format) projects#update DELETE /projects/:id(.:format) projects#destroy

Leí en la documentación sobre la limitación de recursos anidados:

Los recursos nunca se deben anidar más de 1 nivel de profundidad.

Fuente: http://guides.rubyonrails.org/routing.html#limits-to-nesting Ok. Entonces, como decía la documentación, voy a usar "superficial" en mis rutas.

shallow do resources :projects do resources :collections end end

Las rutas asociadas son:

project_collections GET /projects/:project_id/collections(.:format) collections#index POST /projects/:project_id/collections(.:format) collections#create new_project_collection GET /projects/:project_id/collections/new(.:format) collections#new edit_collection GET /collections/:id/edit(.:format) collections#edit collection GET /collections/:id(.:format) collections#show PATCH /collections/:id(.:format) collections#update PUT /collections/:id(.:format) collections#update DELETE /collections/:id(.:format) collections#destroy projects GET /projects(.:format) projects#index POST /projects(.:format) projects#create new_project GET /projects/new(.:format) projects#new edit_project GET /projects/:id/edit(.:format) projects#edit project GET /projects/:id(.:format) projects#show PATCH /projects/:id(.:format) projects#update PUT /projects/:id(.:format) projects#update DELETE /projects/:id(.:format) projects#destroy

La principal diferencia que veo es el "show" de colecciones, este:

collection GET /collections/:id(.:format) collections#show

Entonces, si estoy en lo cierto, el enlace para mostrar la acción de una colección es:

<%= link_to ''Show", collection_path(collection)%>

y debería devolver algo como esto: " http://example.com/collections/1 "

PERO ! 2 cosas :

  • Esto no está funcionando. Me aparece en su lugar " http://example.com/projects/1 ". WTF?
  • Incluso si funcionaba, en realidad es bastante malo porque pierdo el REST básico que dice "La colección es hija del proyecto, luego la url debe ser" localhost / project / 1 / collections / 1 "

No entiendo cuál es el interés superficial si se quiere perder la gran ventaja de las acciones de Descanso. ¿Cuál es el interés? ¿Y cuál es el interés de perder la acción "Mostrar"? Ya publiqué esto en SO, pero el único comentario que recibí fue "Es algo normal". WTF? ¿En qué se trata de un comportamiento normal para "eliminar" una acción del resto API?

Reproduje el problema en un proyecto neutral, para asegurarme de que no estaba haciendo algo mal, y ocurrió el mismo problema. Entonces, sí, puede ser conveniente para los ayudantes usar poco profundo, pero NO ES PARA EL resto conveniente, se pierde todo el interés de "una colección está anidada en un proyecto, así que esto se refleja en la URL".

No sé si hay otra forma de hacerlo, es cierto que poco profundo permite más flexibilidad sobre los ayudantes, pero es falso que sea compatible con el resto. Por lo tanto, ¿hay alguna posibilidad de que funcionen los "ayudantes" (es bastante sorprendente tener "anidado3_ruta (recopilación)" en lugar de "anidado1_invertido2_nestado3 ([anidado1, desviado2.numerado3, anidado1, desviado2, anidado1])" y manteniendo el " url parte "y seguir teniendo" anidado1 / 123 / anidado2 / 456 / anidado3 / 789?

Gracias !


Como hay una id para una Collection , es redundante anidar la ruta bajo el Proyecto a excepción del index y create acciones.

Hay una regla sobre URL donde se supone que solo hay una URL para GET (con 200) un recurso dado, si hay otras URL debe redirigir a ella. Por lo tanto, es posible que tenga una ruta /projects/:id/collections/:collection_id que redirige a /collections/:collection_id .

En su caso, una Colección está ligada a un Proyecto, pero eso no es necesariamente cierto para todas las relaciones. Una vez que tenga el :collection_id , no necesita hacer referencia al contexto del Project para acceder a él.


No creo que Rails ofrezca ninguna forma integrada para que las URL utilicen la jerarquía completa (por ejemplo, /projects/1/collections/2 ), sino que también tengan los ayudantes de acceso directo (por ejemplo, collection_path lugar de project_collection_path ).

Si realmente quieres hacer esto, puedes desplegar tu propio ayudante personalizado de la siguiente manera:

def collection_path(collection) # every collection record should have a reference to its parent project project_collection_path(collection.project, collection) end

Pero eso sería bastante complicado de hacer manualmente para cada recurso.

Creo que la idea detrás del uso de rutas shallow se resume mejor en la documentación:

Una forma de evitar el anidamiento profundo (como se recomendó anteriormente) es generar las acciones de recopilación con el alcance del padre, a fin de obtener una idea de la jerarquía, pero no anidar las acciones del miembro. En otras palabras, solo crear rutas con la cantidad mínima de información para identificar de manera única el recurso

fuente: http://guides.rubyonrails.org/routing.html#shallow-nesting

Por lo tanto, aunque esto puede no ser compatible con REST (como dices), no estás perdiendo ninguna información porque cada recurso puede identificarse de manera única y puedes volver a subir por la jerarquía suponiendo que tus asociaciones estén configuradas correctamente.


Niveles

La idea de que solo debe usar 1 nivel en sus recursos anidados solo es realmente aplicable al diseño del sistema:

El asistente de ruta correspondiente sería publisher_magazine_photo_url, lo que requiere que especifique objetos en los tres niveles. De hecho, esta situación es tan confusa que un artículo popular de Jamis Buck propone una regla general para un buen diseño de Rails:

Creo que Rails aún puede manejar múltiples niveles, aunque no se recomienda desde una perspectiva de usabilidad

Superficial

Aunque he visto algo superficial antes, nunca lo he usado

Al mirar la documentation , parece superficial tiene un propósito bastante oscuro (en realidad no sé por qué está allí). El problema es que no está pasando públicamente el parámetro post_id a su controlador, lo que le deja cargar la collection sin un parámetro importante.

Me gustaría suponer (y esto es solo especulación), que el objetivo es pasar el parámetro que necesita detrás de las escenas, por lo que se queda con una ruta pública "superficial":

#config/routes.rb resources :projects do resources :collections, shallow: true end

Me imagino que obtendrías un URL helper como este:

collection_path(project.id, collection.id)

Esto saldría como domain.com/collection/2


A partir de esta respuesta , parece que las rutas poco profundas desafían la convención de Rails, IMO.

Creo que no necesitarías el asistente de ruta explícito para una ruta de muestra. El link_to helper debería poder inferirlo del método to_param del objeto.

#your helper becomes link_to "show", collection

Si utiliza el asistente como lo hizo anteriormente, probablemente también deba pasar la identificación anidada del recurso principal al ayudante.

link_to "show", collection_path([project, collection])