ポートフォリオ作成中、バリデーションのエラーメッセージが表示できずに苦戦してました
redirect_toとrenderの違いを理解していなかったのが原因です。
redirect_toとrender, ついでにflashとflash.nowの違いについても今更理解したのでまとめます。
参考
renderとredirect_toの違い
- render => ビューを描画するだけで、新たにhttpリクエストを送信するわけではない
- redirect_to => 新たにhttpリクエストを送信して、その結果コントローラからビューが描画される
class TweetsController < ApplicationController
def new
@tweet = Tweet.new
end
def create
@tweet = Tweet.new(tweet_params)
if @tweet.save
# 成功時の処理
else
flash[:danger] = '失敗しました'
redirect_to new_tweet_path
end
end
private
def tweet_params
params.require(:tweet).permit(:content)
end
end
= form_with model: @tweet, local: true do |f|
- if @tweet.errors.any?
.alert.alert-danger
ul
- @tweet.errors.full_messages.each do |message|
li= message
= f.label :content
= f.text_area :content
= f.submit 'tweet'
こんな感じの設定があったとします(tweetモデルはpresence: trueのconent: stringカラムを持つ)
この場合、空白で送信してもエラーメッセージは表示されません
redirect_toでリダイレクトするとコントローラを経由してしまうため、新たに@tweet
が生成され、エラーメッセージを含んだ@tweet
が消えてしまうから…だと考えています
ここで、コントローラを経由せずにページを描画するrenderを使用します
class TweetsController < ApplicationController
def new
@tweet = Tweet.new(tweet_params)
end
def create
@tweet = Tweet.new(tweet_params)
if @tweet.save
# 成功時の処理
else
flash[:danger] = '失敗しました'
render action: :new # ここを変更
end
end
private
def tweet_params
params.require(:tweet).permit(:content)
end
end
renderを使用すればコントローラを経由せずにページを描画することができるため、エラーメッセージを含んだ@tweet
がビューに渡されif @tweet.errors.any?
に引っ掛かり、エラーメッセージを表示することができます
これで無事エラーメッセージを表示することができました!
flashとflash.nowの違いについて
- flash => 次のリクエスト終了時まで表示される
- flash.now => 次のリクエスト開始時まで表示される
コントローラーが上の最終状態のまま空白で送信した場合、失敗しました
というflashメッセージが表示され、失敗します。
しかし、このままでは次別のページに遷移した時flashが残ったままになってしまいます。
renderを使うとリクエストを送信しないため次にリクエストを送信した時もflashが残り、その次のリクエストを送信した時点でやっとflashが消えるからだと思われます
そこでflash.nowを使ってみましょう
class TweetsController < ApplicationController
def new
@tweet = Tweet.new(tweet_params)
end
def create
@tweet = Tweet.new(tweet_params)
if @tweet.save
# 成功時の処理
else
flash.now[:danger] = '失敗しました' # ここを変更
render action: :new
end
end
private
def tweet_params
params.require(:tweet).permit(:content)
end
end
flash.nowは次リクエストを送信した時点で消えるため、これでflashを残さずに次のページへ移動することができます
それぞれの組み合わせ
- flash[]とredirect_to => 次のページにリダイレクトした時点でflashは消える
- flash[]とrender => renderはリクエストを送信しないため、次のページに移動してもflashは残る
- flash.now[]とredirect_to => redirect_toの時点でflashが消えるため、flash自体表示されない
- flash.now[]とrender => 次のページへリダイレクトした時点でflashは消える
最後に
Railsチュートリアルで丁寧に説明されていた箇所なんですが、実際に自分で試行錯誤して初めて理解できました
何かおかしい部分があれば指摘して頂けると嬉しいです
読んでいただきありがとうございました!