Ruby on Rails最佳实践 - 大型控制器与小型控制器

时间:2012-08-16 09:35:21

标签: ruby-on-rails ruby model-view-controller ruby-on-rails-3.2

我需要一些关于Ruby on Rails中最佳实践的信息,特别是需要做很多事情的控制器的信息,所以,一个简单的“show”动作现在符合要求。我知道,它不是很好,我有特定的代码。

以下是示例代码:

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

正如你所看到的,我在这里有很多逻辑, 我要检查转录是否结束,      如果没有,请更新progress_bar(@ sound.transcript_progress),      如果是的话,我首先必须连接到soap动作以获取XML路径,然后通过FTP获取XML,然后将其存储到Amazon S3(Shitty SOAP,我必须重新解析所有响应......)。

  

在我的所有动作控制器中,我必须连接S3 / SOAP / FTP,而不是   按照相同的顺序..所以我想我为每个人做一个课,比如   C ++,一种抽象。我想要完成的东西,我不关心(很多)如何   完成。但是MVC的最佳实践是什么?我必须做一个   新文件夹“Class?”一个新的控制器?

3 个答案:

答案 0 :(得分:7)

  

这更像是一个长篇评论,因为它解释了你的困境的根源,但没有提供任何解决方案。

问题实际上是由于错误解释了MVR,RoR普及了。

这是两个因素的组合,导致控制器内爆:

  • 一方面你有anemic model,因为RoR使用的是ORM实例的集合,而不是真正的模型层。原因在于Rails最初是为快速原型设计(生成抛弃代码)而创建的。原型设计正是活跃记录最擅长的。使用scaffolding,您可以轻松地从现有数据库生成活动记录结构。

    但是这会导致某些域业务逻辑泄漏到您的控制器中。

  • 另一方面,您有不存在的视图。由于目标是原型设计,Rails倾向于通过将视图合并到控制器中来摆脱实际上包含表示逻辑的视图。现在缺少的视图被简单的模板替换,这些模板被称为“视图”。

    这会强制控制器包含表示逻辑。

这两个因素将是我为什么试图断言的原因,即RoR甚至不是MVC框架。生成的模式实际上更接近Model-View-Presenter。虽然它已被简化到它开始破坏的地步Separation of Concerns

答案 1 :(得分:5)

您的大部分逻辑都不属于控制器。控制器的职责是将输入(HTTP请求及其参数)与输出(您的视图)联系起来。其他一切都是应该在模型中实现的业务逻辑 - 在您的情况下Sound,它看起来像。例如,每个if块都可以作为Sound类的实例方法实现。如果您发现自己在各种模型中重用代码(如AWS存储位),请在Modulelib下)实现它们,并在该模型中包含该模块。

答案 2 :(得分:0)

看起来所有这些都应该重构为模型(或库模块)并分解为更小的函数。最好的原因是因为您可以设置单元测试来单独测试较小的部件。控制器只需要实例化模型并将数据返回给浏览器。