2010-01-25 17 views
17

Ho un modello che rappresenta un elemento Content che contiene alcune immagini. Il numero di immagini è fisso in quanto questi riferimenti di immagine sono molto specifici per il contenuto. Ad esempio, il modello Content si riferisce al modello Image due volte (immagine del profilo e immagine di sfondo). Sto cercando di evitare un generico has_many e di rimanere su più has_one. L'attuale struttura del database è simile a:Rails has_one vs belongs_to semantics

contents 
    - id:integer 
    - integer:profile_image_id 
    - integer:background_image_id 

images 
    - integer:id 
    - string:filename 
    - integer:content_id 

Non riesco proprio a capire come configurare correttamente le associazioni qui. Il modello Content potrebbe contenere due riferimenti belongs_to a uno Image, ma ciò non sembra semanticamente corretto perché idealmente un'immagine appartiene al contenuto o, in altre parole, il contenuto ha due immagini.

questo è il migliore che potevo pensare (rompendo la semantica):

class Content 
    belongs_to :profile_image, :class_name => 'Image', :foreign_key => 'profile_image_id' 
    belongs_to :background_image, :class_name => 'Image', :foreign_key => 'background_image_id' 
end 

io sono lontano, e un modo migliore per raggiungere questa associazione?

risposta

22

La risposta più semplice è quello di impostare le vostre associazioni in senso inverso di quello che hai, in questo modo:

# app/models/content.rb 
class Content < ActiveRecord::Base 
    has_one :profile_image, :class_name => 'Image' 
    has_one :background_image, :class_name => 'Image' 
end 

# app/models/image.rb 
class Image < ActiveRecord::Base 
    belongs_to :content 
end 

Non è necessario le chiavi esterne 'background_image_id' e 'profile_image_id' nella tabella dei contenuti a tutti .

Tuttavia, esiste una soluzione più elegante: ereditarietà di tabella singola. Configuralo ora nel caso in cui desideri che le immagini di sfondo e di profilo si comportino in modo leggermente diverso in futuro, in più chiarirà il tuo codice oggi.

In primo luogo, aggiungere una colonna alle immagini tabella denominata Tipo:

# command line 
script/generate migration AddTypeToImages type:string 
rake db:migrate 

Ora configurare i modelli in questo modo:

# app/models/content.rb 
class Content < ActiveRecord::Base 
    has_one :profile_image 
    has_one :background_image 
end 

# app/models/image.rb 
class Image < ActiveRecord::Base 
    belongs_to :content 
end 

# app/models/background_image.rb 
class BackgroundImage < Image 
    # background image specific code here 
end 

# app/models/profile_image.rb 
class ProfileImage < Image 
    # profile image specific code here 
end 

ora si può fare ogni genere di cose come ottenere un elenco di tutte le immagini di sfondo:

# script/console 
BackgroundImage.all 

Questo è più fedele al modello di dati che si sta tentando di creare, consente l'espandibilità più facile in futuro e offre oggi nuovi metodi interessanti.

UPDATE:

allora ho creato un articolo del blog chiamato Single-Table Inheritance with Tests che va in modo più dettagliato, e copre il test.

+0

L'ereditarietà di una tabella singola funziona perfettamente per il mio problema. Sai come integrarei STI con le associazioni polimorfiche? Ad esempio, se insieme al contenuto, c'erano alcune immagini che facevano parte dei metadati del documento e entrambe le immagini del contenuto e dei metadati sono state memorizzate nella tabella delle immagini. – Anurag

+0

grazie mille per l'articolo. questo deve essere il miglior articolo su Single Table Ereditarietà per Rails in rete! – Anurag

+0

Per la 'risposta semplice', in che modo il Contenuto sa quali immagini fare riferimento se non ci sono chiavi esterne nella sua tabella db? – greg7gkb

1

Basato su the AR associations guide, penso che dovresti usare has_one. Non ha senso che un'immagine possieda un Contenuto ... il Contenuto sicuramente possiede l'immagine. Dalla guida:

La distinzione è in dove si posiziona la chiave esterna (si va sul tavolo per la classe che dichiara l'belongs_to associazione), ma si dovrebbe dare qualche pensiero al significato effettivo di anche i dati . La relazione has_one dice che uno di qualcosa è il tuo - cioè, che qualcosa rimanda a tu.

Infine, non sono sicuro che sia il contenuto sia le immagini abbiano le chiavi esterne. Finché le immagini fanno riferimento a content_id, penso che tu stia bene.

Problemi correlati