LoginSignup
0
0

More than 1 year has passed since last update.

rails apiでの複数の値をmapで回してcreateアクションでDBへ保存しようとするとAbstractController::DoubleRenderErrorで苦しめられた話

Posted at

はじめに

reactで配列を使って作成した値を、一気にrails apiに送ってcreateアクションで保存をしたいと考えていました。
ですが、AbstractController::DoubleRenderErrorを解消することに時間がかかったので、備忘録として残そうと思います。
深夜テンションで、雑に文章を書いちゃってる部分もあるかもしれないので、後で元気がある時に確認して必要があれば修正しようと思います。

どのような記述をしてエラーが起きたか

データやモデル名やカラム名は少しいじってますが、下記のような値がrails apiが来ているとします。

Parameters: {"_json"=>[
{"quiz_name"=>"問1", "quiz_status"=>"answered"},
{"quiz_name"=>"問2", "quiz_status"=>"answered"},
{"quiz_name"=>"問3", "quiz_status"=>"answered"}], 
"quiz"=>{}}

最初は下記のように記述をしていました。
自分の考えだと、mapで一周するごとにrenderでフロント側にjsonを返してくれるからそのデータを使ってあれこれやろうと考えていました。

def create
    params.require(:_json).map do |param|
      quiz = Quiz.new(param.permit(:quiz_name, :quiz_status).to_h)
      if quiz.save
        render json: { status: 'SUCCESS', data: quiz }
      else
        render json: quiz.errors
        return
      end
    end
  end

すると、下記のようなエラーが出て、DBへの保存も途中で失敗しフロント側にデータが返ってきませんでした。

AbstractController::DoubleRenderError 
(Render and/or redirect were called multiple times in this action. 
Please note that you may only call render OR redirect, and at most once per action. Also note that neither redirect nor render terminate execution of the action, 
so if you want to exit an action after redirecting, 
you need to do something like "redirect_to(...) and return".):

renderを連続でしないでね、というエラーだと翻訳でしり、指示通りに and returnをrenderの後に入れるもそこでmapが終了して全てのデータが保存できませんでした。

renderは一回のアクションにつき一回のみだった

色々と記事を調べてみると"renderを2回してはいけない"という記事がたくさん出てきましたが、僕は"mapでしっかり1データづつ保存してるから連続してないじゃん!!"とネットの記事に心の中で反論していました。

ですが僕の勘違いでした。
1回のアクションで一度しか使ってはいけないということだったんですね。
2つデータがあれば、僕の記述だと1回のアクションで2回のrenderが発生してしっかり二重レンダリングをしていることになっていました。
エラーが出るのは当たり前だったようです。

なので配列を作ってデータを保存するたびにその配列に格納し、保存が終わった後に配列ごとreactへ返すように記述をしたところ、保存が成功してフロント側へjsonでデータを送れました。

  def create
    quiz_hash = []
    params.require(:_json).map do |param|
      quiz_branch = Quiz.new(param.permit(:quiz_name, :quiz_status).to_h)
      if quiz.save
        quiz_hash.push(quiz)
      else
        render json: quiz.errors
        return
      end
    end
    render json: { status: 'SUCCESS', data: quiz_hash }
  end

このやり方が最適解ではないかと思いますが、昨日このエラーと格闘して、まだまだ知識不足の自分にとっては手強い相手であり、解決できた時は達成感がありました。
手を動かすのがやっぱり一番勉強になりますね。。

同じような箇所で詰まっている人は少ないかもしれませんが、誰かの助けになったら幸いです。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0