Los recursos anidados son una de las cosas que mas me gustan de trabajar con REST en Rails y es básicamente la forma de generar rutas mas amistosas de una manera mucho mas rapida asociando los modelos, usando esta forma se crea un lazo inseparable entre el padre y sus hijos.
El efecto lo puedes lograr tu mismo iterando sobre el contenido de los modelos, modificando las rutas, pero el problema es que pierdes el acceso REST a los controladores o al menos se te haga muy muy enredado.
Recuerda, Rails es acerca de convenciones, cuando las sigues te convertirás en uno de los miles de programadores felices, si no… mejor no uses Rails (Obviamente, en ocasiones romper las convenciones ayuda, solo no lo hagas cuando no sea necesario).
Pero como lo implemento
map.resources :branches, :path_prefix => '/admin' do |branches|
branches.resources : orders
end
2do, tienes que agregar las asociaciones
En app/model/branch.rb
has_many : orders # Ojo con las convenciones, has_many :plural
En app/model/order.rb
belongs_to : banch # Ojo con las convenciones, belongs_to :singular (lógico!, se lee!)
3ero. Tenemos que retocar los controladores, para que sepa donde buscar a los hijos.
En este caso app/controllers/orders.rb
class OrdersController < ApplicationController
before_filter : load_branch
# GET /orders
# GET /orders.xml
def index
@orders = @branch.orders.find(:all).reverse
respond_to do |format|
format.html # index.rhtml
format.xml { render : xml => @orders.to_xml }
end
end
# GET /orders/1
# GET /orders/1.xml
def show
@order = @branch.orders.find(params[:id])
@lines = @branch.types
respond_to do |format|
format.html # show.rhtml
format.xml { render : xml => @order.to_xml }
end
end
# GET /orders/new
def new
@order = Order.new
end
# GET /orders/1;edit
def edit
@order = @branch.orders.find(params[:id])
end
# POST /orders
# POST /orders.xml
def create
@order = Order.new(params[:order])
respond_to do |format|
if @order.save
flash[: notice] = ‘Order was successfully created.’
format.html { redirect_to order_url(@branch,@order) }
format.xml { head : created, :location => order_url(@branch,@order) }
else
format.html { render : action => “new” }
format.xml { render : xml => @order.errors.to_xml }
end
end
end
# PUT /orders/1
# PUT /orders/1.xml
def update
@order = @branch.orders.find(params[:id])
respond_to do |format|
if @order.update_attributes(params[:order])
flash[:notice] = ‘Order was successfully updated.’
format.html { redirect_to order_url(@branch,@order) }
format.xml { head : ok }
else
format.html { render :action => “edit” }
format.xml { render : xml => @order.errors.to_xml }
end
end
end
# DELETE /orders/1
# DELETE /orders/1.xml
def destroy
@order = @branch.orders.find(params[:id])
@order.destroy
respond_to do |format|
format.html { redirect_to orders_url }
format.xml { head : ok }
end
end
# Notar como obtengo al papa de las ordenes
def load_branch
@branch = Branch.find params[:branch_id]
end
end
Notar en el código de arriba, como llamo a el padre (before_filter) de en este caso las ordenes, y como genero sus rutas (order_url(@branch,@order))
Lo que automáticamente te genera por ejemplo, las siguientes rutas:
/branches (Lista de sucursales)
/branches/1 (Muestra sucursal 1)
/branches/1;edit (Editas sucursal 1)
/branches/1/orders (Lista de ordenes para la sucursal 1)
/branches/1/orders/1;edit (Editas la orden 1 de la sucursal 1)
ups, pero estoy ocupando path_prefix asi que en realidad quedaría:
(Esta opción es completamente opcional y no recomendada (Es preferible tener una sola interfaz para todo, al menos algunos lo creen así… yo no mucho, aunque creo depende del tipo de proyecto.)
/admin/branches (Lista de sucursales)
/admin/branches/1 (Muestra sucursal 1)
/admin/branches/1;edit (Editas sucursal 1)
/admin/branches/1/orders (Lista de ordenes para la sucursal 1)
/admin/branches/1/orders/1;edit (Editas la orden 1 de la sucursal 1)
Se puede jugar un poco mas….
Aunque lo dejo a tu discreción
map.resources :branches, :path_prefix => '/admin' do |branches|
branches.resources : orders do |orders|
orders.resources :line_items
end
end
Nota: Para este ejemplo ocupe scaffold_resource para generar todo el código, si ustedes también lo hacen podrán verlo funcionando de inmediato.
Nota 2: Lamento lo difícil que es leer código en mi blog, lo tengo como uno de los principales puntos del porque quiero re diseñar mi sitio, pero igualmente espero ayudarlos (ojo: Hay muchos dos puntos ( : ) que separo para no generar emoticons, recuerden es :variable)