Pregunta sobre has_many

Buenas, tengo unos modelos tal que así

class Incidencia < ActiveRecord::Base
belongs_to :cliente_usuario
end

class ClienteUsuario < ActiveRecord::Base
belongs_to :cliente
has_many :incidencias
end

class Cliente < ActiveRecord::Base
has_many :cliente_usuarios
end

Y me gustaría acceder desde incidencia a cliente sin tener que poner
@clientes = incidencia.cliente_usuario.cliente

He visto algo de has_many :through, pero no sé si es para este caso

Alguna ayudita?

Estupendo. Muchas gracias.

Y en el caso de que quisiera acceder a las incidencias de un cliente?
Ahí si
que se usaría el through o habría que definir otro método para
incidencias?

On Oct 23, 2006, at 9:49 AM, Luis V. wrote:

class Cliente < ActiveRecord::Base
has_many :cliente_usuarios
end

Y me gustaría acceder desde incidencia a cliente sin tener que
poner @clientes = incidencia.cliente_usuario.cliente

He visto algo de has_many :through, pero no sé si es para este caso

Efectivamente no lo es, has_many :through se usaria si ClienteUsuario
fuera un join model.

Una solucion habitual es simplemente añadir un metodo de conveniencia
a la clase Incidencia:

class Incidencia < ActiveRecord::Base
belongs_to :cliente_usuario

 def cliente
   self.cliente_usuario.cliente
 end

end

Piensa que los modelos en Rails no son meros mappings a tablas,
generalmente uno les añade algo de chicha para que su API ofrezca la
abstraccion necesaria. En Ruby for Rails a eso le llaman “soft/hard
model enhancement”. Una utilidad chica como Incidencia#cliente
entraria en los “soft”.

– fxn

On Oct 23, 2006, at 10:16 AM, Luis V. wrote:

Estupendo. Muchas gracias.

Y en el caso de que quisiera acceder a las incidencias de un
cliente? Ahí si que se usaría el through o habría que definir otro
método para incidencias?

Ahi escribiria otro soft-enhancement, por ejemplo:

class Cliente
has_many :cliente_usuarios

 def incidencias
   cliente_usuarios.map do |cu|
     cu.incidencias
   end.flatten
 end

end

– fxn

Xavier N. wrote:

class Cliente
has_many :cliente_usuarios

 def incidencias
   cliente_usuarios.map do |cu|
     cu.incidencias
   end.flatten
 end

end

muy interesante los metodos de conveniencia

donde encuentro mas ejemplos y exactamente q es .flatten y .map

On Nov 9, 2006, at 3:32 PM, lamacarena wrote:

 end

end

muy interesante los metodos de conveniencia

donde encuentro mas ejemplos y exactamente q es .flatten y .map

Son metodos muy utiles.

flatten es un metodo que ofrecen algunas colecciones. En ese caso
estamos usando Array#flatten[*] que devuelve el array que resulta del
“aplanado” recursivo del array sobre el que se invoca:

irb(main):001:0> [1, [2, 3], [[[[[7, [8]]]]]]].flatten
=> [1, 2, 3, 7, 8]

Asi que cuando uno obtiene de manera natural un array de arrays, y
esta interesado en el array de los elementos mismos, en vez de
complicarse la vida genera lo natural y aplica flatten al resultado.

map itera sobre una coleccion, le pasa cada elemento a un bloque y
construye la coleccion de los resultados:

irb(main):002:0> [1, 2, 3].map { |x| 2*x }
=> [2, 4, 6]

Como cliente_usuarios devuelve una coleccion, y para cada uno
#incidencias devuelve otra coleccion, nos queda natural generar un
array con los arrays de incidencias, a pesar de que queremos un array
con las incidencias mismas. Ves que es un caso de uso de flatten?

– fxn

[*] En el ejemplo, como cliente_usuarios nos viene de AR en realidad
estamos invocando a #flatten sobre un proxy donde AR wrappea las
coleccciones, pero como este no especializa #flatten se delega en un
verdadero Array interno con method_missing, de manera que en ultima
instancia si que se ejecuta Array#flatten.