普通にRails書いていてどうもうまくいかないところがあってはまったのでメモしておく。

フォーム埋めてcreateアクションにPOSTしたあと、モデルのsaveが成功したらindexアクションへリダイレクト、失敗したらもう1回newをレンダリングというよくあるケース。これで保存に成功してindexにリダイレクトしたとき、なぜかURLに?notice=successがくっついてしまうということがあった。

実際に書いたコード(とほぼ同じもの)はこちら。

1def create
2  @entry = Entry.new(permitted_params)
3  if @entry.save
4    redirect_to action: :index, notice:"success"
5  else
6    render :new
7  end
8end

実は上のコードだと問題があるが、気を抜いていたので見落としてしまった。

redirect_toはこのようにハッシュの引数を2つ受け取る。

1redirect_to(options = {}, response_status = {})

さきほどのケースでは暗黙のうちにactionnoticeも1つ目のハッシュであると解釈されてしまった。

1redirect_to({action: :index, notice:"success"})

Rubyではメソッドの引数になるハッシュの波カッコは省略できるし、メソッドの引数も省略できることもあるのでどちらが優先されるのかが一見するとわかりにくい。

正しく動かすには以下のようにする必要がある。

1def create
2  @entry = Entry.new(permitted_params)
3  if @entry.save
4    redirect_to({action: :index}, notice:"success")
5  else
6    render :new
7  end
8end

一応これでうまくいった。