[Teoria] Associations "encadeadas" nos Models

7 views
Skip to first unread message

Reinaldo Junior

unread,
Nov 16, 2009, 2:11:53 PM11/16/09
to rail...@googlegroups.com
Boa tarde pessoal,

Estou quebrando a cabeça faz mto tempo com uns models para usar associações "aninhadas". (o problema tá no fim do email)

Meu exemplo:
 
class Thing < ActiveRecord::Base
  has_and_belongs_to_many :groups
end

class Group < ActiveRecord::Base
  has_and_belongs_to_many :things
end

E uma tabela

create_table :groups_things, :id => false do |t|
  t.references :group
  t.references :thing

Assim eu tenho
thing.groups #grupos daquela coisa
e
group.things #coisas naquele grupo

Até aqui beleza =D

Agora cada Grupo possuem propriedades

class Property < ActiveRecord::Base
  belongs_to :group
end

Mudando group

class Group < ActiveRecord::Base
  has_and_belongs_to_many :things
  has_many :properties
end


PROBLEMA: COMO PEGAR as Properties de um Thing usando o Group como "atravessador" (pode haver mais de um Group)?
OU SEJA, quero poder usar thing.properties e ele retornar todos os properties de todos os groups do thing em questão..

Tentei colocar:

class Thing < ActiveRecord::Base
  has_and_belongs_to_many :groups
  has_many :properties, :through => :groups
end

Mas não funcionou...

Só consigo pegar fazendo isso...
thing.groups.collect{|t| t.properties}

Realmente não tem como fazer isso apenas com as associações? Porque não tem como?


Reinaldo de Souza Junior
http://reinaldojunior.net

Gabriel Sobrinho

unread,
Nov 16, 2009, 2:27:01 PM11/16/09
to rail...@googlegroups.com
Você disse que o has_many :properties, :through => :groups não funcionou mas não disse o problema que ocorreu.

Deu algum erro? Resultados diferentes do esperado?
-- 
Cordialmente,

Gabriel Sobrinho
Diretor de Desenvolvimento

http://www.hite.com.br/

Rodrigo Urubatan Ferreira Jardim

unread,
Nov 16, 2009, 3:02:47 PM11/16/09
to rail...@googlegroups.com
Só pra começar, usar has and belongs to many quase sempre não é uma boa idéia, crie um modelo de associação, por que daqui a pouco tu vai querer saber quem associou, desassociou, quando, por que, ...
Mas continuando com o problema, acho que não da para aninhar dois has_many through (ou um has many through com um habtm) então para implementar o que tu quer, só consigo lembrar agora do finder SQL ...
Um exemplo simples, pode ser que tenha algum erro ...
class Group < ActiveRecord::Base
    has_many :group_and_things
    has_many :properties
end

class GroupAndThing < ActiveRecord::Base
  belongs_to :group
  belongs_to :thing
end


class Property < ActiveRecord::Base
  belongs_to :group
end

class Thing < ActiveRecord::Base
    has_many :group_and_things
    has_many :groups, :through => :group_and_things
    has_many :properties, :class_name => "Property", :finder_sql => 'select p.* ' +
    'from properties p ' +
    'inner join group_and_things gat on p.group_id = gat.group_id ' +
    'where gat.thing_id = #{id} '
   
end

Com isto thing.properties vai funcionar, mas não vejo problemas em usar a versão com o collect, melhor ainda se colocar em um modulo o groups.collect{|g| g.properties } e passar isto para o extend da associação de grupos, ai fica thing.groups.properties :D


Rodrigo Urubatan Ferreira Jardim
rod...@urubatan.com.br
Visite meu blog: http://www.urubatan.com.br
Blog em ingles: http://www.urubatan.info

Melhor livro de RoR do Brasil: http://livro.urubatan.com.br
Joan Crawford  - "I, Joan Crawford, I believe in the dollar. Everything I earn, I spend."

2009/11/16 Reinaldo Junior <jun...@gmail.com>

Reinaldo Junior

unread,
Nov 16, 2009, 3:04:40 PM11/16/09
to rail...@googlegroups.com

Reinaldo de Souza Junior
http://reinaldojunior.net
Se vou no console e tento:

>> coisa = Thing.first
=> #<Thing id: 1, name: "Cachorro", created_at: "2009-11-16 19:38:43", updated_at: "2009-11-16 19:39:07">

>> coisa.properties
ActiveRecord::StatementInvalid: SQLite3::SQLException: no such column: groups.thing_id: SELECT "properties".* FROM "properties"  INNER JOIN "groups" ON "properties".group_id = "groups".id    WHERE (("groups".thing_id = 1)) 


2009/11/16 Gabriel Sobrinho <gabriel....@gmail.com>

Reinaldo Junior

unread,
Nov 16, 2009, 3:08:25 PM11/16/09
to rail...@googlegroups.com

Reinaldo de Souza Junior
http://reinaldojunior.net


2009/11/16 Rodrigo Urubatan Ferreira Jardim <urub...@gmail.com>

Com isto thing.properties vai funcionar, mas não vejo problemas em usar a versão com o collect, melhor ainda se colocar em um modulo o groups.collect{|g| g.properties } e passar isto para o extend da associação de grupos, ai fica thing.groups.properties :D


Ótimo! Acho que assim ficaria ainda mais elegante...
Mas, o que seria o "extend da associação"?

Reinaldo Junior

unread,
Nov 16, 2009, 3:10:48 PM11/16/09
to rail...@googlegroups.com
2009/11/16 Rodrigo Urubatan Ferreira Jardim <urub...@gmail.com>
Só pra começar, usar has and belongs to many quase sempre não é uma boa idéia, crie um modelo de associação, por que daqui a pouco tu vai querer saber quem associou, desassociou, quando, por que, ...

Sim, eu tentei criando um modelo para a associação mas ainda assim persistiu o problema

Reinaldo Junior

unread,
Nov 16, 2009, 4:34:51 PM11/16/09
to rail...@googlegroups.com
Fiz funcionar com "Association extensions" (investiguei mais na documentação do Rails)

Mas tem um problema, quando eu faço:

thing.groups.properties sempre retorna []

Agora se eu faço:

thing.groups
e depois
thing.groups.properties

Aí retorna certo...

É assim mesmo que funciona o "Association extensions"? Ou é porque eu to usando Sqlite3?

Reinaldo de Souza Junior
http://reinaldojunior.net


2009/11/16 Reinaldo Junior <jun...@gmail.com>

Rodrigo Urubatan Ferreira Jardim

unread,
Nov 16, 2009, 6:06:22 PM11/16/09
to rail...@googlegroups.com
deveria funcionar de primeira, como ficou o teu código?

Rodrigo Urubatan Ferreira Jardim
rod...@urubatan.com.br
Visite meu blog: http://www.urubatan.com.br
Blog em ingles: http://www.urubatan.info

Melhor livro de RoR do Brasil: http://livro.urubatan.com.br
Ted Turner  - "Sports is like a war without the killing."

2009/11/16 Reinaldo Junior <jun...@gmail.com>

Rodrigo Urubatan Ferreira Jardim

unread,
Nov 17, 2009, 8:03:14 AM11/17/09
to rail...@googlegroups.com
a minha extension ficou assim:
module GroupsAssocciationExtension
    def properties
        all.collect {|g| g.properties }.flatten
    end
end
e na classe Thing

class Thing < ActiveRecord::Base
    has_many :group_and_things
    has_many :groups, :through => :group_and_things, :extend => GroupsAssocciationExtension
   
end

e funciona direto, sem problemas ...


Rodrigo Urubatan Ferreira Jardim
rod...@urubatan.com.br
Visite meu blog: http://www.urubatan.com.br
Blog em ingles: http://www.urubatan.info

Melhor livro de RoR do Brasil: http://livro.urubatan.com.br
Samuel Goldwyn  - "I'm willing to admit that I may not always be right, but I am never wrong."

2009/11/16 Reinaldo Junior <jun...@gmail.com>

Reinaldo Junior

unread,
Nov 17, 2009, 2:05:11 PM11/17/09
to rail...@googlegroups.com
Eu usei isso mesmo, mas ao inves de definir um modulo eu usei

has_many :groups, :through => :group_and_things do]
   def properties
        proxy_target.collect {|g| g.properties }
    end  
end

(fiz se mo flatten mesmo pra eu poder saber qual property é reference a qual group)
Isso proque eu segui a documentação.... Mas de onde vem esse "all" aí mágico?

Assim se eu faço 
a_thing.groups.properties
>> []

Se eu faco

a_thing.groups
>> [group1, group2]

e em seguida

a_thing.groups.properties
>> [[prop1, prop2], [prop3]]

Com group1 tendo as propriedades prop1 e prop2 e group2 tendo a prop3

Será que é porque eu to usando sqlite pra testar? Ou é por causa desse proxy_target no lugar do all?

Reinaldo de Souza Junior
http://reinaldojunior.net


2009/11/17 Rodrigo Urubatan Ferreira Jardim <urub...@gmail.com>

Rodrigo Urubatan Ferreira Jardim

unread,
Nov 17, 2009, 2:08:52 PM11/17/09
to rail...@googlegroups.com
é por causa do proxy target, se tu simplesmente tirar o proxy_target dali (não precisa nem colocar o all) vai funcionar beleza :D


Rodrigo Urubatan Ferreira Jardim
rod...@urubatan.com.br
Visite meu blog: http://www.urubatan.com.br
Blog em ingles: http://www.urubatan.info

Melhor livro de RoR do Brasil: http://livro.urubatan.com.br
Ted Turner  - "Sports is like a war without the killing."

2009/11/17 Reinaldo Junior <jun...@gmail.com>

Reinaldo Junior

unread,
Nov 18, 2009, 7:49:22 AM11/18/09
to rail...@googlegroups.com
hummm..

Muito obrigdo velho!

Agora, por favor me diga odne na documentação fala sobre esse "all", e porque o proxy_target se comporta assim? (alguém sabe?)
Reply all
Reply to author
Forward
0 new messages