Ruby
 Computer >> コンピューター >  >> プログラミング >> Ruby

すべての苦痛なしで`Respond_to`

Railsでスキャフォールドを生成すると、通常のrespond_toが表示されます。 ブロック:

app / controllers / tasks_controller.rb
  def destroy
    @task.destroy
    respond_to do |format|
      format.html { redirect_to tasks_url, notice: 'Task was successfully destroyed.' }
      format.json { head :no_content }
    end
  end

ただし、indexなどの一部のアクション 、持っていない!

app / controllers / tasks_controller.rb
  # GET /tasks
  # GET /tasks.json
  def index
    @tasks = Task.all
  end

これは悪いです。なんで? /tasks.txtを押した場合 、およびtxt アプリでサポートされていない場合、間違ったエラーが発生します:

ActionView::MissingTemplate (Missing template tasks/index, application/index with {:locale=>[:en], :formats=>[:text], :variants=>[], :handlers=>[:erb, :builder, :raw, :ruby, :coffee, :jbuilder]}

これは正しくありません。 適切なファイルが見つからないということではなく、サポートしていない形式を要求していることをクライアントに伝える必要があります。

これがUnknownFormatの場合 エラーの場合は、より適切な応答コードを返すことができます。代わりに、これらのエラーは他の無関係なエラーと混ざり合い、処理が非常に困難になります。

respond_toを追加できます indexにブロックする アクション:

app / controllers / tasks_controller.rb
  # GET /tasks
  # GET /tasks.json
  def index
    @tasks = Task.all
    respond_to do |format|
      format.html
      format.json
    end
  end

次に、予想される例外とエラーコードを取得します。

Started GET "/tasks.txt" for 127.0.0.1 at 2014-11-03 22:05:12 -0800
Processing by TasksController#index as TEXT
Completed 406 Not Acceptable in 21ms

ActionController::UnknownFormat (ActionController::UnknownFormat):
  app/controllers/tasks_controller.rb:8:in `index'

ずっといい。 ただし、すべてのコントローラーにrespond_toを散らかす クレイジーです。 レールっぽくない感じがします。 DRYに違反します。そして、それはあなたのコントローラーが実際に行っている仕事からあなたをそらします。

あなたはまだ悪いフォーマットを正しく扱いたいです。それで、あなたは何をしますか?

respond_to ショートカット

オブジェクトをレンダリングするために特別なことを何もしていない場合は、ショートカットを使用できます。あなたが書く場合:

app / controllers / tasks_controller.rb
def index
  @tasks = Task.all
  respond_to :html, :json
end

完全なrespond_toを作成するのと同じように機能します indexのブロック 。 これは、アクションが認識しているすべての形式についてRailsに伝えるための簡単な方法です。 また、さまざまなアクションがさまざまな形式をサポートしている場合、これは多くのコードなしでそれらの違いを処理するための良い方法です。

コントローラーレベルでフォーマットを処理する

ただし、通常、コントローラーの各アクションは同じで機能します。 フォーマット。 indexの場合 jsonに応答します 、new 、およびcreate 、およびその他すべて。 respond_toがあればいいのにと思います これはコントローラー全体に影響します:

app / controllers / tasks_controller.rb
class TasksController < ApplicationController
  before_action :set_task, only: [:show, :edit, :update, :destroy]
  respond_to :html, :json

  # GET /tasks
  # GET /tasks.json
  def index
    @tasks = Task.all
    respond_with(@tasks)
  end

そしてこれは実際に機能します:

Started GET "/tasks.txt" for 127.0.0.1 at 2014-11-03 22:17:37 -0800
Processing by TasksController#index as TEXT
Completed 406 Not Acceptable in 7ms

ActionController::UnknownFormat (ActionController::UnknownFormat):
  app/controllers/tasks_controller.rb:8:in `index'

まさに私たちが望んでいた種類のエラーです!そして、それを行うために各アクションを台無しにする必要はありませんでした。

モデルの状態に応じて、さまざまなことをしたい場合があります。 たとえば、createの場合 、モデルが有効かどうかに応じて、フォームをリダイレクトまたは再レンダリングします。

Railsはこれを処理できます。ただし、respond_withを使用して、チェックするオブジェクトを指定する必要があります。 。代わりに:

app / controllers / tasks_controller.rb
  def create
    @task = Task.new(task_params)

    respond_to do |format|
      if @task.save
        format.html { redirect_to @task, notice: 'Task was successfully created.' }
        format.json { render :show, status: :created, location: @task }
      else
        format.html { render :new }
        format.json { render json: @task.errors, status: :unprocessable_entity }
      end
    end
  end

あなたが書くことができます:

app / controllers / tasks_controller.rb
  def create
    @task = Task.new(task_params)
    flash[:notice] = "Task was successfully created." if @task.save
    respond_with(@task)
  end

このようにして、応答する形式からコードを分離します。 Railsに1回伝えることができます 処理するフォーマット。すべてのアクションでそれらを繰り返す必要はありません。

レスポンダーの宝石

Rails 4.2には、キャッチがあります:respond_with 含まれなくなりました。 ただし、respondersをインストールすると、元に戻すことができます 宝石。 そしてresponders gemには、他にもいくつかの優れた機能があります。

フラッシュメッセージはrespond_withで設定できます responders :flashを含めることによって コントローラの上部:

app / controllers / tasks_controller.rb
class TasksController < ApplicationController
  responders :flash

便利なことに、ロケールファイルでこれらのフラッシュメッセージのデフォルトを設定できます。

また、respondersがいる場合 Gemfile内のgem Railsスキャフォールドを生成すると、ジェネレーターはrespond_withを使用してコントローラーを作成します respond_toの代わりに :

app / controllers / tasks_controller.rb
class TasksController < ApplicationController
  before_action :set_task, only: [:show, :edit, :update, :destroy]
  respond_to :html, :json
  
  def index
    @tasks = Task.all
    respond_with(@tasks)
  end

  def show
    respond_with(@task)
  end

  # ...

これは、Railsに付属している足場よりもはるかにクリーンです。

最後に、特定のコントローラーアクションの形式でのみ応答する場合は、respond_toを呼び出すことができます。 複数回:

class TasksController < ApplicationController
  respond_to :html
  respond_to :js, only: :create
end

最後のヒントのコメントでJeroenWeeinkに感謝します!

respond_with またはrespond_to

さまざまな形式でさまざまな情報を返したい場合は、いくつかのオプションがあります。 コントローラーレベルのrespond_to respond_withと組み合わせる 短いコントローラーを取得するための優れた方法です。ただし、すべてのコントローラーアクションが同じ形式に応答し、Railsが期待する方法で動作する場合に最も役立つ傾向があります。

ただし、場合によっては、動作が異なるいくつかのアクションを実行できるようにしたいことがあります。ワンライナーrespond_to そのような状況に対処するのに最適です。

さらに制御が必要な場合は、完全なrespond_toを使用してください ブロックを使用すると、各フォーマットを好きなように処理できます。

これらのいずれかを使用すると、サポートされていない形式のリクエストで正しいエラーが発生します。また、アプリとそのクライアントの両方が混乱することはほとんどありません。


  1. MongoDBコレクションのすべての名前を取得します

    元々は2019年1月18日にObjectRocket.com/blogで公開されました。 スキーマを検証したり、フィールドのタイプミスをデバッグしたり、設定すべきでないフィールドを見つけたりするには、MongoDB®コレクションのすべてのキーを理解する必要があります。 ObjectRocketを含む多くのMongoDB-as-a-Service企業は、ユーザーインターフェイス(UI)でこれを行う簡単な方法を提供しています。経験豊富なMongoDBusersは通常、MongooseforJavaScript®やMongoengineforPython®などのオブジェクトドキュメントマッパ

  2. MongoDBコレクション内のすべてのキーの名前を取得する

    スキーマを検証したり、フィールドのタイプミスをデバッグしたり、設定されていないフィールドを見つけたりするには、MongoDBコレクションのすべてのキーを理解する必要があります。 多くのMongoDB-as-a-service企業は、ObjectRocketを含め、UIでこれを行う簡単な方法を提供しています。経験豊富なMongoDBユーザーは通常、JS用のMongooseやPython用のMongoengineなどのオブジェクトドキュメントマッパー(ODM)から始めます。これにより、アプリケーションの一貫したスキーマを構築し、タイプミスを減らすことができます。 (ODMは型の検証も行うため、整