Mejores prácticas de Ruby on Rails: controlador grande frente a controlador pequeño

Necesito información sobre las mejores prácticas en Ruby on Rails, especialmente con Controller que tiene que hacer muchas cosas , por lo tanto, una simple acción de “mostrar” ahora depende de las líneas. Lo sé, no es realmente bueno, y tengo un código específico.

Aquí hay un código de muestra:

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 formed 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 

Como puede ver, tengo mucha lógica aquí, tengo que verificar si la transcripción se ha terminado, si no, actualice la barra de progreso (@ sound.transcript_progress), si es así, primero tengo que conectarme a una acción de soap para obtener la ruta XML, luego obtenga el XML a través de FTP, luego almacénelo en Amazon S3 (Shitty SOAP, tengo que volver a analizar toda la respuesta …).

En todo mi controlador de acción, tengo que conectarme en S3 / SOAP / FTP, no en el mismo orden … Así que estoy pensando en hacer una clase para cada uno, como en C ++, una abstracción. Quiero hacer las cosas, no me importa (mucho) cómo se hace. Pero, ¿cuál es la mejor práctica con el MVC? Tengo que hacer una nueva carpeta “¿Clase?” Un nuevo controlador?

Este es más un comentario largo , ya que explica el origen de su dilema, pero no brinda ninguna solución.

El problema en realidad es causado por la mala interpretación de MVC, que RoR populariza.

Es la combinación de dos factores que están causando esta implosión de controlador:

  • Por un lado, tiene un modelo anémico , porque, en lugar de la capa del modelo real, RoR usa la colección de instancias ORM. La razón de esto es que Rails se creó originalmente para ser un marco para el prototipado rápido (generación de código descartable). Y la creación de prototipos es exactamente lo que mejor hace el registro activo. Con el uso de andamios, puede generar fácilmente estructuras de registros activos a partir de bases de datos existentes.

    Pero esto hace que parte de la lógica comercial del dominio se filtre en sus controladores.

  • En el otro lado, tienes la vista inexistente. Dado que el objective era la creación de prototipos, Rails favoreció la eliminación de las vistas, que en realidad pueden contener la lógica de presentación, al fusionarlas en los controladores. Las vistas, que ahora faltaban, se reemplazaron por plantillas simples, que simplemente se llaman “vistas”.

    Esto fuerza a los controladores a contener la lógica de presentación.

Estos dos factores serían la razón, por la que estoy tentado de afirmar, de que RoR ni siquiera es el marco MVC. El patrón resultante en realidad está más cerca de Model-View-Presenter . Aunque se ha simplificado hasta el punto en que comienza a romper la Separación de preocupaciones .

La mayor parte de tu lógica no pertenece al controlador. La responsabilidad de los controladores es vincular la entrada (solicitudes HTTP y sus parámetros) a la salida (sus puntos de vista). Todo lo demás es lógica de negocios que debería implementarse en el modelo: Sound en tu caso, parece. Cada uno de sus bloques if , por ejemplo, sería un buen candidato para implementar como un método de instancia de la clase Sound . Si se encuentra reutilizando el código (como el bit de almacenamiento de AWS) en varios modelos, impleméntelos en un Módulo (en lib ) e incluya ese módulo en esos modelos.

Parece que todo eso debe refactorizarse en un modelo (o módulo de biblioteca) y dividirse en funciones más pequeñas. La mejor razón para esto es porque luego puede configurar pruebas unitarias para probar las partes más pequeñas individualmente. El controlador simplemente necesita crear una instancia del modelo y devolver los datos al navegador.