2012-12-30 23 views
11

Ho un e Scarica modello Libro che condividono molti attributi, quindi il mio obiettivo è quello di ereditare gli attributi comuni da un modello DownloadableResource.
dato un'occhiata a STI, ma sono andato via abstract base model class invece:
implementazione astratta modello base di classe, il Rails Way ™

  • modelli:

    class DownloadableResource < ActiveRecord::Base 
        self.abstract_class = true 
    
        attr_accessible :title, :url, :description, :active, :position 
        validates :title, :url, :description, presence: true 
        scope :active, where(active: true).order(:position) 
    end 
    
    class Book < DownloadableResource 
        attr_accessible :cover_url, :authors 
        validates :cover_url, :authors, presence: true 
    end 
    
    class Download < DownloadableResource 
        attr_accessible :icon_url 
        validates :icon_url, presence: true 
    end 
    
  • migrazioni:

    class CreateDownloadableResources < ActiveRecord::Migration 
        def change 
        create_table :downloadable_resources do |t| 
         t.string :title 
         t.string :url 
         t.text  :description 
         t.boolean :active,  default: false 
         t.integer :position 
         t.timestamps 
        end 
        end 
    end 
    
    class CreateBooks < ActiveRecord::Migration 
        def change 
        create_table :books do |t| 
         t.string :cover_url 
         t.string :authors 
         t.timestamps 
        end 
        end 
    end 
    
    class CreateDownloads < ActiveRecord::Migration 
        def change 
        create_table :downloads do |t| 
         t.string :icon_url 
         t.timestamps 
        end 
        end 
    end 
    

Dopo la migrazione, quando ho crea un nuovo libro il risultato è lontano prevede:

> Book.new 
=> #<Book id: nil, cover_url: nil, authors: nil, created_at: nil, updated_at: nil> 

Può qualcuno si prega di far luce su come implementare la tecnica di base astratto modello di classe in modo da modelli ActiveRecord possono condividere codice comune tramite inheritance ancora essere persistiti diverse tabelle di database?

+0

Un modo è una composizione anziché un'ereditarietà. Alcuni esempi: http://rails-bestpractices.com/posts/17-extract-into-module – VadimAlekseev

+0

Come nota a margine, anche se si utilizzano due tabelle strutturate in modo simile, è possibile almeno mantenere le migrazioni ASCIUTTE prima creando tutte tabelle con solo i loro campi unici e quindi facendo qualcosa come '[: libri,: download] .each do | table | tabella change_table do | t | t.text: descrizione # ... fine fine' – Janosch

risposta

9

Dichiarando un modello come astratto si sta effettivamente dicendo che non esiste una tabella sottostante e si desidera consentire la sottoclasse. Ciò significa:

  • non ti servono tabella downloadable_resources
  • stampe Book.table_name books invece di downloadable_resources

Come @Finbarr già accennato, questo significa anche che entrambi i modelli Book e Download bisogno avere tutti gli attributi nelle loro tabelle.

Che cosa è effettivamente utile per questo? Secondo me non per molto. È possibile condividere convalide, ambiti ecc. Ma è possibile ottenere tutto ciò più facilmente includendo moduli personalizzati.

Per risolvere il tuo problema, probabilmente andrei con un approccio diverso. Creerei un altro modello chiamato DownloadableContent che sarebbe autonomo. Includerebbe le convalide e la tabella avrebbe tutti gli attributi. E infine i modelli Book e Download avrebbero una relazione polimorfa has_one con il modello DownloadableContent.

Si potrebbe andare con l'approccio STI, ma generalmente non mi piace mescolare tutti gli attributi personalizzati insieme.

5

In questo caso non dovrebbe esserci una tabella downloadable_resources. Sia le tue tabelle di libri che quelle di download dovrebbero dichiarare tutti i campi di cui hanno bisogno.

+2

Perché? Cosa rende questo caso inadatto all'eredità? E come decidere quando vale la pena ereditare e quando non lo è? –