Ruby on Rails Best practice – Big Controller vs Small Controller

Ho bisogno di alcune informazioni per le migliori pratiche in Ruby on Rails, in particolare con Controller che deve fare un sacco di cose , quindi, una semplice azione “show” ora è fino alle linee. Lo so, non è molto bello e ho un codice specifico.

Ecco un codice di esempio:

def show sound = Sound.find(params[:id]) @xml_path = File.dirname(sound.file.path) s3 = AWS::S3.new( :access_key_id => 'XXX', :secret_access_key => 'XXX') @url = s3.buckets['dev'].objects[sound.file.path[1..-1]].url_for(:read, :expires => 10*60) if sound.id_job != 0 && sound.transcript_progress != 100 @response = Savon.client("http://srap.php?wsdl").request(:avance) do soap.body = { :Jeton => "abcdef", :ID_job => sound.id_job, } end @response = @response.to_hash @progress = @response[:avance][:avancement].to_s.split("#")[1]# ID_job received is formsd like "OK#123", we keep "123" if @progress == "Termine" sound.transcript_progress = 100 elsif @progress == "ERROR" flash.now[:alert] = "Oups, il semblerait que le fichier soit illisible, ou qu'il n'y ait rien a ecouter !" elsif @progress != "Queued" sound.transcript_progress = @response[:avance_response][:avancement].to_s.split("#")[2].split("%")[0].to_i end sound.save end if sound.transcript_progress == 100 # If transcription finished # Get XML File URL on the FTP @xml_path = Savon.client("http://srap.php?wsdl").request(:donneResultat) do soap.body = { :Jeton => "XXX", :FichierSon => sound.id_job } end # Parse XML Path URL on Kimsufi @xml_path = @xml_path.to_hash[:donne_resultat_transposition_response][:chemin_fichier].to_s.split("#")[2].to_s.split("/")[5] # Create local directory (/tmp/sounds) for XML Temp Save if ! File.directory?(Rails.root.to_s + '/tmp/sounds') Dir.mkdir(Rails.root.to_s + '/tmp/sounds') end # Get XML from FTP ftp=Net::FTP.new ftp.connect("ftp.com", 21) ftp.login("XXX", "XXX") if ftp.closed? flash.now[:alert] = "Oups, il semblerait qu'il y ait eu un problème ! Merci d'actualiser la page" else ftp.passive = true ftp.chdir('results') ftp.getbinaryfile(@xml_path, Rails.root.to_s + '/tmp/sounds/' + @xml_path) ftp.close end # Send XML on S3 s3 = AWS::S3.new( :access_key_id => 'XXX', :secret_access_key => 'XXX') @xml_new = (File.dirname(@sound.file.path) + '/' + File.basename(@xml_path))[1..-1] s3.buckets['dev'].objects[@xml_new].write(Pathname.new(Rails.root.to_s + '/tmp/sounds/' + @xml_path)) @file = s3.buckets['dev'].objects[@xml_new].read() end # A lot of logic again, i've not did it yet end 

Come puoi vedere, ho un sacco di logica qui, devo controllare se la trascrizione è finita, se no, aggiorna la progress_bar (@ sound.transcript_progress), se sì, devo prima connettermi a un’azione soap per ottenere il percorso XML, quindi ottenere l’XML via FTP, quindi immagazzinarlo in Amazon S3 (Shitty SOAP, devo ripubblicare tutte le risposte …).

In tutti i miei controller di azione, devo collegarmi su S3 / SOAP / FTP, non nello stesso ordine. Quindi sto pensando di fare una lezione per ognuno, come in C ++, un’astrazione. Voglio fare le cose, non mi interessa (molto) come è fatto. Ma qual è la migliore pratica con MVC? Devo creare una nuova cartella “Class?” Un nuovo controller?

Questo è più di un commento a lungo termine , poiché spiega l’origine del tuo dilemma, ma non fornisce soluzioni.

Il problema in realtà è causato da un’interpretazione errata di MVC, che RoR rende popolare.

È la combinazione di due fattori, che stanno causando questa implosione del controller:

  • Da un lato si ha un modello anemico , perché, invece del livello del modello reale, RoR utilizza la raccolta di istanze ORM. Il motivo è che Rails è stato originariamente creato per essere un framework per la prototipazione rapida (generazione di codice throw-away). E la prototipazione è esattamente ciò a cui è meglio fare il record attivo. Utilizzando lo scaffolding, è ansible generare facilmente strutture di record attive da database esistenti.

    Ma ciò causa la perdita della logica di business del dominio nei controller.

  • Dall’altro lato hai la vista inesistente. Dal momento che l’objective era la prototipazione, Rails ha preferito eliminare le visualizzazioni, che in realtà possono contenere la logica di presentazione, unendole nei controller. Le viste, ora mancanti, sono state sostituite con semplici modelli, che sono solo chiamati “viste”.

    Ciò impone ai controller di contenere la logica di presentazione.

Questi due fattori sarebbero la ragione, perché sono tentato di affermare, che il RoR non è nemmeno un framework MVC. Il modello risultante è in realtà più vicino a Model-View-Presenter . Sebbene sia stato semplificato fino al punto in cui inizia a rompere Separation of Concerns .

La maggior parte della tua logica non appartiene al controller. La responsabilità del controllore è di bind l’input (le richieste HTTP ei loro parametri) all’output (le vostre viste). Tutto il resto è la logica di business che dovrebbe essere implementata nel modello – Il Sound nel tuo caso, sembra. Ad esempio, ognuno dei tuoi blocchi if sarebbe un buon candidato da implementare come metodo di istanza della class Sound . Se ti ritrovi a riutilizzare il codice (come il bit di archiviazione AWS) su vari modelli, implementali in un modulo (sotto lib ) e includi quel modulo in quei modelli.

Sembra che tutto ciò dovrebbe essere refactored in un modello (o in un modulo di libreria) e suddiviso in funzioni più piccole. La migliore ragione per questo è perché poi è ansible impostare i test unitari per testare singolarmente le parti più piccole. Il controller deve semplicemente creare un’istanza del modello e restituire i dati al browser.