Techioz Blog

Ruby on Rails - 二重レンダリングエラー - リダイレクトとリターン

概要

エラー: AbstractController::DoubleRenderError (このアクションでは、レンダーおよび/またはリダイレクトが複数回呼び出されています。レンダーまたはリダイレクトを呼び出せるのはアクションごとに 1 回だけであることに注意してください。また、リダイレクトもレンダーもアクションの実行を終了しないことに注意してください)したがって、リダイレクト後にアクションを終了したい場合は、「redirect_to(…) and return」のようなことを行う必要があります。)

更新時に、モデルは template.exists? をチェックし、true の場合、レポートをダウンロードし、親オブジェクトにリダイレクトします。それ以外の場合は、リダイレクトするだけです。

「if」ステートメントの接線側で「and return」を使用しているのですが、なぜ期待どおりに機能しないのですか?

def update
  template = resource.check_changes(params[:well_master])
  paramString = resource.to_json
  
  update! do |format|
    if resource.errors.present?
      return render :edit
    else
      if template != ''
        generateWellLetter(template, 'Rpt_Farm_Name', paramString) 
      else
        rec = resource.PERMIT
        format.html { redirect_to admin_well_master_path(rec) }
      end
    end
  end
end
 
def generateWellLetter(template, letterName, params)
  @URL = "#{ENV["API_HOST"]}/api/Document/Generate/#{template}"
  response = HTTParty.post(@URL,
     :body => params,
     :headers => { "Content-Type" => "application/json" })

  Zip::InputStream.open(StringIO.new(response)) do |io|
    while entry = io.get_next_entry
      report = io.read
      send_data report, :filename => letterName + '.docx', :type => 'docx'
    end
  end

  respond_to do |format|
    rec = resource.PERMIT
    format.html { redirect_to admin_well_master_path(rec) } and return
  end
end

解決策

レンダリングの回数が多すぎるため、レンダリング呼び出しをまとめて保持することをお勧めします。

# send_data is like render, you can only call it once
while entry = io.get_next_entry
  report = io.read
  send_data report, filename: letterName + ".docx", type: "docx"
end
# can't send_data and also render
#
# can't use respond_to and respond_with (from inherited_resources -> responders)
# that's what `update!` method is for
#
# returning inside of the respond_to block means 
# `redirect_to admin_well_master_path(rec)` never runs
respond_to do |format|
  rec = resource.PERMIT
  format.html { redirect_to admin_well_master_path(rec) } and return
end

継承されたリソースを使用している場合は、おそらくそれを使用する必要があります。そうでない場合は役に立たないため、独自のロジックでresponse_toブロックを使用する必要があります。

def update
  template = resource.check_changes(params[:well_master])
  update! do |success, failure|
    # failure - already renders :edit so it's not needed
    success.html do
      if template.present?
        generate_well_letter(template, resource.to_json) do |report|
          send_data report, filename: "Rpt_Farm_Name.docx", type: "application/vnd.openxmlformats-officedocument.wordprocessingml.document"
        end
      else
        redirect_to admin_well_master_path(resource.PERMIT)
      end
    end
  end
end

def generate_well_letter(template, json)
  url = "#{ENV["API_HOST"]}/api/Document/Generate/#{template}"
  response = HTTParty.post(url, body: json, headers: {"Content-Type" => "application/json"})

  # either you're sending the whole zip file or just one file from the zip file
  Zip::InputStream.open(response) do |io|
    entry = io.get_next_entry
    report = entry.get_input_stream.read
    yield report
  end
end

https://translate.google.com/translate?hl=ja&sl=en&tl=ja&u=https://github.com/activeadmin/inherited_resources#overwriting-actions