Has_and_belongs_to_many con acts_as_adjacency_list


#1

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 G.
Desarrollador Rails


#2

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


#3

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
removed_email_address@domain.invalid
http://lists.simplelogica.net/mailman/listinfo/ror-es

Muchas Gracias por tu respuesta


#4

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


#5

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 removed_email_address@domain.invalid
escribi


#6

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 G.
Desarrollador Web


#7

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).

  1. ¿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.


#8

Gracias Javier

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

Jorge G.
Desarrollador Rails


#9

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


#10

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 G.
Desarrollador Rails