LoginSignup
33
36

More than 5 years have passed since last update.

Railsでredirect_toする際に、別コントローラーのアクションにエラーメッセージを受け渡したい

Last updated at Posted at 2015-12-09

趣旨

sessionは怖いので、redirect_toの引数としてflashを用いて別コントローラーに引き継ぐのがいいのでは。

どういうことか。

ときたま、pages_controllerなどで表示した静的ページの中で会員登録を行いたい場合がある。

今現在、/teaserというパスにおり、そこではpages_controller#teaserが呼び出されているとする。
そこで会員登録を行い、失敗した場合は再度同じパスに戻りエラーメッセージを表示させたいというのが今回の目的。

そのような場合でも、createはusers_controllerで行っていることが一般的であり、そうするとバリデーションに失敗してsave出来なかった場合の処理は以下のように書きたくなる。が、これでは当然上手く動かない。


# 静的ページを管理するコントローラー
class PagesController < ApplicationController

  def teaser
    @user = User.new()
    render layout: 'teaser'
  end

  def teaser_thanks
    render layout: 'teaser'
  end

end

# @user.saveはUsersControllerで行いたい
class UsersController < ApplicationController

  def create
    @user = User.new(user_params)
    if @user.save
      redirect_to teaser_thanks_path # 成功すればティザーサイトのサンクスページヘ
    else
      # render 'new'ではなく、teaser_pathへ遷移
      redirect_to teaser_path
    end
  end

  private
  def user_params
    params.require(:user).permit(:email)
  end
end

この時、別コントローラーのアクションを呼び出しているため、インスタンス変数に放り込まれているエラーメッセージ @user.errors が受け渡されない

なので若干の工夫をする必要がある。

案1 sessionに渡す

この方法でも問題ない気はするが、以下の2つの理由から見送り。

  • sessionはむやみに使いたくない
  • 同じ画面に2つ同じフォームを置きたい場合(上部と下部にemail入力欄を設けたい、など)、先に出てくるフォームでsession[:error]が消されてしまい、それ以降のフォームではエラーメッセージが表示されない
    • 工夫でなんとかできるが、viewがややこしくなるので好きではない
class UsersController < ApplicationController

  def create
    @user = User.new(user_params)
    if @user.save
      redirect_to teaser_thanks_path # 成功すればティザーサイトのサンクスページヘ
    else
      session[:error] = @user.errors.full_messages
      redirect_to teaser_path
    end
  end

  # 中略
end
# view
<%= form_for @user do |f| %>
  <%= f.text_field :email, { placeholder: 'メールアドレス' } %>
  <%= f.submit '事前登録' %>

  <% if session[:error].present? %>
    <ul class="errors">
      <% session[:error].each do |e| %>
        <li><%= e %></li>
      <% end %>
    </ul>
    <% session[:error] = nil # 念のため使い終わったら消す %>   
  <% end %>
<% end %>

案2 素直にflashに渡す

30分ほど格闘し、flashに問題なく渡せることに気づいた。最初からこうすればよかった。

class UsersController < ApplicationController

  def create
    @user = User.new(user_params)
    if @user.save
      redirect_to teaser_thanks_path # 成功すればティザーサイトのサンクスページヘ
    else
      redirect_to teaser_path, flash: { error: @pre_regist.errors.full_messages }
    end
  end

  # 中略
end
# view
<%= form_for @user do |f| %>
  <%= f.text_field :email, { placeholder: 'メールアドレス' } %>
  <%= f.submit '事前登録' %>

  <% if flash[:error].present? %>
    <ul class="errors">
      <% flash[:error].each do |e| %>
        <li><%= e %></li>
      <% end %>
    </ul>
  <% end %>
<% end %>

終わりに

rails 楽しい。
が、こういうところで細かく悩まずに済むようにいち早く精進したい。

33
36
4

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
33
36