LoginSignup
0
1

More than 3 years have passed since last update.

【Rails】ユーザー登録フォームの作成その2 ユーザー登録の失敗【Rails Tutorial 7章まとめ】

Last updated at Posted at 2019-11-27

ユーザー登録に失敗した場合の処理

ユーザー登録に失敗した場合は、renderメソッドを使って新規登録ページに戻り、エラーメッセージを表示する。
renderを使うことで、newアクションの@user = User.newは実行されず、以前送信した内容がフォーム内に保持される。

エラーメッセージはパーシャルを使って分けておくことにする。
フォーム内にはエラーメッセージ用パーシャルへのrenderを書く。

app/views/users/new.html
<%= form_for(@user) do |f| %>
  <%= render 'shared/error_messages' %>

  <%= f.label :name %>
  <%= f.text_field :name, class: 'form-control' %>

  <%= f.label :email %>
  <%= f.email_field :email, class: 'form-control' %>

  <%= f.label :password %>
  <%= f.password_field :password, class: 'form-control' %>

  <%= f.label :password_confirmation, "Confirmation" %>
  <%= f.password_field :password_confirmation, class: 'form-control' %>

  <%= f.submit "Create my account", class: "btn btn-primary" %>
<% end %>

各フォームについているform_controlクラスは、bootstrap用である。

エラーメッセージ用のパーシャルは次のようである。
app/views/shared/_error_messages.html.erb

app/views/shared/_error_messages.html
<% if @user.errors.any? %>
  <div id="error_explanation">
    <div class="alert alert-danger">
      The form contains <%= pluralize(@user.errors.count, "error") %>.
    </div>
    <ul>
    <% @user.errors.full_messages.each do |msg| %>
      <li><%= msg %></li>
    <% end %>
    </ul>
  </div>
<% end %>

コントローラにまたがって共通で使うパーシャルはsharedディレクトリに入れておく。

ここで、any?メソッドはempty?メソッドの逆であり、要素が一つでもある場合はtrue、ない場合はfalseを返す。
@user.errors.countは、エラーの個数を返す。

pluralizeメソッドは、第一引数に整数を、第二引数に英単語をとり、整数値に応じて英単語を複数化する。
不規則活用にも使える。

>> helper.pluralize(1, "error")
=> "1 error"
>> helper.pluralize(5, "error")
=> "5 errors"

エラーが起こり、newページに戻されると、エラーメッセージが表示される。
また、Railsはfield_with_errorsクラスを持つdivタグによって、フォームのラベルとフォームそのものを囲んでくれる。
スクリーンショット 2019-11-28 4.22.05.jpg
これによってcssを使ってエラーを起こしたフォームの枠を赤くしたりできる。
スクリーンショット 2019-11-28 4.23.41.jpg
cssは以下のよう。

app/assets/stylesheets/custom.scss
/* forms */
.
.
.
#error_explanation {
  color: red;
  ul {
    color: red;
    margin: 0 0 30px 0;
  }
}

.field_with_errors {
  @extend .has-error;
  .form-control {
    color: $state-danger-text;
  }
}

has_errorはbootstrapのcssクラスである。

登録エラー時のテスト

新規ユーザー登録用の統合テストを生成する。

$ rails generate integration_test users_signup

登録エラー時のテストを書く。

test/integration/users_signup_test.rb
require 'test_helper'

class UsersSignupTest < ActionDispatch::IntegrationTest

  test "invalid signup information" do
    get signup_path
    assert_template 'users/new'
    assert_no_difference 'User.count' do
      post users_path, params: { user: { name:  "",
                                         email: "user@invalid",
                                         password:              "foo",
                                         password_confirmation: "bar" } }
    end
    assert_template 'users/new'
  end
end

①まずsignup_pathにGETリクエストを送信する。行き先はnewアクションのnewビューである。
②newビューが表示されていることを確認する。
③assert_no_differenceを使って、ユーザー登録操作の前後でユーザー数が変わらないことを確認する。ユーザー登録が失敗すればユーザー数は変わらないはずである。
④users_pathにPOSTリクエストを送信する。postメソッドの第二引数にはparamsハッシュを指定する。
(paramsは変数でありハッシュでもあるらしい...よく分からない)
⑤ユーザー登録が失敗し、renderメソッドによってnewページに戻っていることを確認する。

必要であれば
⑥エラーメッセージが表示されていることを確認する。

assert_select 'div#<CSS id for error explanation>'
assert_select 'div.<CSS class for field with error>'

URLの修正

登録エラーでnewページに戻ると、URLが/signupから/usersに変わる。
これはusersリソースのRESTfulなルーティングによるもの。
フォームの送信は/usersのPOSTリクエストに送られて、createアクションに到達する。
その後登録エラーでnewページに戻るが、リダイレクトではなく再読み込みしていないので、URLはPOSTリクエストがされた時のままになる。
(という認識であってるかな?)

これを修正するためにルーティングを変更する。
URLが/signupのPOSTリクエストを作る(行き先はcreateアクション)。

config/routes.rb
Rails.application.routes.draw do
  .
  .
  .
  get  '/signup',  to: 'users#new'
  post '/signup',  to: 'users#create'
  resources :users
end

フォームの送信先もこのルーティングに変更する。

app/views/users/new.html.erb
<%= form_for(@user, url: signup_path) do |f| %>
  .
  .
  .
<% end %>

テストのPOSTリクエスト部分を修正する。また、form_forから生成されるformタグのaction属性(送信先のURLを値にとる)が正しいURLになっていることを確認する。

test/integration/users_signup_test.rb
  test "invalid signup information" do
    get signup_path
    assert_template 'users/new'
    assert_no_difference 'User.count' do
      post signup_path, params: { user: { name:  "",
                                         email: "user@invalid",
                                         password:              "foo",
                                         password_confirmation: "bar" } }
    end
    assert_template 'users/new'
    assert_select 'form[action="/signup"]'
  end
0
1
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
1