3

Ruby on Rails でのベスト プラクティスに関する情報が必要です。特にController では多くのことを行う必要があるため、単純な「表示」アクションは行数までです。私はそれが本当に良くないことを知っています、そして私はそれに特定のコードを持っています。

サンプルコードは次のとおりです。

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 にストックします (くだらない SOAP、すべての応答を再解析する必要があります...)。

私のすべてのアクションコントローラーで、同じ順序ではなく、S3 / SOAP / FTPに接続する必要があります..だから、C ++のように、抽象化であるそれぞれのクラスを作成することを考えています。私は物事を成し遂げたい、私はそれがどのように行われたか(あまり)気にしません. しかし、MVC のベスト プラクティスは何ですか? 新しいフォルダ「Class?」を作成する必要があります。新しいコントローラー?

4

3 に答える 3

7

これは、ジレンマの原因を説明しているが、解決策を提供していないため、より長い形式のコメントです。

この問題は実際には、RoR が普及している MVC の誤解によって引き起こされます。

このコントローラーの内破を引き起こしているのは、次の 2 つの要因の組み合わせです。

  • 一方では、実際のモデル レイヤーの代わりに RoR が ORM インスタンスのコレクションを使用するため、貧血モデルがあります。その理由は、Rails はもともと高速プロトタイピング (使い捨てコードの生成) のためのフレームワークとして作成されたからです。そしてプロトタイピングは、まさにアクティブレコードが得意とするところです。スキャフォールディングを使用すると、既存のデータベースからアクティブなレコード構造を簡単に生成できます。

    ただし、これにより、ドメイン ビジネス ロジックの一部がコントローラーでリークします。

  • 反対側には、存在しないビューがあります。目標はプロトタイピングだったので、Rails はコントローラーにマージすることで、実際にプレゼンテーション ロジックを含むことができるビューを取り除くことを好みました。現在欠落しているビューは、単に「ビュー」と呼ばれる単純なテンプレートに置き換えられました。

    これにより、コントローラーにプレゼンテーション ロジックが含まれるようになります。

これらの 2 つの要因が、RoR は MVC フレームワークでさえないと断言したくなる理由です。結果のパターンは、実際にはModel-View-Presenterに近いものになります。懸念の分離を破り始めるところまで単純化されていますが。

于 2012-08-16T09:52:37.847 に答える
5

ロジックのほとんどはコントローラーに属していません。コントローラーの責任は、入力 (HTTP 要求とそのパラメーター) を出力 (ビュー) に結び付けることです。他のすべては、モデルに実装する必要があるビジネス ロジックですSound。あなたの場合は、次のようになります。ifたとえば、各ブロックは、Soundクラスのインスタンス メソッドとして実装するのに適しています。さまざまなモデルでコード (AWS ストレージ ビットなど) を再利用している場合は、それらをモジュール( の下lib) に実装し、そのモジュールをそれらのモデルに含めます。

于 2012-08-16T09:46:57.053 に答える
0

これらすべてをモデル (またはライブラリ モジュール) にリファクタリングし、より小さな関数に分割する必要があるようです。これの一番の理由は、単体テストをセットアップして小さなパーツを個別にテストできるからです。コントローラーは、モデルをインスタンス化し、データをブラウザーに返すだけで済みます。

于 2012-08-16T12:17:05.270 に答える