9 Oct
matte

matte il 9 October 2006 parla di Altro

Elaborare risultati dell’ActiveRecord senza accedere al DataBase

Sicuramente vi sarà capitato di aver interrogato il DataBase e aver ottenuto un set di risultati come risposta. Ma se vi servisse effettuare un ulteriore filtraggio dei dati, come è possibile farlo evitando di accedere di nuovo al DataBase?

Supponiamo di avere tre modelli: Car, Detail, CarDetail. Qui sotto elenco le classi con le varie relazioni utilizzate.

    1 class Car < ActiveRecord::Base
    2     has_and_belongs_to_many :details
    3 end
    4 
    5 class Detail < ActiveRecord::Base
    6     has_and_belongs_to_many :cars
    7 end
    8 
    9 class CarDetail < ActiveRecord::Base
   10     belongs_to :car
   11     belongs_to :detail
   12 end

Dove un’istanza di Car rappresenta una specifica macchina e con istanze di Detail gli accessori appartenenti a tutti i veicoli. Avremo quindi 3 tabelle, cars dove ci saranno i veicoli, details per gli accessori, mentre nella tabella cars_details sarà specificato quali accessori possiede una particolare macchina.

Supponiamo di avere il sequente set di dati nelle rispettive tabelle:

Tabella cars:

    1 id: 1
    2 name: MG TF
    3 id: 2
    4 name: Toyota Corolla
    5 id: 3
    6 name: Opel Corsa

Tabella details:

    1 id: 1
    2 name: Aria Condizionata
    3 id: 2 
    4 name: Cerchi in lega

Tabella cars_details:

    1 detail_id: 1
    2 car_id: 1
    3 detail_id: 1
    4 car_id: 2
    5 detail_id: 1
    6 car_id: 3
    7 detail_id: 2
    8 car_id: 1

Per ottenere la lista di tutte le macchine con incluse le specifiche è possibile usare il comando:

    1 cars = Car.find(:all, :include => :details)

all’interno della variabile cars avremo quindi l’elenco delle vetture con i dettagli associati (è bastata una sola query per ottenere i dati dal database). Se ora mi occorressero solamente le vetture corredate di “Cerchi in lega” potrei interrogare di nuovo il database con uno dei seguenti comandi:

    1 Car.find(:all, :include => :details, :conditions => "cars_details.detail_id = 2")
    2 Car.find(:all, :include => :details, :conditions => "details.name = 'Cerchi in lega'")

o utilizzare una combinazione degli iteratori rails nei seguenti modi:

    3 cars.map{|car| car if car.details.find_all{|d| d.id== 2}!=[]}.compact
    4 cars.map{|car| car if car.details.find_all{|d| d.name=="Cerchi in lega"}!=[]}.compact

Vediamo i vantaggi che si hanno utilizzando le due istruzioni sopra (riga 3 o riga 4):

  • Si fanno solamente cicli all’interno dell’array di oggetti contenuti nella variabile cars senza accedere di nuovo al DataBase.
  • Inoltre con le istruzioni alla riga 1 o 2 oltre ad interrogare una volta di più il database si ottiene l’oggetto cercato non con tutti i dettagli ma solo con il dettaglio cercato. Per visualizzare la scheda della vettura con tutti gli accessori è necessario quindi riaccedere al DataBase una successiva volta.