Listando relacion padre-hijo con filtro de hijo

Hola, me ha surgido una duda acerca de las relaciones padre-hijos. Luego
de probar y renegar durante un rato bastante largo, me he percatado de
lo siguiente:

<file /app/models/factura.rb>
class Factura < ActiverRecord::Base
has_many :detalles

end

<file /app/models/detalle.rb>
class Detalle < ActiverRecord::Base
belongs_to :factura

end

<file /app/controllers/facturador.rb>
class FacturadorController < ApplicationController
def busca_articulo
@facturas = Factura.find(:all, :include => :detalles,
:conditions => [“detalles.articulo_id = ?”, 5], :order => “fecha”)
end

end

Luego, en la vista <file /app/views/facturador.rhtml>

<% for fac in @facturas %> <% for detalle in fac.detalles %> <% end %> <% end %>
Fecha: <%= fac.fecha.to_s -%>   Cliente:   <%= fac.cliente.to_s -%>
<%= detalle.articulo.nombre %> <%= detalle.cantidad %> <%= detalle.precio %>

O sea, quiero mostrar todas las facturas (con el detalle completo) que
incluyen un determinado artículo (en el ejemplo, el artículo 5).
Sin embargo, la linea que resalto en la vista no me devuelve todos los
detalles de una factura sino que solo el detalle que contiene el
artículo 5. ¿Por qué sucede eso?
Para que me funcione, es como que tengo que volver a buscar el objeto
Factura para que ahí sí realice las asociaciones que deseo; haciendo por
ejemplo:
for detalle in Factura.find(fac.id).detalles
en lugar de la linea antes mencionada.
¿Por qué si “fac” es del tipo “Factura” no ejecuta correctamente la
asociación “detalles” sino que solo me devuelve el registro que tiene el
artículo 5?
Por otro lado, si en el controlador quito la condición de que busque
facturas cuyos detalles incluyan al artículo 5, me funciona de
maravillas la vista.

Bueno, espero sus comentarios.
Saludos

Ariel Diaz B.
Analista en Computación


Correo Yahoo!
Espacio para todos tus mensajes, antivirus y antispam ¡gratis!
¡Abrí tu cuenta ya! - http://correo.yahoo.com.ar

On Oct 23, 2006, at 5:11 PM, Ariel Fernando Diaz B. wrote:

<% for fac in @facturas %>
        </tr>
    <% end %>
<% end %>

O sea, quiero mostrar todas las facturas (con el detalle completo)
que incluyen un determinado artículo (en el ejemplo, el artículo 5).
Sin embargo, la linea que resalto en la vista no me devuelve todos
los detalles de una factura sino que solo el detalle que contiene
el artículo 5. ¿Por qué sucede eso?

Es que si en el WHERE pone detalles.articulo_id = 5, todo detalle que
suba de la query cumple esa condicion.

Una manera de arreglarlo seria recargar la coleccion en la vista con
fac.detalles(true), que vuelve a cargar la relacion para fac. Otra es
venirse desde Articulo

@facturas = Articulo.find(5).detalles.map do |d|
d.factura
end

La original sigue la direccion natural pero ha de recargar la
asociacion y acopla un poco la vista y la accion, una vista deberia
recibir objetos factura normal. La otra va en la direccion opuesta y
posiblemente sea mas costosa (salvo que haya eager loaders
configurados aqui y alla) pero es directa. No estoy muy seguro de
cual me gusta mas.

Ah, una tercera es hacer el reload en el controlador, que el si sabe
que ha hecho algo a medias

@facturas.each { |f| f.detalles(true) }

Si todo esto resulta muy pesado siempre queda find_by_sql.

– fxn

Ok, muchas gracias por tu respuesta Xavier. Veré cuál de todas las
opciones afecta menos el rendimiento.
Saludos y nuevamente gracias por la pronta respuesta.

Ariel Diaz B.
Analista en Computación

Xavier N. [email protected] escribió: On Oct 23, 2006, at 5:11 PM,
Ariel Fernando Diaz B. wrote:

<% for fac in @facturas %>
        
    <% end %>
<% end %>

O sea, quiero mostrar todas las facturas (con el detalle completo)
que incluyen un determinado artículo (en el ejemplo, el artículo 5).
Sin embargo, la linea que resalto en la vista no me devuelve todos
los detalles de una factura sino que solo el detalle que contiene
el artículo 5. ¿Por qué sucede eso?

Es que si en el WHERE pone detalles.articulo_id = 5, todo detalle que
suba de la query cumple esa condicion.

Una manera de arreglarlo seria recargar la coleccion en la vista con
fac.detalles(true), que vuelve a cargar la relacion para fac. Otra es
venirse desde Articulo

@facturas = Articulo.find(5).detalles.map do |d|
d.factura
end

La original sigue la direccion natural pero ha de recargar la
asociacion y acopla un poco la vista y la accion, una vista deberia
recibir objetos factura normal. La otra va en la direccion opuesta y
posiblemente sea mas costosa (salvo que haya eager loaders
configurados aqui y alla) pero es directa. No estoy muy seguro de
cual me gusta mas.

Ah, una tercera es hacer el reload en el controlador, que el si sabe
que ha hecho algo a medias

@facturas.each { |f| f.detalles(true) }

Si todo esto resulta muy pesado siempre queda find_by_sql.

– fxn


Ror-es mailing list
[email protected]


Correo Yahoo!
Espacio para todos tus mensajes, antivirus y antispam ¡gratis!
¡Abrí tu cuenta ya! - http://correo.yahoo.com.ar

Si es que entiendo bien el problema, creo que hay todavia otra opcion.
En el controlador se puede hacer esto:

def busca_articulo
@facturas = Factura.find(:all, :include => [{:detalles => :articulo}],
:conditions => [“detalles.articulo_id = ?”, 5], :order => “fecha”)
end

nota la diferencia en el “:include”. Esta es la forma mas eficiente ya
que se genera una sola llamada a la base de datos.

Sergio

Perdon el include seria:

:include => [{:factura => :detalles}]

Sergio B. wrote:

Si es que entiendo bien el problema, creo que hay todavia otra opcion.
En el controlador se puede hacer esto:

def busca_articulo
@facturas = Factura.find(:all, :include => [{:detalles => :articulo}],
:conditions => [“detalles.articulo_id = ?”, 5], :order => “fecha”)
end

nota la diferencia en el “:include”. Esta es la forma mas eficiente ya
que se genera una sola llamada a la base de datos.

Sergio

Sergio, he probado lo que me dices pero me hace lo mismo: es decir, en
los resultados devueltos no me trae el resto de los detalles de cada
factura.
De todas formas muchas gracias. Saludos

Ariel

Sergio B. [email protected] escribió: Si es que
entiendo bien el problema, creo que hay todavia otra opcion.
En el controlador se puede hacer esto:

def busca_articulo
@facturas = Factura.find(:all, :include => [{:detalles => :articulo}],
:conditions => [“detalles.articulo_id = ?”, 5], :order => “fecha”)
end

nota la diferencia en el “:include”. Esta es la forma mas eficiente ya
que se genera una sola llamada a la base de datos.

Sergio


Posted via http://www.ruby-forum.com/.


Ror-es mailing list
[email protected]


Correo Yahoo!
Espacio para todos tus mensajes, antivirus y antispam ¡gratis!
¡Abrí tu cuenta ya! - http://correo.yahoo.com.ar

Nuevamente, si lo pongo como me dices aquí, obtengo un error de

Association named ‘factura’ was not found; perhaps you misspelled it?
???
Saludos,

Ariel

Sergio B. [email protected] escribió: Perdon el
include seria:

:include => [{:factura => :detalles}]

Sergio B. wrote:

Sergio


Posted via http://www.ruby-forum.com/.


Ror-es mailing list
[email protected]


Correo Yahoo!
Espacio para todos tus mensajes, antivirus y antispam ¡gratis!
¡Abrí tu cuenta ya! - http://correo.yahoo.com.ar