CodeZine(コードジン)

特集ページ一覧

Rails 5で実用的なユーザー登録機能を実装

サンプルコードで学ぶRuby on Rails 5実践入門 第4回

  • LINEで送る
  • このエントリーをはてなブックマークに追加
2017/02/16 14:00
目次

ユーザー登録時のバリデーションを追加(2)

uniquenessバリデーションの追加

 ユーザー登録は、同じメールアドレスで登録することは一般にあり得ないでしょう。そこで一意性を担保するためのバリデーションを追加します。

リスト4 app/models/user.rb
class User < ApplicationRecord
  validates :name, presence: true, length: { maximum: 255 }
  VALID_EMAIL_REGEX = /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i
  validates :email, presence: true, length: { maximum: 255 }, format: { with: VALID_EMAIL_REGEX }, uniqueness: { case_sensitive: false }
end

 case_sensitiveをfalseに設定することで、メールアドレスは大文字・小文字を区別しないことを表現しています。バリデーションが機能していることを確認しましょう。

$ bin/rails c

 ↓

irb(main):001:0> User.create name: 'test', email: 'test@example.com'
   (0.1ms)  BEGIN
  User Exists (38.0ms)  SELECT  1 AS one FROM "users" WHERE "users"."email" = $1 LIMIT $2  [["email", "test@example.com"], ["LIMIT", 1]]
  SQL (8.3ms)  INSERT INTO "users" ("name", "email", "created_at", "updated_at") VALUES ($1, $2, $3, $4) RETURNING "id"  [["name", "test"], ["email", "test@example.com"], ["created_at", 2016-12-21 10:09:19 UTC], ["updated_at", 2016-12-21 10:09:19 UTC]]
   (20.0ms)  COMMIT
=> #<User id: 2, name: "test", email: "test@example.com", created_at: "2016-12-21 10:09:19", updated_at: "2016-12-21 10:09:19">

irb(main):002:0> user = User.new name: 'test', email: 'test@example.com'
=> #<User id: nil, name: "test", email: "test@example.com", created_at: nil, updated_at: nil>

irb(main):003:0> user.valid?
  User Exists (0.7ms)  SELECT  1 AS one FROM "users" WHERE "users"."email" = $1 LIMIT $2  [["email", "test@example.com"], ["LIMIT", 1]]
=> false

irb(main):004:0> user.errors.full_messages
=> ["Email has already been taken"]
irb(main):005:0> user = User.new name: 'test', email: 'TEST@EXAMPLE.COM'
=> #<User id: nil, name: "test", email: "TEST@EXAMPLE.COM", created_at: nil, updated_at: nil>

irb(main):006:0> user.valid?
  User Exists (16.6ms)  SELECT  1 AS one FROM "users" WHERE LOWER("users"."email") = LOWER($1) LIMIT $2  [["email", "TEST@EXAMPLE.COM"], ["LIMIT", 1]]
=> false

irb(main):007:0> user.errors.full_messages
=> ["Email has already been taken"]

 メールアドレス「test@example.com」のユーザーを登録し、再度同じメールアドレスで登録しようとするとバリデーションエラーが発生している様子が分かります。また、全て大文字にした「TEST@EXAMPLE.COM」で登録しようとしても同様にバリデーションエラーが発生している様子が分かるでしょう。

emailの一意性をデータベースレイヤーで担保

 uniquenessバリデーションでemailの一意性を担保しましたが、これはあくまでアプリケーションレイヤーでの話です。データベースレイヤーでも一意性を担保する必要があります。

 そこでemailの一意性を担保するためにusersテーブルにユニークインデックスを追加しましょう。

$ bin/rails g migration add_index_to_users_email

 ↓

      invoke  active_record
      create    db/migrate/20161221101841_add_index_to_users_email.rb

 生成されたマイグレーションファイルを編集し、usersテーブルのemailカラムにユニークインデックスを追加する定義を記述します。

リスト5 db/migrate/20161221101841_add_index_to_users_email.rb
class AddIndexToUsersEmail < ActiveRecord::Migration[5.0]
  def change
    add_index :users, :email, unique: true
  end
end

 マイグレーションを実行しましょう。

$ bin/rails db:migrate

 ↓

== 20161221101841 AddIndexToUsersEmail: migrating =============================
-- add_index(:users, :email, {:unique=>true})
   -> 0.1713s
== 20161221101841 AddIndexToUsersEmail: migrated (0.1714s) ====================

フォームからユーザー登録のバリデーションをテスト

 Usersリソース一覧から「New User」をクリックし、実際にフォームからバリデーションエラーが表示されることをテストしてみましょう。Name、Emailに何も入力せずに「Create User」ボタンをクリックすると以下の画面が表示されるはずです。

図1 http://localhost:3000/users
図1 http://localhost:3000/users

 presence、formatの各バリデーションエラーメッセージが表示されていることが確認できます。また、バリデーションエラーになっているName、Emailのテキストボックスが赤枠で囲まれています。

 エラーメッセージを表示するviewファイルを確認しましょう。

リスト6 app/views/users/_form.html.erb
…(中略)…
  <% if user.errors.any? %>
    <div id="error_explanation">
      <h2><%= pluralize(user.errors.count, "error") %> prohibited this user from being saved:</h2>

      <ul>
      <% user.errors.full_messages.each do |message| %>
        <li><%= message %></li>
      <% end %>
      </ul>
    </div>
  <% end %>

  <div class="field">
    <%= f.label :name %>
    <%= f.text_field :name %>
  </div>

  <div class="field">
    <%= f.label :email %>
    <%= f.text_field :email %>
  </div>
…(中略)…

 viewファイルのif user.errors.any?でバリデーションエラーが発生した場合にエラーメッセージのブロックを表示する分岐を行っています。pluralizeはヘルパーメソッドで第2引数を複数形にして第1引数と文字列をスペース区切りで連結します。この場合バリデーションエラーの数が3つなので出力は画面表示の通り「3 errors」となります。

 なお、NameとEmailのテキストボックスが赤枠で表示されているのはf.labelとf.text_fieldヘルパーメソッドが、バリデーションエラー時にはdivのクラス名をfield_with_errorsで出力してくれているからです。

まとめ

 今回はscaffoldで自動生成したユーザー登録機能をより実践的に拡張しました。次回はユーザー登録時にパスワードを登録できるようにし、ログインフォームを開発します。

参考文献



  • LINEで送る
  • このエントリーをはてなブックマークに追加

バックナンバー

連載:サンプルコードで学ぶRuby on Rails 5実践入門

もっと読む

著者プロフィール

  • WINGSプロジェクト 竹馬 力(チクバ ツトム)

    <WINGSプロジェクトについて> 有限会社 WINGSプロジェクトが運営する、テクニカル執筆コミュニティ(代表 山田祥寛)。主にWeb開発分野の書籍/記事執筆、翻訳、講演等を幅広く手がける。2018年11月時点での登録メンバは55名で、現在も執筆メンバを募集中。興味のある方は、どしどし応募頂...

  • 山田 祥寛(ヤマダ ヨシヒロ)

    静岡県榛原町生まれ。一橋大学経済学部卒業後、NECにてシステム企画業務に携わるが、2003年4月に念願かなってフリーライターに転身。Microsoft MVP for ASP/ASP.NET。執筆コミュニティ「WINGSプロジェクト」代表。 主な著書に「入門シリーズ(サーバサイドAjax/XM...

あなたにオススメ

All contents copyright © 2005-2021 Shoeisha Co., Ltd. All rights reserved. ver.1.5