Forum: Rails-ES has_and_belongs_to_many con acts_as_adjacency_list

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
0cd446ac0fa70a937c5ba9fd17b39d5d?d=identicon&s=25 Jorge Garcia (Guest)
on 2009-03-02 17:00
(Received via mailing list)
Hola Lista

Tengo tres tablas Productos, Tags  y productos_tags. Los Tags pueden
tener
hijos y necesito hacer una consulta que devuelva los productos de un
Tags o
de los descendientes de dicho Tag.

Mis tablas:

    create_table :productos do |t|
      t.integer :activo
      t.string :nombre

      t.timestamps
    end

    create_table :tags do |t|
      t.string :nombre
      t.integer :parent_id

      t.timestamps
    end

    create_table :productos_tags do |t|
      t.integer :producto_id
      t.integer :tag_id

      t.timestamps
    end

Mis Modelos:

class Producto < ActiveRecord::Base
   has_and_belongs_to_many :tags
end

class Tag < ActiveRecord::Base
  acts_as_adjacency_list :foreign_key => 'parent_id'
  has_and_belongs_to_many :productos
end

No quiero usar find_by_sql

Tendria que hacer 3 modelos y usar has many :through? Agradecere
cualquier
idea o indicación de tema para buscar más información

Gracias

Jorge Garcia
Desarrollador Rails
1f2eadfb41362800ebc2cf211b91d0f7?d=identicon&s=25 javier ramirez (Guest)
on 2009-03-02 17:13
(Received via mailing list)
hola
>
> Tengo tres tablas Productos, Tags  y productos_tags. Los Tags pueden
> tener hijos y necesito hacer una consulta que devuelva los productos
> de un Tags o de los descendientes de dicho Tag.

si sólo tienes un par de niveles (padre/hijo) puedes conseguirlo de
forma fácil con un include y una condición. Si tienes varios niveles, no
hay forma portable de hacerlo sin utilizar varias queries con la
estructura que propones (aunque algunas bases de datos sí traen
extensiones para navegar por un árbol)

lo que sí podrías hacer es no utilizar un árbol, sino un nested set.
Tiempo ha en rails estaba incluída el componente "acts_as_nested_set"
que de forma transparente te permitía este tipo de cosas. Hoy en día es
un plugin separado en
http://github.com/rails/acts_as_nested_set/tree/master

suerte,


--
javier ramírez

..i do ruby on rails development in madrid, spain, at
http://www.aspgems.com
..you can find out more about me on http://formatinternet.wordpress.com
and http://workingwithrails.com/person/5987-javier-ramirez
0cd446ac0fa70a937c5ba9fd17b39d5d?d=identicon&s=25 Jorge Garcia (Guest)
on 2009-03-02 17:23
(Received via mailing list)
>
> si sólo tienes un par de niveles (padre/hijo) puedes conseguirlo de
> forma fácil con un include y una condición. Si tienes varios niveles, no
> hay forma portable de hacerlo sin utilizar varias queries con la
> estructura que propones (aunque algunas bases de datos sí traen
> extensiones para navegar por un árbol)

Tengo varios niveles. A que te refieres con utilizar varias queries?
la BBDD es MySql

>
> lo que sí podrías hacer es no utilizar un árbol, sino un nested set.
> Tiempo ha en rails estaba incluída el componente "acts_as_nested_set"
> que de forma transparente te permitía este tipo de cosas. Hoy en día es
> un plugin separado en http://github.com/rails/acts_as_nested_set/tree/master
>
> suerte,
>
Me miro lo del acts_as_nested_set, aunque Necesito que sea usando el
acts_as_adjacency_list

 >
> --
> javier ramírez
>
> ..i do ruby on rails development in madrid, spain, at http://www.aspgems.com
> ..you can find out more about me on http://formatinternet.wordpress.com
> and http://workingwithrails.com/person/5987-javier-ramirez
> _______________________________________________
> Ror-es mailing list
> Ror-es@lists.simplelogica.net
> http://lists.simplelogica.net/mailman/listinfo/ror-es

Muchas Gracias por tu respuesta
1f2eadfb41362800ebc2cf211b91d0f7?d=identicon&s=25 javier ramirez (Guest)
on 2009-03-02 17:41
(Received via mailing list)
> Me miro lo del acts_as_nested_set, aunque Necesito que sea usando el
> acts_as_adjacency_list
>

en ese caso estás condenado a la ineficiencia.. acts as adjacency list
es como acts as tree. Cada vez que quieres consultar información de los
hijos de un padre determinado (o del padre de un elemento) tienes que
ejecutar una query contra la base de datos.. y así hasta llegar al
último nivel.

precisamente un nested set te evita esto, pero si tienes que usar
adjacency no vas a poder hacerlo en una única consulta, que pensaba que
era lo que pedías en tu mail inicial

--
javier ramírez

..i do ruby on rails development in madrid, spain, at
http://www.aspgems.com
..you can find out more about me on http://formatinternet.wordpress.com
and http://workingwithrails.com/person/5987-javier-ramirez
0cd446ac0fa70a937c5ba9fd17b39d5d?d=identicon&s=25 Jorge Garcia (Guest)
on 2009-03-02 17:44
(Received via mailing list)
Hola

Mire un poco el acts_as_nested_set

Si lo de usarlo era para poder acceder a todos los descendientes de un
elemento puedo con  acts_as_adjacency_list

productos= []
Tag.find(:first).descendents.collect{|p| productos << p }

con esto tengo productos en un array y Necesitaba algo asi:

@products = @tag.productos.find(:all,:page => {:start => 1, :size =>
10, :current =>2}, :include => ,:conditions=>"activo <>0",
:order=>"activo")

para que me funcione el plugin paginating_find

Alguna idea?

Gracias

Jorge Garcia
Desarrollador Web
0cd446ac0fa70a937c5ba9fd17b39d5d?d=identicon&s=25 Jorge Garcia (Guest)
on 2009-03-02 17:48
(Received via mailing list)
Muchas Gracias Javier

Mirare mas a fondo el nested y intentare implementarlo con el

El día 2 de marzo de 2009 17:40, javier ramirez <jramirez@aspgems.com>
escribi
1f2eadfb41362800ebc2cf211b91d0f7?d=identicon&s=25 javier ramirez (Guest)
on 2009-03-02 17:49
(Received via mailing list)
> Si lo de usarlo era para poder acceder a todos los descendientes de un
> elemento puedo con  acts_as_adjacency_list
>

poder puedes, pero a costa de lanzar muchas consultas
> Tag.find(:first).descendents.collect{|p| productos << p }
>

ese inocente "descendents" te lanza una query por cada nivel de hijos
que tengas. A eso me refería con el tema de que con nested_set podías
sacar todos los hijos de una sola vez en un único find



--
javier ramírez

..i do ruby on rails development in madrid, spain, at
http://www.aspgems.com
..you can find out more about me on http://formatinternet.wordpress.com
and http://workingwithrails.com/person/5987-javier-ramirez
49b6123803e4f327144e991daab62f77?d=identicon&s=25 Daniel Rodriguez Troitiño (Guest)
on 2009-03-02 18:58
(Received via mailing list)
Jorge, tengo un par de dudas sobre tus preguntas,

1) ¿de donde sale acts_as_adjacency_list? Lo único que encuentro con
Google es un commit al source code de Spree en GitHub. Sin README, sin
documentación (la poca que tiene parece copiada de Acts As Tree).

2) ¿por qué la necesidad de utilizar acts_as_adjancency_list? Si lo
que nos vas a decir es porque es ese el plugin que está instalado...
no me parece una razón válida.

En un repaso rápido del código no está optimizado para casi nada. Lo
único que proporciona por encima de Acts As Tree es el orden de los
nodos hijos. Y tampoco diría que lo hace muy eficientemente. Además
por lo que veo de tu código no utilizas el orden de los hijos para
nada (y por cierto, no es necesario que indiques la opción
:foreing_key si se va a llamar "parent_id", que es el nombre por
defecto).

3) ¿por qué no acts_as_nested_set? Como te han dicho ya te soluciona
elegantemente el problema de recuperar todos los descendientes de un
tag. Y con ello es relativamente sencillo conseguir todos los
productos de esos tags. Y luego hacer el paginating find. Y la
migración de las tablas no parece tan complicada.

Suerte.
0cd446ac0fa70a937c5ba9fd17b39d5d?d=identicon&s=25 Jorge Garcia (Guest)
on 2009-03-02 19:10
(Received via mailing list)
Gracias Javier

Tienes razón, debería usar acts_as_nested_set. cuando lo consiga
posteare como me ha ido

Jorge Garcia
Desarrollador Rails
0cd446ac0fa70a937c5ba9fd17b39d5d?d=identicon&s=25 Jorge Garcia (Guest)
on 2009-03-03 11:23
(Received via mailing list)
Al final lo hice asi:

Cree este metodo en el modelo:

  def id_todos_los_hijos(a=nil)
    a=[] if a==nil
    a << self.id
    self.children.each {|child| child.id_todos_los_hijos(a)}
    return a
  end

Y en el controlador:

@productos = Productos.find (:all,
                :page => {:start => 1, :size => 10, :current =>
params[:p]},
                :include => :images,
                :joins=>"INNER JOIN productos_tags ON
productos.id=products_tags.producto_id",
                :conditions=>"activo<>0 and tag_id in
(#{tag.id_todos_los_hijos.join(",")})")

Es verdad que es poco eficiente en comparacion con acts_as_nested_set

Mi duda esta resuelta. Era si se podia establecer una relacion
has_and_belongs_to_many contra una tabla con hijos y la respuesta
parece ser que No.

Gracias a toda la lista

Jorge Garcia
Desarrollador Rails
This topic is locked and can not be replied to.