14

Digamos que mi aplicación tiene dos modelos, Foo y Bar.Rails Espacio de nombres frente a recurso anidado

Foo opcionalmente pertenece a Bar.

Ahora puedo mirar un solo Foo, o buscar un Foo en particular, y el FoosController maneja todo eso. Mis URL son como: foos/1 y foos/new

A veces quiero ver un bar. BarsController maneja eso, y lo hago como: bars/1 o bars/1/edit.

Si estoy buscando un Bar, es posible que desee explorar todos los Foos que forman parte de ese Bar. Entonces, me gustaría usar bars/1/foos/ para mirar esos Foos.

Esto es muy sencillo con recursos anidados, y se ve así:

resources :foo 
resources :bar do 
    resources :foo 
end 

Sin embargo, Foos que son parte de una barra son un poco especial, apartado de los Foos regular. Entonces, por ejemplo, si cargo foos/1 o bars/1/foos/1, estaría buscando el mismo Foo, pero estoy enfocado en información diferente en cada caso.

Así que he estado pensando en tener un Controlador BarFoos para manejar Foos cuando están en el contexto de un Bar. Sin embargo, si anoto BarFoos en Bar, mis ayudantes serán como bar_bar_foos_path y new_bar_bar_foo_path. Eso parece redundante.

Por lo tanto, ahora estoy pensando en espacios de nombres, que es algo que nunca antes había visto. Veo en los carriles de guía que podría definir:

namespace "bar" do 
    resources :foos 
end 

Si hago lo que puedo hacer una segunda FoosController bajo app/bar/, y que FoosController puedo manejar Foos en el interior de un bar con buenos ayudantes como bar_foo_path(:id) en lugar de bar_bar_foo_path(:id).

Pero si hago eso, ¿qué ocurre con mi BarsController? ¿Cómo se enrutan las solicitudes al BarsController si en lugar de resources :bars tengo namespace "bar"?

Y, por último, ¿hay algo especial que deba hacer dentro de mi FoosController secundario para asegurarme de que no haya un conflicto de nombre con el FoosController de nivel superior? Me doy cuenta de que el enrutamiento dice "espacio de nombres", pero ¿cómo sabe el resto del código de rubí que el app/bar/foos_controller y el app/foos_controller no son de la misma clase?

Gracias!

Respuesta

36

Creo que lo que estamos tratando de lograr es:

  1. Bar tiene muchas Foos
  2. Ver Foos perteneciente a Bar
  3. Ver todos los Foos independientemente de los padres.

Puede lograrlo con: rutas.RB:

resources :foos 
resources :bars do 
    resources :foos, :controller => 'bars/foos' 
end 

Los ayudantes ruta que terminan con son:

  • bars_path
  • foos_path
  • bars_foos_path
  • etc, etc, 'rutas rastrillo' para el resto =)

En esencia, terminas con :

  • app/BarsController (carriles bares controlador g)
  • app/FoosController (carriles Foos controlador g)
  • app/bares/FoosController (carriles bares controlador g/foos)

en FoosController, usted podrá acceder a Foos como de costumbre con:

@foos = Foos.all 

y en los bares/FoosController, usted podrá acceder a Foos de barras con:

@foos = @bar.foos 

donde bar puede ser pre-recuperada en el controlador bares/Foos con:

before_filter :get_client 

private 
def get_client 
    @bar = Bar.find(params[:bar_id]) 
end 

Hope esto ayuda. =)

Editar: En cuanto a rutas de espacios de nombres, los he usado personalmente cuando algunos de mis recursos recuperados de una sub-ruta. Por ejemplo, si tengo una sección de administración de mi sitio web, entonces podría tener lo siguiente:

routes.rb:

namespace :admin do 
    resources :foos 
end 

y creo mi controlador con:

rails g controller admin/foos 

Este configura mi recurso foos, de modo que pueda acceder a él en "my site url"/admin/foos, y también obtenga ayudantes como admin_foos_path.

+0

Su descripción de mi escenario es exactamente correcto , y tu respuesta es muy clara, ¡gracias! Veo cómo funcionaría tu respuesta, ¡eso es increíble! Solo para dar seguimiento a un detalle, ¿* recomendarías * anidar sobre el espacio de nombres en este escenario? ¿Podrías ofrecer cualquier pros/contra que hayas experimentado en ambos sentidos? – Andrew

+3

En su caso, como bar y foo son ambos recursos, y foo pertenece a la barra, tiene mucho sentido usar recursos anidados. Para ampliar la explicación del espacio de nombres anterior: si se encuentra en una situación en la que se trata de diferentes comportamientos para diferentes contextos, es decir, si soy administrador, hago A, de lo contrario hago B, y la lógica es cualquier cosa menos la lo más simple o disperso, consideraré el espacio de nombres y agregaré un controlador que me permita trabajar en ese contexto específico. 'admin' representa un contexto en lugar de un recurso en este caso. – clemensp

+0

Genial, ¡eso tiene mucho sentido! – Andrew

5

Hay contras a este enfoque.

Si declara una constante, ej. CONST_NAME, en el recurso anidado foos, los rieles arrojarán la excepción "constante no inicializada :: Foo :: CONST_NAME" debido a su algoritmo de alcance.

Para evitar tal comportamiento, utilice:

resources :foos 
resources :bars do 
    scope :module => "bar" do 
    resources :foos #, :controller => 'bar/foos' no need to use this now because route will be searched there by default 
    end 
end 

Ahora usted no conseguirá una excepción durante el uso:

Foo::CONST_NAME 

o

Bar::Foo::CONST_NAME 
Cuestiones relacionadas