Computer >> 컴퓨터 >  >> 프로그램 작성 >> Ruby

고통 없이 'Respond_to'

Rails에서 스캐폴드를 생성하면 일반적인 respond_to가 표시됩니다. 블록:

앱/컨트롤러/태스크_컨트롤러.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와 같은 일부 작업은 , 가지고 있지 않습니다!

앱/컨트롤러/태스크_컨트롤러.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 차단 액션:

앱/컨트롤러/태스크_컨트롤러.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 바로가기

개체를 렌더링하기 위해 특별한 작업을 수행하지 않는 경우 바로 가기를 사용할 수 있습니다. 작성하는 경우:

앱/컨트롤러/태스크_컨트롤러.rb
def index
  @tasks = Task.all
  respond_to :html, :json
end

전체 respond_to를 작성하는 것과 같은 방식으로 작동합니다. index의 블록 . 작업이 알고 있는 모든 형식에 대해 Rails에 알리는 짧은 방법입니다. 그리고 다른 작업이 다른 형식을 지원하는 경우 많은 코드 없이 이러한 차이를 처리하는 좋은 방법입니다.

컨트롤러 수준에서 형식 처리

그러나 일반적으로 컨트롤러의 각 작업은 동일한 형식. index인 경우 json에 응답 new도 마찬가지입니다. , 및 create , 그리고 다른 모든 것. 그래서 respond_to 전체 컨트롤러에 영향을 미칩니다.

앱/컨트롤러/태스크_컨트롤러.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를 사용하여 확인하려는 개체를 알려야 합니다. . 따라서 다음 대신:

앱/컨트롤러/태스크_컨트롤러.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

다음과 같이 작성할 수 있습니다.

앱/컨트롤러/태스크_컨트롤러.rb
  def create
    @task = Task.new(task_params)
    flash[:notice] = "Task was successfully created." if @task.save
    respond_with(@task)
  end

이렇게 하면 응답하는 형식에서 코드를 분리할 수 있습니다. Rails에게 한 번 말할 수 있습니다. 처리하려는 형식. 모든 작업에서 반복할 필요는 없습니다.

응답자 보석

Rails 4.2에는 다음과 같은 캐치가 있습니다. respond_with 더 이상 포함되지 않습니다. 하지만 responders를 설치하면 되돌릴 수 있습니다. 보석. 그리고 responders gem은 다른 멋진 기능을 제공합니다.

respond_with에서 플래시 메시지를 설정할 수 있습니다. responders :flash를 포함하여 컨트롤러 상단:

앱/컨트롤러/태스크_컨트롤러.rb
class TasksController < ApplicationController
  responders :flash

편리하게도 로케일 파일에서 이러한 플래시 메시지의 기본값을 설정할 수 있습니다.

또한 responders가 있는 경우 Gemfile의 gem Rails 스캐폴드를 생성하면 생성기가 respond_with를 사용하여 컨트롤러를 생성합니다. respond_to 대신 :

앱/컨트롤러/태스크_컨트롤러.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

마지막 팁에 대한 의견에 Jeroen Weeink에게 감사드립니다!

respond_with 또는 respond_to ?

다른 형식에 대해 다른 정보를 반환하려는 경우 몇 가지 옵션이 있습니다. 컨트롤러 수준 respond_to respond_with와 결합 짧은 컨트롤러를 얻는 좋은 방법입니다. 그러나 모든 컨트롤러 작업이 동일한 형식에 응답하고 Rails가 기대하는 방식으로 작동할 때 가장 도움이 되는 경향이 있습니다.

그러나 때로는 다르게 작동하는 몇 가지 작업을 원할 수 있습니다. 한 줄짜리 respond_to 이러한 상황을 처리하는 데 좋습니다.

더 많은 제어가 필요한 경우 전체 respond_to를 사용하세요. 블록을 사용하여 원하는 대로 각 형식을 처리할 수 있습니다.

이들 중 하나를 사용하면 지원하지 않는 형식에 대한 요청에 올바른 오류가 발생합니다. 또한 앱과 클라이언트 모두 혼란을 훨씬 덜 수 있습니다.