Recursos anidados (o no) con REST

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.

Algunos me propondréis que haga esto:

before_filter ::get:user, :only =>
[ :edit, :update, :destroy, :new, :create ]

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.

Sugerencias de los RESTafaris?

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é?

On Jan 9, 2008, at 9:57 AM, Emili Parreño wrote:

Creo en mi routes:
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.

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

– fxn

On Jan 9, 2008, at 10:43 AM, Jaime I. wrote:

anidar… O qué?

No es asi en general.

Hay que tener presente que las URLs que dan acceso a un mismo recurso
pueden ser multiples, por ejemplo

 /releases/my-app-1.1.tar.gz
 /releases/latest.tar.gz

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.

– fxn

On Jan 9, 2008, at 10:48 AM, Xavier N. wrote:

def target
@user ? @user.jobs || Job
end

Ugh, eso seria

def target
@user ? @user.jobs : Job
end

El codigo esta picado en el mismo mail, disculpad si hay alguna errata.

– fxn

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

Algo parecido a esto no?

Un saludo,

Francesc

On Jan 9, 2008, at 10:43 AM, Jaime I. wrote:

anidar… O qué?


Jaime I.
http://jaimeiniesta.com - http://railes.net


Ror-es mailing list
[email protected]
http://lists.simplelogica.net/mailman/listinfo/ror-es


name. Francesc E. i Martí
voice. +34 678.681.603

Merci Xavi :slight_smile:

Lo he hecho como tu decías y ha ido de conya, en definitiva para el
que le interese
sería así:
en el controlador añadir los before filter:

before_filter :get_user
before_filter :get_job

y crear los métodos

GET /jobs

def index
@jobs = target.find(:all)
end

protected

def target
@user ? @user.jobs : Job
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.