ruby-on-rails - recursos - ruby on rails que es
Enrutamiento de recursos anidados en Rails 3 (5)
¿Ha considerado usar una ruta anidada poco profunda en este caso?
Anidamiento de ruta superficial En ocasiones, los recursos anidados pueden generar URL engorrosas. Una solución a esto es usar el anidamiento de ruta superficial:
resources :products, :shallow => true do
resources :reviews
end
Esto permitirá el reconocimiento de las siguientes rutas:
/products/1 => product_path(1)
/products/1/reviews => product_reviews_index_path(1)
/reviews/2 => reviews_path(2)
Tengo un caso bastante común para las rutas anidadas, me siento como, que se ve algo como esto (en algún tipo de pseudonotación):
''/:username/photos'' => Show photos for User.find_by_username
''/photos'' => Show photos for User.all
En pocas palabras: tengo usuarios. Ellos tienen fotos. Quiero poder mostrar sus fotos en su página. También quiero poder mostrar todas las fotos, independientemente del usuario. Me gustaría mantener mis rutas RESTful y utilizar los métodos de resource
integrados parece ser la forma correcta de hacerlo.
La opción 1 para hacer esto es hacer que PhotosController # index use un condicional para verificar qué parámetros se dan y obtener la lista de fotos y establecer la vista (diferente para las fotos de un usuario que para todas las fotos). Incluso es fácil dirigirlo:
resources :photos, :only => [:index]
scope '':/username'' do
resources :photos
end
Auge. Parecería que Rails estaba configurado para esto. Después de las rutas, sin embargo, las cosas se vuelven más complicadas. Ese retroceso condicional en la acción del índice PhotosController # se está volviendo cada vez más inflado y está haciendo una gran cantidad de degación. A medida que la aplicación crezca y también la cantidad de formas en que quiero mostrar fotos, solo empeorará.
La opción 2 podría ser tener un User :: PhotosController para manejar las fotos de los usuarios, y un PhotosController para manejar mostrando todas las fotos.
resources :photos, :only => [:index]
namespace :user, :path => ''/:username'' do
resources :photos
end
Eso genera las siguientes rutas:
photos GET /photos(.:format) {:action=>"index", :controller=>"photos"}
user_photos GET /:username/photos(.:format) {:action=>"index", :controller=>"user/photos"}
POST /:username/photos(.:format) {:action=>"create", :controller=>"user/photos"}
new_user_photo GET /:username/photos/new(.:format) {:action=>"new", :controller=>"user/photos"}
edit_user_photo GET /:username/photos/:id/edit(.:format) {:action=>"edit", :controller=>"user/photos"}
user_photo GET /:username/photos/:id(.:format) {:action=>"show", :controller=>"user/photos"}
PUT /:username/photos/:id(.:format) {:action=>"update", :controller=>"user/photos"}
DELETE /:username/photos/:id(.:format) {:action=>"destroy", :controller=>"user/photos"}
Esto funciona bastante bien, creo, pero todo está bajo un módulo de Usuario y siento que eso podría terminar causando problemas cuando lo integre con otras cosas.
Preguntas
- ¿Alguien tiene experiencia con algo como esto?
- ¿Alguien puede compartir una mejor manera de manejar esto?
- ¿Alguna ventaja y desventaja adicional a considerar con cualquiera de estas opciones?
Actualización : He seguido implementando la Opción 2 porque se siente más limpio y permite que la lógica de Rails funcione en lugar de anularla. Hasta ahora las cosas van bien, pero también necesitaba cambiar el nombre de mi espacio de nombres a :users
y agregar un :as => :user
para evitar que chocara con mi modelo de User
. También he reemplazado el método to_param
en el modelo de User
para devolver el nombre de usuario. Los ayudantes de ruta aún funcionan de esta manera también.
Aún agradecería mi opinión sobre este método. ¿Estoy haciendo las cosas de la manera esperada, o estoy haciendo un uso indebido de esta funcionalidad?
Hice algo similar a esto en una de mis aplicaciones. Estás en el camino correcto. Lo que hice fue declarar los recursos anidados y crear la consulta utilizando la sintaxis flexible basada en arel de Active Record en Rails 3. En su caso, podría verse algo como esto:
# config/routes.rb
resources :photos, :only => :index
resources :users do
resources :photos
end
# app/controllers/photos_controller.rb
def index
@photos = Photo.scoped
@photos = @photos.by_user(params[:user_id]) if params[:user_id]
# ...
end
La mejor manera de hacerlo depende de la aplicación, pero en mi caso ciertamente es la Opción B. Utilizando rutas con nombres de nombres, puedo usar un módulo para mantener diferentes preocupaciones separadas en diferentes controladores de una manera muy limpia. También estoy usando un controlador específico de espacio de nombre para agregar funcionalidad compartida a todos los controladores en un espacio de nombre particular (agregando, por ejemplo, un before_filter para verificar la autenticación y el permiso para todos los recursos en el espacio de nombres).
Podría definir una ruta separada para obtener las fotos para un usuario así:
get ''(:username)/photos'', :to => ''photos#index''
Pero aconsejaría simplemente usar el recurso anidado que Jimmy publicó anteriormente, ya que es la solución más flexible.
Example::Application.routes.draw do
resources :accounts, :path => '''' do
resources :projects, :path => '''', :except => [:index]
end
end
Obtuve el ejemplo de: http://jasoncodes.com/posts/rails-3-nested-resource-slugs
Acabo de aplicar eso en mi proyecto actual.