Has_and_belongs_to_many -- Ternaria

Hola a todos,

Tengo el siguiente problema para tomar el valor de una relacion
ternaria, me explico:

Tengo una relacion N a N a N con los siguientes modelos, Especificacion,
Lote y Subasta.

Estas se conectan en una relacion llamada Especificacions_Lotes_Subastas
y se crea perfectamente en la base de datos, el problema que tengo es
que si tengo un ID de un especificacion y quiero buscar cuantas subastas
tiene en relacion me pasa lo siguiente:

Esto es lo que yo hago para tomar el valor

@subastas= Especificacion.find(ID_especificacion).subastas

Este es el error:

Mysql::Error: #42S02Table ‘sei_development.especificacions_subastas’
doesn’t exist: SHOW FIELDS FROM especificacions_subastas

Esto me ha funcionado antes para relaciones N a N de dos entidades pero
ahora con tres no se como hacer para que funcione

Saludos,
Maximiliano M.

2008/6/11 Maximiliano M. [email protected]:

Tengo el siguiente problema para tomar el valor de una relacion
ternaria, me explico:

Tengo una relacion N a N a N con los siguientes modelos, Especificacion,
Lote y Subasta.

Estas se conectan en una relacion llamada Especificacions_Lotes_Subastas
y se crea perfectamente en la base de datos, el problema que tengo es
que si tengo un ID de un especificacion y quiero buscar cuantas subastas
tiene en relacion me pasa lo siguiente:

Puedes explicar como se relacionan los modelos en terminos de has_many
y belongs_to?

Hola Xavier seguro,

Los modelos estan relacionados de la siguiente manera:

class Especificacion < ActiveRecord::Base

has_and_belongs_to_many :lotes
has_and_belongs_to_many :subastas

end

class Lote < ActiveRecord::Base

has_and_belongs_to_many :especificacions
has_and_belongs_to_many :subastas

end

class Subasta < ActiveRecord::Base

has_and_belongs_to_many :lotes
has_and_belongs_to_many :especificacions

end

Y esta es la tabla relacion que se llama especificacions_lotes_subastas

class EspecificacionsLotesSubastas < ActiveRecord::Base
has_many :lotes
has_many :especificacions
has_many :subastas

end

Yo quisiera seleccionar con el ID de especificacions a que subastas se
relaciona pero me muestra el error que escribi antes y como dije ya lo
probe para una relacion N a N y si funciono pero N a N a N no

2008/6/11 Maximiliano M. [email protected]:

Los modelos estan relacionados de la siguiente manera:

Gracias, antes de seguir, que modela esto que tiene tantas flechas?
Una misma subasta puede pertenecer a varias especificaciones? Un mismo
lote puede pertenecer a varias subastas?

El 11/06/2008, a las 04:30 p.m., Maximiliano M.
escribió:

Hola Xavier seguro,

A mi parecer en realidad las especificaciones forman parte del lote
y este a su vez formar parte de la subasta. Entonces seria mas facil
si lo modelas de la siguiente manera:

Subasta ----> Lote ----> Especificacion

class Especificacion < ActiveRecord::Base
belongs_toy :lotes
end

class Lote < ActiveRecord::Base
has_many :especificacions
belongs_to :subastas
end

class Subasta < ActiveRecord::Base
has_many :lotes
end

El 11/06/2008, a las 06:21 p.m., Maximiliano M.
escribió:

Te coloco un ejemplo:

2008/6/12 Maximiliano M. [email protected]:

Todo esto seria de la misma subasta, por lo tanto si lo vemos asi una
subasta puede tener varios lotes, donde estos a su vez tienen varias
especificaciones y estas especificaciones aparecen en varios lotes como
se nota en el ejemplo y se podria dar el caso de que apareciean en otras
subastas, por esto mi relacion es N a N a N.

En este caso me parece que lo que podemos eliminar es la relacion
explicita entre especificaciones y subastas, ya que una especificacion
pertenece a una subasta en tanto en cuanto pertenece a un lote de esa
subasta.

Ademas seria seguramente una relacion de solo lectura en ambos
sentidos. Como las especificaciones viven en un limbo, no tienen
belongs_to, no vas a crearlas como hija de una subasta ni nada asi,
solo vas a leer que hay asociado a traves de lotes.

Me sale este modelo escrito sobre la marcha (modulo la hora que es
cafe con leche mediante :slight_smile:

class Subasta < AR::Base
has_many :lotes

 # metodo de conveniencia, read-only
 def especificaciones
   lotes.map(&:especificaciones).flatten.uniq
 end

end

class Lote < AR::Base
belongs_to :subasta
habtm :especificaciones
end

class Especificacion < AR::Base
habtm :lotes

 # metodo de conveniencia, read-only
 def subastas
   lotes.map(&:subasta)
 end

end

Algo asi.

Te coloco un ejemplo:

Supongamos que quiero subastar Ipod´s con un par de accesorios:

El lote #1 tendria:

Ipod (60GB) --> Esto seria la especificacion #1
De color negro --> Esto seria la especificacion #2

EL lote #2 tendria:

Ipod (60)Gb --> Misma especificacion #1
De color blanco --> Especificacion #3

Todo esto seria de la misma subasta, por lo tanto si lo vemos asi una
subasta puede tener varios lotes, donde estos a su vez tienen varias
especificaciones y estas especificaciones aparecen en varios lotes como
se nota en el ejemplo y se podria dar el caso de que apareciean en otras
subastas, por esto mi relacion es N a N a N.

2008/6/12 Maximiliano M. [email protected]:

@subastas=Proveedor.find(id).especificacions (Arreglo de
especificaciones que cumple con ese id)

pero despues quisiera buscar cuales subastas estan relacionadas a ese
arreglo de especificaciones.

Si lo entiendo bien usarias por ejemplo uno de los idiomas que iba en
el post de esta mañana:

Proveedor.find(id).especificaciones.map(&:subastas).flatten.uniq

El tema esta en que las especificaciones estan asociadas a subastas,
pero una colecction de especificaciones no. Por eso hay que iterar por
cada una (map) e ir componiendo la coleccion final.

Xavier,

Esta funcionando perfecto con tu consejo, coloque los metodos y realice
la consulta tal cual tu lo escribiste y me esta mostrado las subastas
asociadas a ese proveedor a traves de las especificaciones.

De verdad muchisimas gracias, esto no solo me resuelve este problema
sino varios ya que necesito realizar este tipo de consultas
frecuentemente para otras relaciones. Lo unico que te queria consultar
es si tienes algun link con la documentacion de esto, ya que lo hice tal
cual me indicas pero teoricamente no tengo ni idea que es lo que hice y
me gustaria aprender sobre esto bien.

Nuevamente muchisimas gracias

Saludos,

Xavier,

Tienes razon al decir que es mas logico modelar Subasta ----> Lote ---->
Especificacion, me parece una muy buena idea, el problema es que me
preocupa cambiar el modelo en base de datos a estas alturas ya que
tengo avanzada esa parte en el proyecto y no quisiera perjudicar la
entrega que es en un par de semanas.

El problema que me surge de cualquiera de los dos modelos ( El que tu
propones y el que tengo actualmente) es un buscar, te muestro como
resolvi el error que me mostraba anteriormente pero que aun con esto no
logro obtener la consulta que quiero.

Coloque esto en los modelos y ya puedo realizar esta consulta:

subastas=Especificacion.find(id_especificacion).subatas (Esto me
devuelve todas las subastas relacionadas a ese ID)

A los modelos les agregue esto:

class Lote < ActiveRecord::Base
has_and_belongs_to_many :especificacions, :join_table =>
‘especificacions_lotes_subastas’
has_and_belongs_to_many :subastas, :join_table =>
‘especificacions_lotes_subastas’
end

class Subasta < ActiveRecord::Base
has_and_belongs_to_many :lotes, :join_table =>
‘especificacions_lotes_subastas’
has_and_belongs_to_many :especificacions, :join_table =>
‘especificacions_lotes_subastas’
end

class Especificacion < ActiveRecord::Base
has_and_belongs_to_many :lotes, :join_table =>
‘especificacions_lotes_subastas’
has_and_belongs_to_many :subastas, :join_table =>
‘especificacions_lotes_subastas’
end

Mi problema ahora seria el siguiente si yo adicionalmente tengo N
proveedores relacionados a N especificaciones, me gustaria a traves de
un ID proveedor poder obtener a que subasta se relacionan

Es decir quisiera hacer esto

@subastas=Proveedor.find(id).especificacions.subatas

pero me indica que .subastas no es un metodo definido

Como se puede hacer una consulta para un arreglo de valores, ya que si
solo hago esto:

@subastas=Proveedor.find(id).especificacions (Arreglo de
especificaciones que cumple con ese id)

pero despues quisiera buscar cuales subastas estan relacionadas a ese
arreglo de especificaciones.

Se que mi caso se ve complicado y definitivamente he realizado
demasiadas preguntas, si me pudieras ayudar estaria muy agradecido ya
que esto es un proyecto de grado y estoy culminando la carrera.

Gracias de antemano y saludos,
Maximiliano M.

quiero hacer un ejemplo de libros y autores

require ‘rubygems’
require ‘active_record’
require ‘yaml’
config = YAML::load(File.open(“path_to/database.yml”))[“development”]
ActiveRecord::Base.establish_connection( config )

class Author < ActiveRecord::Base
has_and_belongs_to_many :books
end

class Book < ActiveRecord::Base
has_and_belongs_to_many :authors
end

num_authors = 10;
num_books = 10;

authors = Array.new
books = Array.new

num_authors.times { |loop|

authors[loop] = Author.new({:name=>'author_'+loop.to_s})

}

num_books.times { |loop|
books[loop] = Book.new({:name=>‘book_’+loop.to_s})
books[loop].authors= authors
books[loop].save
}

y el probleme es cuando intenta crea el segundo libro y almacenar las
respectivas relaciones de este con los autores

in log': Mysql::Error: #23000Duplicate entry '35' for key 1: INSERT INTO authors_books (id,book_id,author_id`) VALUES (10, 2, 10)
(ActiveRecord::StatementInvalid)

es como si no cambiara el id del registro de la relacion

Gracias de antemano

2008/6/13 Maximiliano M. [email protected]:

Esta funcionando perfecto con tu consejo, coloque los metodos y realice
la consulta tal cual tu lo escribiste y me esta mostrado las subastas
asociadas a ese proveedor a traves de las especificaciones.

De verdad muchisimas gracias, esto no solo me resuelve este problema
sino varios ya que necesito realizar este tipo de consultas
frecuentemente para otras relaciones. Lo unico que te queria consultar
es si tienes algun link con la documentacion de esto, ya que lo hice tal
cual me indicas pero teoricamente no tengo ni idea que es lo que hice y
me gustaria aprender sobre esto bien.

Son metodos de Ruby mismo para colecciones. Partimos de esto

Proveedor.find(id).especificaciones

que es una coleccion de especificaciones. Aplicamos

map {|espec| esp.subastas}

en la forma Railera (es equivalente)

map(&:subastas)

El resultado es una coleccion de colecciones de subastas, una por cada
especificacion. Como lo que queremos es una coleccion de subastas en
lugar de una coleccion de colecciones, aplicacamos flatten, que quita
anidacion. Y por ultimo, como podria pasar que una dos
especificaciones de ese proveedor pertenezcan a una misma subasta,
quitamos posibles duplicados con uniq.

Todo junto:

Proveedor.find(id).especificaciones.map(&:subastas).flatten.uniq

Rails es un framework Ruby y como puntero te diria que leas un libro
de Ruby como “Programming Ruby”.

On Tue, Jun 24, 2008 at 3:55 AM, Rafael G.
[email protected] wrote:

y el probleme es cuando intenta crea el segundo libro y almacenar las
respectivas relaciones de este con los autores

in log': Mysql::Error: #23000Duplicate entry '35' for key 1: INSERT INTO authors_books (id, book_id, author_id`) VALUES (10, 2, 10)
(ActiveRecord::StatementInvalid)

Hola,

En las relaciones HABTM la “join table” no ha de tener id, sólo los
ids de las relaciones (en tu caso book_id y author_id).

Un saludo,


Sergio Gil Pérez de la Manga
e-mail > [email protected]
blog > http://www.lacoctelera.com/porras

Gracias por tu respuesta

Pero eso no suena muy bien, lo que me dices resuelve el problema pero no
entiendo por que no deben tener id. donde puedo encontrar una
explicación a esto ?

perdon el error es
in log': Mysql::Error: #23000Duplicate entry '10' for key 1: INSERT INTO authors_books (id,book_id,author_id`) VALUES (10, 2, 10)
(ActiveRecord::StatementInvalid)

El día 25 de junio de 2008 2:47, Rafael G.
[email protected]
escribió:> Pero eso no suena muy bien, lo que me dices resuelve el problema pero no

entiendo por que no deben tener id. donde puedo encontrar una
explicación a esto ?

A diferencia de las has_many :through, las habtm no permiten guardar
atributos en la relación: como los dos únicos campos que puedes
guardar son los ids de los modelos que estás relacionando no tiene
sentido manejar esta tabla como un modelo ActiveRecord y por tanto no
es necesario almacenar un id en ella.