Rails – 掲示板 – サインアップ機能

概要

サインアップ機能では、フォームで入力されたユーザー情報をデータベースに登録する。

データベースの構築、テーブルのマイグレーション、モデルによるDBの操作を整理する。

掲示板の第1段階へ

データベースの準備

データベースの準備」の要領でプロジェクトで扱うデータベースを準備する。

database.yml

development用のデータベースのみ準備し、testとproductionではデータベースを作成しない設定とする。

config/database.yml

DB作成

rails db:createでデータベースを作成し、rails db:consoleでmysqlコンソールに入り、データベースが作成されていることを確認。

モデルの生成とマイグレーション

モデルを生成し、これに対応したテーブルをマイグレーションにより生成する(基本的な方法はこちら)。

第1段階の最初で設定したデータベースのカラムを指定してモデルを生成する。idcreated_atupdated_atの3つはRailsが自動的に付加するので、以下の3つのみ指定する。

  • name:string
  • email:string
  • password:string

モデル名、モデルファイル名などの対応は以下の通り。

モデル名 user
モデルクラス名 User
モデルファイル名 user.rb
テーブル名 users

モデルの生成には、rails generate modelコマンドを使う。

rails generate model model_name col1:type col2:type ...

app/modelsディレクトリーにモデルファイルuser.rbが生成される。

app/models/user.rb

同時に、dbディレクトリーにマイグレーションファイルが生成される。

ファイル名は20210320060906_create_users.rbで、日時がUSTとなっている。

db/20210320060906_create_users.rb

rails db:maigrateコマンドを実行すると、マイグレーションファイルの内容に従ってテーブルが作成される。

rails dbconsoleコマンドを実行すると既にプロジェクトのデータベースを使う状態になっていて、usersテーブルが作成されているのが確認できる。

フォームデータのデータベースへの登録

フォームデータの取得

モデルによるフォーム入力への変更

フォーム入力の確認ではURL(アクション)を指定してデータを送信した。

モデルを使う場合には、モデルのインスタンスを生成して、そのインスタンスを介してデータを扱う。そのために以下の2点を変更する。

まずフォームでモデルを指定するため、その実行前、sign_upで空のUserクラスのインスタンスを準備する。結果はコントローラーのインスタンス変数@userに格納し、フォームがあるビューでも利用可能なようにしておく。

app/controllers/users_controller.rb

次に、フォーム側でモデルに入力データを格納するように変更する。form_withの場合は:modelキーで@userを指定する(form_forを使う場合は単に第1引数に@userを指定する)。

app/views/users/sign_up.html.erb

モデルのパラメーターの一括取得

モデルによるフォームデータの取得を参考に、require.permitによるメソッドを準備しておく。

app/controllers/users_controller.rb

データ保存の枠組み

フォームの入力データを単に保存する、というだけの手続きであれば、以下の処理になる。

  1. フォームからデータがPOSTされる
  2. それがsign_up_processにルーティングされる
  3. sign_up_processアクション内で
    1. フォームに入力されたパラメーターで新たなUserモデルのインスタンスを生成
    2. そのインスタンスの内容でデータベースに書き込み

フォームへの入力後、サインアップのボタンを押した後のテーブルの内容を確認すると、データは登録されている。

入力データの検証と書き込み

入力データのバリデーション

入力データのバリデーション処理を記述する。検証内容は以下の通り。

:name :email :password
存在 空ではない 空ではない 空ではない
一意性 一意 一意 一意
長さ 20文字以下 80文字以下 6文字以上
書式制約 なし あり なし

モデルのデータのバリデーションは、モデルクラス内で以下を宣言する。実行はsavecreateupdateの時に実行される。

validates: 対象カラム, 検証条件, 検証条件, ...

userモデルへのバリデーションの実装は以下の通り。

メールアドレスについては正規表現によりパターンチェックしている。

  • ローカル部は単語形成文字(a-z, _)2文字以上で間に連続しないドットをはさんでよい
  • ドメインは単語形成文字で間に連続しないドットをはさんでよく、最後にTLD(top level domain)が必要

エラー表示

モデルにvalidatesを定義すると、user.saveでデータベースに登録する前にバリデーションが実行される。

検証結果が適正であればデータは登録され、user.saveの戻り値はtrue。不適正であればデータは登録されず、user.saveの戻り値はfalseになる。

適正に登録された場合はトップページに遷移し、登録成功した旨のメッセージを一定時間表示する。一方不適正な場合は再度サインアップページを表示し、入力が不適正な旨のメッセージを一定時間表示する。

ページ遷移の際に一定時間メッセージを表示して消す機能についてはflushの使い方を参照。

コントローラーでの処理

  1. フォームからPOSTされたデータをで受け取り、user_paramsメソッドを介してモデルを生成
  2. テストのため、valid?メソッドでバリデーション実行
  3. 検証の結果が適正か不適正かによってflash.nowに保存
  4. 共通レイアウトを指定し、適正ならsign_inを、不適正ならsign_upをレンダリング

app/controllers/users_controller.rb

flash.nowを使っている理由は以下の通り。

  • エラー後の再入力で、直前に入力した値をフォームに入れておきたい
  • そのためにはインスタンス変数@userを使う必要がある
  • ただしredirect_toでアクションから実行すると@usernilに初期化されてしまう
  • そこでrender@userの内容を保持したい
  • そうすると、flashではその次のアクションまで内容が保持されて余計な表示がされることがある
  • そこで適正・不適正ともflash.nowrenderを使った

また、17行目の処理は以下の通り。

  • @user.errors.messagesはメッセージタイプをキーとするハッシュ
  • ハッシュの値は検証結果のメッセージの配列
  • まずvaluesmessagesの全てのメッセージタイプの値を取り出す(メッセージ配列を要素とする配列)
  • flattenで1次元のメッセージの配列にする
  • joinで配列要素を文字列に結合(区切りは<br>タグ)

レイアウトでの表示

  1. JQueryを使うのでCDNから読み込み(9行目)
  2. flash.nowが設定されていればメッセージを表示
    • 表示するp要素のクラスをタイプごとに設定
    • メッセージ中の<br>タグを有効にするため、html_safeを適用
  3. 3秒後にメッセージをスライドアップするJavaScriptを記述

app/views/layouts/application_signed_out.html.erb

スタイルの設定

  • .flash_messageで共通のスタイルを定義
  • success/dangerに応じて設定されたクラスごとに色を変える

app/assets/stylesheets/common.scss

DB書き込み処理

@user.valid?でメッセージの内容や挙動を確認したら、ここを@user.saveに書き換える。

データを1つ登録した結果。

以降、重複する内容のデータで登録しようとするとuniquenessで弾かれる。

パスワードの暗号化

パスワードの暗号化はDigest::MD5を使うuserモデルに以下を追記する。

before_saveでコールバックを設定していて、モデルの内容がデータベースに書き込まれるときにパスワードが暗号化される

当初これをbefore_saveとしていたが、これだと後述のデータ更新のときにもコールバックが実行され、既にハッシュ化されているパスワードが更にハッシュ化されて登録されていまう。このため、これをbefore_createに変更。

before_createでコールバックを設定していて、モデルの内容でデータベースのレコードが新規作成されるときにパスワードが暗号化される。

以下はテストデータを登録した結果。

 

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です