Associazioni has many through: qualcu no mi può dare una dritta?

Ciao a tutti,

ho qualche problemino con le associazioni has_many :through.

Si tratta di questo:

ammettiamo di avere siti e applicazioni con una associazione many to
many via through association (perchè nella tabella di link devo gestire
altre proprietà):

Siti: id, name

class Site < ActiveRecord::Base
has_many :link_site_apps, :dependent => :destroy
has_many :apps, :dependent => :destroy, :through => :link_site_apps
end

Applicazioni: id, name

class App < ActiveRecord::Base
has_many :link_site_apps, :dependent => :destroy
has_many :sites, :dependent => :destroy, :through => :link_site_apps
end

Collegamento siti/applicazioni: site_id, app_id, is_active (boolean)

class LinkSiteApp < ActiveRecord::Base
belongs_to :app
belongs_to :site
end

  1. Se provo ad associare le prime 3 applicazioni al sito mediante

site = Site.find(1)
site.apps = App.find([1,2,3])
site.save!

non ottengo alcun errore ma non scrive nulla nel db, mentre con:

site.apps << App.find([1,2,3])

funziona, ma se voglio aggiornare le associazioni impostando solo le
prime 2 applicazioni si rende necessario eseguire prima:

site.link_site_apps.delete_all (NB: DEVO USARE IL LINK PERCHÈ ESEGUENDO
site.apps.delete_all MI VA IN ERRORE…)

e poi il ricaricamento con

site.apps << App.find([1,2])

dovendo obbligatoriamente passare per il “link di associazione”
(link_site_apps) e questo non lo capisco perchè con habtm era
sufficiente assegnare site.apps e tutto funzionava correttamente…

  1. Con rails 1.2.x nella view era sufficiente impostare l’input per le
    associazioni many to many con nome “app_ids[]” e tutto andava liscio, se
    faccio questo con “through association” se ne sbatte altamente (penso
    per il problema al punto 1) e quindi sono costretto ad intervenire
    eliminando prima tutte le associazioni (site.link_site_apps.delete_all)
    e poi ricaricando le apps (site.apps << App.find(params[:app_ids])); mi
    chiedo quindi quali sono le “best practices” di view e controller per
    gestire al meglio le associazioni multiple “through” (mi piacerebbe
    intervenire in memoria prima del salvataggio del model come si faceva
    con habtm (site.apps = App.find…) perchè eseguire il delete_all e poi
    l’inserimento tramite << presuppone che l’oggetto sia già stato salvato
    e quindi mi forza ad utilizzare le transazioni per essere certo che a
    metà strada si possa eseguire il rollback…

Qualcuno sa darmi qualche dritta ?

Grazie in anticipo !

ho qualche problemino con le associazioni has_many :through.

has_many :link_site_apps, :dependent => :destroy
Collegamento siti/applicazioni: site_id, app_id, is_active (boolean)
site.save!

faccio questo con “through association” se ne sbatte altamente (penso

Qualcuno sa darmi qualche dritta ?

Grazie in anticipo !

Secondo me hai un po’ troppi :dependent => :destroy

site.apps.delete_all non ti funziona perchè se distruggi le quelle apps,
distrugge anche se stesso, visto che hai :dependent => :destroy da tutte
e
due le parti.

Credo che vada messo solo sulle associazioni verso :link_site_apps.

Se non ti va il delete, l’assegnazione con site.apps = App.find…
potrebbe
non funzionare in quanto usa quel metodo.

On Feb 22, 2008, at 10:36 AM, Gianluca T. wrote:

has_many :link_site_apps, :dependent => :destroy

  1. Se provo ad associare le prime 3 applicazioni al sito mediante

site = Site.find(1)
site.apps = App.find([1,2,3])
site.save!

non ottengo alcun errore ma non scrive nulla nel db, mentre con:

site.apps << App.find([1,2,3])

Mi sa che funziona perche’ LinkSiteApp non ha altri attributi non-
nullable a parte le foreign key… o mi sbaglio?

dovendo obbligatoriamente passare per il “link di associazione”
(link_site_apps) e questo non lo capisco perchè con habtm era
sufficiente assegnare site.apps e tutto funzionava correttamente…

Se la memoria non mi inganna con habtm succede esattamente la stessa
cosa (i record di collegamento vengono
cancellati e ricreati).
Con hmt la tabella intermedia e’ un’entita’ vera e propria, per cui
non puoi far finta che non esista… va
bene che ActiveRecord fa un uso estensivo di magia nera, ma non e’
ancora un framework paragnosta :slight_smile:
Io di solito scrivo dei metodi espliciti per gestire queste relazioni:

(avvertimento: implementazione MOLTO MOLTO grezza :slight_smile:

class Site
def has_app?(app)
link_site_apps.find_by_app_id(app.id) != nil
end

def add_app(app, link_attributes={})
link_site_apps.create({:app => app}.merge(link_attributes)) unless
has_app?(app)
end

def remove_app(app)
if link = link_site_apps.find_by_app_id(app.id)
link.destroy
end
end
end

S.

On Feb 22, 2008, at 10:36 AM, Gianluca T. wrote:

Siti: id, name

class Site < ActiveRecord::Base
has_many :link_site_apps, :dependent => :destroy
has_many :apps, :dependent => :destroy, :through => :link_site_apps
end

dimenticavo: il :dependent => :destroy sulla seconda relazione e’
sbagliato (se una App
puo’ appartenere a piu’ Site, come deduco dal fatto che non sono in
relazione diretta)

Applicazioni: id, name

class App < ActiveRecord::Base
has_many :link_site_apps, :dependent => :destroy
has_many :sites, :dependent => :destroy, :through => :link_site_apps
end

Come ha fatto notare giovanni, qui tutti vogliono distruggere tutti :slight_smile:
Idem come sopra, il secondo :dependent non ci va.
Inoltre se non devi implementare una logica particolare di
cancellazione, e’ meglio
se usi :delete_all (o meglio ancora, affidati alle foreign key del
database).

S.

giovanni lion ha scritto:

class Site < ActiveRecord::Base

site.apps = App.find([1,2,3])
site.apps.delete_all MI VA IN ERRORE…)
associazioni many to many con nome “app_ids[]” e tutto andava liscio, se
metà strada si possa eseguire il rollback…
site.apps.delete_all non ti funziona perchè se distruggi le quelle apps,
http://lists.ruby-it.org/mailman/listinfo/ml

Grazie per avermi fatto notare l’errore, in effetti hai ragione, avevo
introdotto per errore la cancellazione in cascata anche nella relazione
through !

L’ho eliminata su entrambe le classi ma il problema rimane, non riesco
ad assegnare site.apps = App.find([1,2,3]), la cosa fantastica è che
durante il site.save! non ricevo alcun errore e con habtm funziona
perfettamente…

Sulle tue applicazioni come gestisci hmt al momento dell’aggiornamento
delle associazioni nel controller ?

Stefano C. ha scritto:

many via through association (perchè nella tabella di link devo
Applicazioni: id, name
belongs_to :site
site.apps << App.find([1,2,3])

Mi sa che funziona perche’ LinkSiteApp non ha altri attributi non-
nullable a parte le foreign key… o mi sbaglio?

No non ti sbagli infatti la classe di collegamento mi genera
correttamente i valori di default e le associazioni sono ok…

site.apps << App.find([1,2])

dovendo obbligatoriamente passare per il “link di associazione”
(link_site_apps) e questo non lo capisco perchè con habtm era
sufficiente assegnare site.apps e tutto funzionava correttamente…

Se la memoria non mi inganna con habtm succede esattamente la stessa
cosa (i record di collegamento vengono
cancellati e ricreati).

Si ma però è la forma che è diversa: con habtm ricordo che facevo:

site.apps = App.find(params[:app_ids])

e poi al site.save! si arrangiava lui a distruggere e ricreare qui
invece devo prima fare in modo che site sia salvato e poi devo prima
eliminare le associazioni e poi riassociare tutto con << ma se qualcosa
mi va male in mezzo a queste operazioni (es. dopo l’eliminazione) devo
poter fare rollback e il tutto diventa complicato da gestire soprattutto
se sto utilizzando make_resourceful plugin e sto intervenendo su punti
di estensione tipo before_create…

link_site_apps.find_by_app_id(app.id) != nil
end

end
end

S.

anche tu vai da eseguire metodi che lavorano direttamente sul db e
quindi ad oggetto già salvato mi sembra di capire…

class Site < ActiveRecord::Base

site.apps = App.find([1,2,3])
site.apps.delete_all MI VA IN ERRORE…)
associazioni many to many con nome “app_ids[]” e tutto andava liscio,
e quindi mi forza ad utilizzare le transazioni per essere certo che a


L’ho eliminata su entrambe le classi ma il problema rimane, non riesco
ad assegnare site.apps = App.find([1,2,3]), la cosa fantastica è che
durante il site.save! non ricevo alcun errore e con habtm funziona
perfettamente…

Sulle tue applicazioni come gestisci hmt al momento dell’aggiornamento
delle associazioni nel controller ?

Ora uso resource_controller e i miei controller sono
così:
class Admin::OptionsController < ResourceController::Base

belongs_to :plan

#dopo la creazione aggiungo all’array del parent
create.after do
@plan.options.push @option if parent_model ||= :plan
end

#questo è necessario per inizializzare un oggetto perche hmt altrimenti si
arrabbia
private
def build_object
@object ||= Option.new object_params
end
end

class Admin::PlansController < ResourceController::Base
end

I modelli invece:

class Option < ActiveRecord::Base
has_many :compatibilities, :dependent => :destroy
has_many :plans, :through => :compatibilities
end

class Plan < ActiveRecord::Base
has_many :compatibilities, :dependent => :destroy
has_many :options, :through => :compatibilities
end

class Compatibility < ActiveRecord::Base
belongs_to :plan
belongs_to :option
end

Mi sembra di capire che tu per caricare le associazioni plan-options vai
a inserirle direttamente utilizzando il controller options e le view
correlate…

Prendendo il tuo caso io volevo gestire l’inserimento del plan con le
associazioni dirette alle options prese ad esempio da un select multiplo
direttamente nella view del plan e non andare su un controller/view
diverso…

Il controller lo fai comunque. Poi con il form fai un bel post al
controller
nestato di option ( form_for Option.new, plan_options_path(@plan) do
blabla…, visto che è in post lo manda a create) e dopo il create ti fai
ridirigere indietro.

Oppure usi attribute_fu… ma non so come si comporti con le hmt

Il succo è: non è importante dove renderizzi il form, basta che lo fai
postare nel posto giusto :slight_smile:

Devo scappareeeee…

giovanni lion ha scritto:

end
site = Site.find(1)
site.link_site_apps.delete_all (NB: DEVO USARE IL LINK PERCHÈ ESEGUENDO
2) Con rails 1.2.x nella view era sufficiente impostare l’input per le
intervenire in memoria prima del salvataggio del model come si faceva

end

class Option < ActiveRecord::Base
belongs_to :plan
belongs_to :option
end


Ml mailing list
[email protected]
http://lists.ruby-it.org/mailman/listinfo/ml

Grazie 1000.

Mi sembra di capire che tu per caricare le associazioni plan-options vai
a inserirle direttamente utilizzando il controller options e le view
correlate…

Prendendo il tuo caso io volevo gestire l’inserimento del plan con le
associazioni dirette alle options prese ad esempio da un select multiplo
direttamente nella view del plan e non andare su un controller/view
diverso…

Mi spiego meglio, se devo fare una applicazione in cui devo associare i
ruoli ad un utente, risulta molto più comodo (all’amministratore) andare
in inserimento/modifica del nuovo utente e nella stessa videata avere
sia i dati dell’utente sia un select multiplo in cui seleziono tutti i
ruoli da assegnare all’utente, poi nel salvataggio viene salvato sia
l’utente che le associazioni hmt…

Sono io che mi complico la vita o è plausibile gestire una situazione
del genere ?

Ti chiedo un’altra paio di cose:

Hai provato ad esporre xml mediante resource controller ?

Anche a te chiede di creare una view per esporre l’xml ?

Se a te non la chiede al limite provo anche io a passare a
resource_controller… (sono passato a make_resourceful perchè non
riuscivo a generare xml senza passare obbligatoriamente per una view…)

giovanni lion ha scritto:

Devo scappareeeee…

Sono io che mi complico la vita o è plausibile gestire una situazione
riuscivo a generare xml senza passare obbligatoriamente per una view…)

Ok grazie 1000 e buon weekend…


Gianluca T.
TreNetMediaMaster S.r.l.
The Internet Technology Company
Telefono +39(049)776196
Fax +39(049)8087806
Visit us @: http://www.trenet.it - http://www.mediamaster.it
e-mail me @: [email protected]