##はじめに
Railsのコントローラーの話でして、例えばある入力フォームで送信した場合に、if文を使って登録を失敗したら、render :new
とかで再度そのページを表示させたりしますよね。
私の場合もし失敗したら、違うコントローラーのshowアクションを呼び出したくて苦戦していました。
なんとかうまくいったので記事に残しておきます。
##よく使うcreateアクションのコード
def create
@progress = Progress.new(progress_params)
if @progress.save
redirect_to students_textbook_path(@textbook)
else
render :new
end
end
これは今まで私がよく活用していたcreateアクションのコードです。
createアクションを実行する(送信ボタンを押す)直前のページはnewアクションでそれに対応しているnewのビューで、入力フォームとなっています。
なので、もし保存に失敗したら、render :new
でnewアクションをルーティングを介さずに、実行するようにしています。
しかし今回は、newアクションは存在せず、違うコントローラーのshowアクションに対応したビューにフォームが存在しているので、違うコントローラーのshowアクションをrenderしたいのです。
##renderで違うコントローラを呼び出す
createアクションが記述されているのはprogressesコントローラーですが、renderで呼び出したいのはtextbooksコントローラのshowアクションです。
その場合下記のような記述で呼び出せます。
def create
@progress = Progress.new(progress_params)
if @progress.save
redirect_to students_textbook_path(@textbook)
else
render template: "students/textbooks/show"
end
end
私の場合、コントローラのフォルダの中にstudentsというフォルダも存在しているのでこのような記述になります。
「renderでコントローラフォルダのstudents配下のtextbooksコントローラのshowアクションをtemplateとして使ってください。」
ということです。
##注意点
もしそのshowアクションで呼び出したビューの中に、textbooksコントローラで定義されている変数がなければいいのですが、大体定義されていますよね。
なのでrenderの前にビューで必要な変数は定義してあげましょう。
私の場合↓
def create
@progress = Progress.new(progress_params)
if @progress.save
redirect_to students_textbook_path(@textbook)
else
@students_textbook = StudentsTextbook.where(student_id: current_student.id).find_by(textbook_id: @textbook.id)
@progress = Progress.new
@progresses = Progress.where(students_textbook_id: @students_textbook.id).order('created_at DESC')
render template: "students/textbooks/show"
end
end
完全に私が作成中のアプリから抜粋したものですのであまり細かいところ気にしないでください 笑
伝えたいことはビューで使う変数はこっちでもちゃんと定義してあげなければいけませんということです。
##最後に
自分で書いときながら、renderで違うコントローラのアクションをを引っ張ってくるとか、呼び出すとか、なんかちょっと表現が違う気がします。。。
どうでしょう?
すごい良いエラーが出た!と思ってとりあえずまとめてみただけなので、まだまだ理解が浅い分、間違った理解や表現をしているかもしれません。
もしご指摘ありましたら、お願いします。