Buenas, aquí estoy liado con REST, parece que ya le voy pillando el
que. Se me presenta una duda y me gustaria que me dijérais como lo
solucionaríais vosotros, ya que se me ocurren diversas soluciones pero
no se si voy bien. Me explico:
En una aplicación tengo recursos anidados, supóngase ofertas de empleo
que pertenecen a un usuario que las ha publicado.
user has_many jobs
job belongs_to user
Creo en mi routes:
map.resources :users do |user|
user.resources :jobs
end
Hasta aquí ningún problema, pongo un before_filter :get_user en el
controlador de jobs i ya está. Pero me gustaría poder acceder
directamente a las ofertas de empleo en algunos casos, para borrarlas
o para hacer simplemente un listado, pasando del usuario. Para esto
añado
map.resources :jobs
en el routes y ya tengo recurso anidado y no anidado. Fantástico. El
problema lo tengo cuando intento acceder directamente a las ofertas ya
que el controlador hace el before_filter :get_user y como no le estoy
pasando un usuario peta.
y así pase del index, pero necesito poder listar todas las ofertas
independientemente del usuario y también poder listar las ofertas de
un usuario en concreto para que las pueda administrar.
El 9/01/08, Emili Parreño [email protected]
escribió:> en el routes y ya tengo recurso anidado y no anidado. Fantástico. El
Yo también soy rest-novato así que corregidme si me equivoco, pero
entiendo que los recursos o son anidados, o no lo son. O sea, que un
recurso sea anidado debería significar que sólo tiene sentido dentro
del contexto de su recurso padre.
De ahí que se haga el before_filter :get_user, y que además sea este @user cogido del contexto el que se use en cada
acción.
En resumen, que yo haría una ruta para users y otra para jobs, sin
anidar… O
qué?
en el routes y ya tengo recurso anidado y no anidado. Fantástico. El
problema lo tengo cuando intento acceder directamente a las ofertas ya
que el controlador hace el before_filter :get_user y como no le estoy
pasando un usuario peta.
Yo creo que ahi lo clave es que se entienda que el usuario es
opcional. Es decir, un before_filter de ese tipo suele conllevar una
precondicion: o hay usuario o redirect por invalido. Pero en este caso
no es asi, su rol seria el de DRYficar la obtencion del job o jobs.
Visto asi se podria enfocar de esta manera en JobsController:
before_filter :get_user
before_filter :get_job
def index
@jobs = target.find(:all)
end
# ...
protected
def get_user
return if params[:user_id].blank?
@user = User.find(params[:user_id])
rescue ActiveRecord::RecordNotFound
redirect_to jobs_url
end
def get_job
@job = target.find(params[:id])
rescue ActiveRecord::RecordNotFound
redirect_to jobs_url
end
def target
@user ? @user.jobs || Job
end
Las URLs con caminos que indican jerarquia pueden indicar nesting
(pertenencia), scope (como en el ejemplo de ayer de Damaris), y en
general lo que tenga sentido en la aplicacion.
Pero supon ahora que estas en una central de reservas de hoteles. Para hacer una reserva puede quedar majo algo asi:
POST /chains/sol-melia/hotel/54/bookings
…
Eso daria una reserva. En una app web podrias ir al show de esa
reserva despues. Si estuvieramos en un web service devolveriamos un
201 Created con una cabecera Location a la direccion de ese recurso
nuevo. Esa direccion puede perfectamente ya no reflejar la jerarquia
(aunque podria hacerlo y se pueden ofrecer ambos accesos):
GET /bookings/789123
Por ejemplo, cancelar una reserva es mas facil que se ofrezca como
DELETE /bookings/789123
a no que el cliente deba añadir la jerarquia que es redundante y puede
que le suponga un GET previo. Ya la reserva sabe a quien pertenece.
En una API asi BookingsController ha de estar preparado para servir
peticiones con scope y sin scope. Si las consultas y las cancelaciones solo son accesibles con URLs directas entonces show y destroy no han
de lidiar con el scope opcional. Si index se publica con y sin scope
entonces la accion debe entender ambas llamadas.
Pero tambien puede hacer que el “get_user” si no recibe ningun
parametro lea uno por defecto. Entiendo que lo quereis hacer para
“administrar” entradas así que debeis tener una sesion creada.
def get_user
user = params[:user_id] || session[:admin] @user = User.find(user)
end
def get_user
return if params[:user_id].blank? @user = User.find(params[:user_id])
rescue ActiveRecord::RecordNotFound
redirect_to jobs_url
end
def get_job @job = Job.find(:all)
rescue ActiveRecord::RecordNotFound
redirect_to jobs_url
end
En el routes.rb crear las rutas
map.resources :forums do |forum|
forum.resources :topics do |topic|
topic.resources :posts
end
end
map.resources :jobs
De esta manera cuando alguien acceda a al recurso /jobs detectará que
no se ha pasado un user_id y cambiará el find que se ejecuta en el
método index del controlador de jobs para que liste todos los jobs. Si
se pasa un recurso anidado buscará los jobs de ese usuario cambiando
el find del método index.
En resumen es esto.
This forum is not affiliated to the Ruby language, Ruby on Rails framework, nor any Ruby applications discussed here.