Ruby Forum Italian Ruby user group > REcupero dati più associazioni Molti a molti.

Posted by Alessandro Del coco (menestra)
on 24.04.2008 15:59
Ciao a tutti,

stavo facendo delle prove su alcune tabelle che ho nel DB.
Cerco di illustrare al meglio la situazione:

USER - ROLES - OPERATIONS

Un utente può avere più ruoli, un ruolo può fare più operazioni, quindi
in pratica 2 associazioni molti-a-molti.
In più nel db ho le relative tabelle diciamo di join, roles_users e
operations_roles.

Come posso recuperare tutte le operazioni di un determinato utente, che
appartiene ad un determinato ruolo?
Io ho fatto in un detemrinato modo ma nn mi sembra per niente elegante,
avete dei consigli?

GRAZIEE!!!!
Posted by Luca Guidi (Guest)
on 24.04.2008 16:19
(Received via mailing list)
Rapidissimo, a occhio non so se funziona, aggiungi ad User:
has_many :operations, :through => :roles

http://wiki.rubyonrails.org/rails/pages/Beginner+Howto+on+has_many+:through

--
blog: www.lucaguidi.com
Pro-Netics: www.pro-netics.com
Sourcesense - making sense of Open Source: www.sourcesense.com
Posted by Stefano Cobianchi (Guest)
on 24.04.2008 16:27
(Received via mailing list)
On Apr 24, 2008, at 3:59 PM, Alessandro Del coco wrote:

> In più nel db ho le relative tabelle diciamo di join, roles_users e
> operations_roles.
>
> Come posso recuperare tutte le operazioni di un determinato utente,  
> che
> appartiene ad un determinato ruolo?

Dato che non c'e' legame diretto fra utenti e operazioni, direi che la
tua
domanda non ha molto senso... oppure non ti sei spiegato bene :-)

S.
Posted by Stefano Cobianchi (Guest)
on 24.04.2008 16:33
(Received via mailing list)
On Apr 24, 2008, at 3:59 PM, Alessandro Del coco wrote:

> In più nel db ho le relative tabelle diciamo di join, roles_users e
> operations_roles.

Ah, quindi sono in relazione molti-a-molti... ecco cosa mi era sfuggito.

>
> Come posso recuperare tutte le operazioni di un determinato utente,  
> che
> appartiene ad un determinato ruolo?
> Io ho fatto in un detemrinato modo ma nn mi sembra per niente  
> elegante,
> avete dei consigli?


In teoria "has_many :operations, :through => :roles", ma...

"You can only use a :through query through a belongs_to or has_many
association on the join model."

S.
Posted by Alessandro Del coco (menestra)
on 28.04.2008 11:09
Spiego meglio la situazione:

1) model USER

  has_and_belongs_to_many :roles
  attr_accessible :roles

2)model ROLE

  has_and_belongs_to_many :operations
  attr_accessible :operations

3)model OPERATION

  has_and_belongs_to_many :roles
  attr_accessible :roles

Premetto che l'autenticazione è gestita da RESTful Authentication che 
crea current_user quindi io ho pensato di fare in questo modo:

current_user.roles.operations

L'errore che mi da è il seguente:
undefined method `operations' for Role(id: integer, name: string):Class

Ho provato anche con :through, ma mi restituisce sempre un errore
Invalid source reflection macro :has_and_belongs_to_many for has_many 
:operations, :through => :roles.  Use :source to specify the source 
reflection.
Posted by Luca Mearelli (Guest)
on 28.04.2008 11:39
(Received via mailing list)
allora, la tua pare essere una doppia associazione molti a molti,
dunque l'has many through deve passare per i join model (N.B. con has
many through le tabelle di join devono diventare veri e propri
modelli)


class User
  has_many :roles, :through=>:user_roles
  has_many :user_roles
end

class UserRole
  belongs_to :user
  belongs_to :role
end

class Roles
  has_many :users, :through=>:user_roles
  has_many :user_roles

  has_many :operations, :through=>:role_operations
  has_many :role_operations
end

class RoleOperation
  belongs_to :role
  belongs_to :operation
end

class Operation
  has_many :roles, :through=>:role_operations
  has_many :role_operations
end

ora per trovare tutte le operations dovrebbe essere possibile
semplicemente definire nel modello User:

has_many   :operations, :through => :roles

N.B. non ho provato con una relazione tipo has_many through mentre con
la has_many semplice dal join model funziona

In alternativa puoi usare una has_many operations con un :finder_sql:

has_many   :operations, , :finder_sql =>
      'SELECT DISTINCT operations.* ' +
      'FROM operations o, role_operations ro, user_roles ur ' +
      'WHERE ur.user_id = #{id} AND ro.role_id = ur.role_id and
o.id=ro.operation_id'

ciao,
Luca
Posted by Alessandro Del coco (menestra)
on 28.04.2008 11:49
Ciao Luca,

ti ringrazio della spiegazione.
Smanettando un pò, sono riuscito ad avere lo stesso risultato 
semplicemnte facendo così:

roles = current_user.roles
@oper = roles.first.operations

Adesso sto cercando di scoprire bene il funzionamento di first.
GRAZIE!!!!

Luca Mearelli wrote:
> allora, la tua pare essere una doppia associazione molti a molti,
> dunque l'has many through deve passare per i join model (N.B. con has
> many through le tabelle di join devono diventare veri e propri
> modelli)
> 
> 
> class User
>   has_many :roles, :through=>:user_roles
>   has_many :user_roles
> end
> 
> class UserRole
>   belongs_to :user
>   belongs_to :role
> end
> 
> class Roles
>   has_many :users, :through=>:user_roles
>   has_many :user_roles
> 
>   has_many :operations, :through=>:role_operations
>   has_many :role_operations
> end
> 
> class RoleOperation
>   belongs_to :role
>   belongs_to :operation
> end
> 
> class Operation
>   has_many :roles, :through=>:role_operations
>   has_many :role_operations
> end
> 
> ora per trovare tutte le operations dovrebbe essere possibile
> semplicemente definire nel modello User:
> 
> has_many   :operations, :through => :roles
> 
> N.B. non ho provato con una relazione tipo has_many through mentre con
> la has_many semplice dal join model funziona
> 
> In alternativa puoi usare una has_many operations con un :finder_sql:
> 
> has_many   :operations, , :finder_sql =>
>       'SELECT DISTINCT operations.* ' +
>       'FROM operations o, role_operations ro, user_roles ur ' +
>       'WHERE ur.user_id = #{id} AND ro.role_id = ur.role_id and
> o.id=ro.operation_id'
> 
> ciao,
> Luca
Posted by Luca Mearelli (Guest)
on 28.04.2008 11:53
(Received via mailing list)
On Mon, Apr 28, 2008 at 11:49 AM, Alessandro Del coco 
<menestra@tele2.it> wrote:
> Ciao Luca,
>
>  ti ringrazio della spiegazione.
>  Smanettando un pò, sono riuscito ad avere lo stesso risultato
>  semplicemnte facendo così:
>
>  roles = current_user.roles
>  @oper = roles.first.operations

first ti da il primo ruolo nell'enumerable roles
dunque roles.first.operations sono le operazioni associate al primo
ruolo, i.e. se hai due ruoli con operazioni associate diverse cosi
trovi solo le operazioni del primo e non quelle del secondo.

ciao,
Luca
Posted by Alessandro Del coco (menestra)
on 28.04.2008 12:06
Grazie ancora,

ma allora non c'è qualcosa che a posto di first riprende tutti i ruoli?


Luca Mearelli wrote:
> On Mon, Apr 28, 2008 at 11:49 AM, Alessandro Del coco 
> <menestra@tele2.it> wrote:
>> Ciao Luca,
>>
>>  ti ringrazio della spiegazione.
>>  Smanettando un p�, sono riuscito ad avere lo stesso risultato
>>  semplicemnte facendo cos�:
>
>>  roles = current_user.roles
>>  @oper = roles.first.operations
> 
> first ti da il primo ruolo nell'enumerable roles
> dunque roles.first.operations sono le operazioni associate al primo
> ruolo, i.e. se hai due ruoli con operazioni associate diverse cosi
> trovi solo le operazioni del primo e non quelle del secondo.
> 
> ciao,
> Luca
Posted by Claudio Petasecca Donati (etapeta)
on 28.04.2008 14:52
Alessandro Del coco wrote:
> Grazie ancora,
> 
> ma allora non c'è qualcosa che a posto di first riprende tutti i ruoli?
> 

@oper = roles.collect {|r| r.operations}.flatten.uniq
Posted by Claudio Petasecca Donati (etapeta)
on 28.04.2008 14:54
oppure, piu' rubioso ancora:

@oper = roles.collect(&:operations).flatten.uniq
Posted by giovanni lion (Guest)
on 28.04.2008 15:49
(Received via mailing list)
Puoi aggiungere al modello User un metodo operations:

def self.operations
  roles.collect(&:operations).flatten.uniq
end

Così avrai direttamente il metodo operations per ogni istanza. Stile

pino = User.find(:first)
pino.operations (ritorna array di operations...)







- Show quoted text -
On Mon, Apr 28, 2008 at 2:54 PM, Claudio Petasecca Donati <
Posted by giovanni lion (Guest)
on 28.04.2008 17:10
(Received via mailing list)
anche se collect usato così non l'ho capito... a me dice expected Proc in
irb. Che uso è esattamente?

On Mon, Apr 28, 2008 at 3:48 PM, giovanni lion <giovanni.lion@gmail.com>
Posted by Claudio Petasecca Donati (etapeta)
on 28.04.2008 17:23
giovanni lion wrote:
> anche se collect usato cos� non l'ho capito... a me dice expected Proc in
> irb. Che uso � esattamente?
> 
> On Mon, Apr 28, 2008 at 3:48 PM, giovanni lion <giovanni.lion@gmail.com>

Rails estende la classe Symbol con un metodo to_proc:

class Symbol
  def to_proc
    Proc.new { |*args| args.shift.__send__(self, *args) }
  end
end

Chiamare
>  roles.collect(&:operations)

equivale a chiamare
>  roles.collect(:operations.to_proc)

ovvero
>  roles.collect {|r| r.send(:operations) }

quindi
>  roles.collect {|r| r.operations }

Questa estensione della classe Symbol e' definita solo in Rails, non in 
Ruby.
Sara' integrata nel prossimo Ruby 1.9

Ecco perche' non ti funziona in irb
Posted by giovanni lion (Guest)
on 28.04.2008 17:27
(Received via mailing list)
Infatti stavo giusto cercando ruby 1.9 e le novità sui lambda... Buono a
sapersi grazie!

2008/4/28 Claudio Petasecca Donati <cpetasecca@gmail.com>: