2010-02-01 9 views
6

Possiedo un modulo che consente di aggiungere file di formati diversi a uno stream. Quindi, uno stream è costituito da molti file, questi file sono file XML ma fondamentalmente hanno schemi diversi. Ho un modulo che consente all'utente di aggiungere qualsiasi file che vogliono, sto usando STI (che funziona benissimo quando i dati sono già nella tabella), il mio problema è aggiungere i dati alla tabella.Rails STI che utilizza il modulo ONE

Il modulo ha 1 campo di input, solo un file_field che consente all'utente di selezionare il file che desidera caricare. Dato che ho solo un modulo, non sono in grado di creare l'oggetto corretto, devo farlo programmaticamente .. e non sono sicuro di come farlo.

Devo solo (o posso) aggiungere un menu a discesa con i possibili tipi e chiamare quel campo 'tipo' in modo che quando il modulo viene inviato, i binari istanziano il tipo di oggetto di scrittura perché viene fornito l'attributo type?

Qual è la migliore pratica per questo .. Sto correndo rotaie 2.3.4.

risposta

3

ho trovato una soluzione al http://coderrr.wordpress.com/2008/04/22/building-the-right-class-with-sti-in-rails/#comment-1826

class GenericClass < ActiveRecord::Base 
    class << self 
    def new_with_cast(*a, &b) 
     if (h = a.first).is_a? Hash and (type = h[:type] || h['type']) and (klass = type.constantize) != self 
     raise "wtF hax!!" unless klass < self # klass should be a descendant of us 
     return klass.new(*a, &b) 
     end 

     new_without_cast(*a, &b) 
    end 
    alias_method_chain :new, :cast 
    end 
end 

Che ha funzionato benissimo con il codice minimo - non so se il suo hackish o meno ma funziona, ed è piuttosto pulito. Mi è piaciuto il fatto che le sue sole 10 righe di codice.

+1

più 1 per "wtF hax !!" – tybro0103

0

Non so quanti tipi avete ma ho semplicemente usato controller e viste separati per i diversi tipi in passato. In questo modo non crei un nuovo oggetto della classe base e provi a impostare il tipo, semplicemente usi il modello che eredita dalla classe base. Ogni nuova pagina di modifica delle risorse può rendere un partial condiviso nel blocco form_for. Il partial conterrà il tuo file_field.

In questo modo, quando il modulo viene inviato, andrà al controller corretto, chiamando la risorsa corretta. Nuovo e tutto è ok.

Lo svantaggio ovviamente sono più file e qualsiasi pagina si colleghi a "aggiungi nuovo file" è necessario aggiungere più collegamenti come "aggiungi nuovo tipo di file", "aggiungi nuovo tipo di file" ecc.

Per quanto riguarda l'impostazione del tipo nel modulo, non sono sicuro che funzioni, ne dubito ma basta provarlo (Fatecelo sapere). Potresti fare in modo che il tipo scenda un tag select e, quando modificato, usa Javascript per cambiare la posizione dell'azione sul modulo.

cura e ha aggiunto il lavoro di base intorno

Non

che mi piace questa soluzione & dubito proprio in alcun modo il migliore, ma se davvero non si vuole controller separati ed è necessario farlo voi a lavorare potrebbe fare qualcosa di simile:

class XmlFile < ActiveRecord::Base 
end 

class XmlFileTypeA < XmlFile 
end 

class XmlFileTypeB < XmlFile 
end 

def create 
    # Leaving this case statement in the controller for simplicity but you probably want to move this to the model 
    case params[:chosen_xml_type] 
     when "file_type_a" 
     @item = XmlFileTypeA.new(params) 
     when "file_type_b" 
     @item = XmlFileTypeB.new(params) 
     else 
     raise "Unknown file type!" 
     etc 
    end 
end 
+0

Sì, volevo davvero evitare di creare un controller separato per ciascuno, anche se attualmente ho solo due tipi di documento, potrebbe diventare più, rapidamente. Rails rende semplicissimo implementare lo STI .. e lo è - ma solo per recuperare informazioni non riesco nemmeno a trovare un esempio di un "nuovo" modulo per un'implementazione STI. – Rabbott

+0

Vedere il mio post modificato, la nuova azione che rende la vista creerebbe @xml_file = XmlFile.new, l'azione create creerebbe il tipo di file giusto per te in base alla scelta dell'utente. Spero che sia chiaro come fango !? – tsdbrown

+0

Questo sta diventando molto più vicino, grazie per l'aggiornamento! Poiché il controller è ciò che effettivamente istanzia l'oggetto, non dovrebbe rimanere lì? Penso che, dopo tutta questa ricerca, quello che sto cercando sia il metodo con cui puoi chiamare classify.constanize.new o qualcosa del genere ... qualsiasi idea di cosa sto parlando. Puoi usare il valore dal menu a discesa e creare un oggetto di quel tipo. – Rabbott

Problemi correlati