スポンサーリンク
バリデーションとは
バリデーションっていうのは、入力フォームの値チェックのことです。
例えば、電話帳アプリの新規登録画面において、名前を空欄のまま登録されないようにしたり、電話番号の欄に番号以外を登録されないようにするのがバリデーション処理です。
電話帳アプリにこの機能を実装していきます。
スポンサーリンク
モデルにバリデーションを定義する
各フィールドについて、どういう値を許可するのかを定義するのは、各モデルクラスの中でします。
/app/models/member.rbを開いて下さい。
値チェックの定義はvalidatesメソッドを使って設定します。以下ではnameの項目(フィールド)について、空欄での登録を禁止しています。
1 2 3 | class Member < ApplicationRecord validates :name, presence: true end |
基本的に、validatesメソッドに、
第一引数検証するフィールド名
第二引数条件
を渡すことで、バリデーションを定義します。
1 | validates 検証するフィールド名, 条件 |
条件は連想配列の形で渡します。
ここではpresenceというキーにtrueという値を渡すことで、空欄での登録を禁止しています。
個人的にはRubyの文法がよく分かっていなかったので、この条件部分の書き方には少し混乱しましたが、要はただの連想配列です。以下の3つは書き方が違うだけで全く同じ処理になります。
1 | validates :name, presence: true |
1 | validates :name, "presence"=> true |
1 | validates :name, {"presence"=> true} |
この辺がよく分からない人はRailsでよく出てくるコロン(:)は、シンボルって言うやつらしいを読んでみて下さい。
※{ }については、書いてはいけないところがあったりしてよく分かりませんでした。{ }無しで書く方が普通のようです。
このようにvalidatesメソッドを書くことによって、モデルはテーブルへ書き込む際に、その条件をチェックするようになります。
その条件を満たさないと判断された場合は、テーブルへの書き込みは行われません。
つまり上記の場合、登録画面でnameフィールドが空欄の状態で登録をクリックしても、何も登録されなくなります。新規登録画面であっても編集画面であっても同様にです。
では、同じようにphoneフィールド(電話番号)も空欄での登録を禁止しておきましょう。
1 2 3 4 | class Member < ApplicationRecord validates :name, presence: true validates :phone, presence: true end |
さらに、phoneフィールドは電話番号を入力するところなので、「半角数字orハイフンだけからなる14文字以内の文字列」という条件を加えます。
複数の条件を指定したい場合は、どんどん後ろに引数を足していくことで指定することができます。
正規表現を使ってパターンマッチを調べるには、formatというキーを使って、その値に{width: 正規表現}という連想配列を入れます。
※この場合、{ }を省略することはできません。
1 2 3 4 | class Member < ApplicationRecord validates :name, presence: true validates :phone, presence: true, format: {with: /\A[0-9-]{,14}\z/} end |
presenceやformat以外にも、valicatesメソッドを使って様々なバリデーションの条件を定義することができます。詳しくは以下のリファレンスを確認してください。
参考validates – リファレンス – – Railsドキュメント
なお、複数の条件がある場合は、以下のように改行を入れると整理されて見やすくなると思います(統一感があった方がいいので:nameの方も改行をいれてます)。
1 2 3 4 5 6 7 8 | class Member < ApplicationRecord validates :name, presence: true validates :phone, presence: true, format: {with: /\A[0-9-]{,14}\z/} end |
とりあえずこれで値チェックの条件を満たさなかった場合は、DBへの書き込みは行われない状態になりました。
けど書き込みが行われなかったにも関わらず、しれっと一覧画面に戻ってしまっては、ユーザーはエラーにより登録に失敗したことに気づきません。
普通はそういう場合は、もう一度入力画面に戻して、然るべきエラーメッセージを表示するべきです。「入力エラーにより登録されませんでした」みたいな。
それを実装しましょう。
バリデーションエラー時には入力フォームへと戻す
コントローラーにて分岐処理を行います。
/app/controllers/members_controller.rbを開いて下さい。
まず新規登録時のバリデーションエラー処理を実装します。
新規登録画面で登録ボタンを押して、その登録情報をサーバーへと送り、それを受け取った際に動くのがupdateアクションです。
現状ではupdateアクションは、以下のようになっています。
1 2 3 4 5 | def create @member = Member.new(member_params) @member.save redirect_to members_path end |
リソースの新規登録画面を作って、登録処理を実装するのおさらいになりますが、
- 2行目 送られてきた入力情報(member_params)からMemberオブジェクトを作る。
- 3行目 そのオブジェクトが持つ情報をDBへと書き込む。
- 4行目 一覧画面へとリダイレクトする。
という処理をしています。
3行目のsaveメソッドを実行することでDBへと実際に書き込んでいるわけですが、saveメソッドはその書き込みに成功した場合にはtrueを返し、失敗した場合はfalseを返すようになっています。
それを利用して、DB書き込み成功時と失敗時に分岐させます。
1 2 3 4 5 6 7 8 | def create @member = Member.new(member_params) if @member.save redirect_to members_path else #書き込み失敗 end end |
書き込み成功時には、先ほどと同じように普通に一覧画面へとリダイレクトを行っています。
書き込み失敗時、つまりバリデーションエラーとなった場合は、新規登録画面を再表示するようにしましょう。
1 2 3 4 5 6 7 8 | def create @member = Member.new(member_params) if @member.save redirect_to members_path else render action: :new end end |
renderメソッドを使ってnewアクションで使われるビュー(つまりnew.html.erb)を表示させています。
renderメソッドは表示するビューを選択する為に使います。
以下のように引数に連想配列を渡すことでアクションを指定します。
1 | render action: アクション名 |
こうすることで、指定したアクションによって表示されるビュー(アクション名と同名のerbファイル)を使って画面を表示することができます。
renderメソッドは内部的に存在していると思えば分かりやすいと思います。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | def index #処理 #render action: :index end def new #処理 #render action: :new end def edit #処理 #render action: :edit end |
なお、renderメソッドは、action以外にも様々なオプションを指定することができます。詳しくは以下を参照してください。
参考render – リファレンス – – Railsドキュメント
これで、バリデーションエラーになった場合には、入力フォーム画面に戻るわけですが、その際、フォームの初期値はどうなっているでしょうか?
リソースの編集画面を作って、編集処理を実装するで説明したように、フォーム入力欄には、テンプレート変数@memberが保持している値が表示されます。
@memberが保持している値はというと、
1 2 3 4 5 6 7 8 | def create @member = Member.new(member_params) if @member.save redirect_to members_path else render action: :new end end |
member_paramsメソッドで取得した値、つまり送信してきた値そのままです。なのでバリデーションエラーとなった値も含め、入力フォームに入力した値そのままを@memberが保持した状態になっています。
なので、バリデーションエラーになって入力画面に戻ると、送信前の状態が勝手に再現されます。非常に賢いですRails。
同様に、新規登録ではなく編集時の送信先であるupdateアクションも、DBへの書き込みの成否によって処理を分けておきましょう。
1 2 3 4 5 6 7 8 | def update @member = find_member_by_id if @member.update(member_params) redirect_to members_path else render action: :edit end end |
これで、新規登録画面でも編集画面でも、入力した値がバリデーションエラーになった際には、再度、入力画面が表示されるようになりました。
バリデーションエラーのメッセージを表示する
元に戻るだけだと、ユーザーからすると何故戻されたのか意味が分からないかも知れないので、エラーメッセージを表示させましょう。
/app/views/members/_form.html.erbを開いて下さい。
エラーがあった場合は@member.errorsにそのエラー情報が格納されていますのでそれを利用します。まずはエラーがあった場合だけ表示する場所を作ります。
1 2 3 4 5 6 7 8 9 10 11 12 13 | <%= form_for @member do |f| %> <% if @member.errors.any? %> <% end %> <p> <%= f.label :name, "名前" %> <%= f.text_field :name %> </p> #以下省略 <% end %> |
その中で、エラーが何件あるかを表示します。
1 2 3 4 5 6 7 8 9 10 11 12 13 | <%= form_for @member do |f| %> <% if @member.errors.any? %> <h3>入力した内容にエラーが<%= @member.errors.count %>件あります</h3> <% end %> <p> <%= f.label :name, "名前" %> <%= f.text_field :name %> </p> #以下省略 <% end %> |
さらにそのエラーの内容(エラーメッセージ)をリストで表示します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | <%= form_for @member do |f| %> <% if @member.errors.any? %> <h3>入力した内容にエラーが<%= @member.errors.count %>件あります</h3> <ul> <% @member.errors.full_messages.each do |message| %> <li><%= message %></li> <% end %> </ul> <% end %> <p> <%= f.label :name, "名前" %> <%= f.text_field :name %> </p> #以下省略 <% end %> |
これで、試してみましょう。新規登録画面で入力フォームが空っぽのまま登録ボタンを押すと、
こんな感じでエラーメッセージが表示されます。
次回はこのエラーメッセージを日本語化する方法をやりたいと思います。
今回実装したのは、サーバー側で値をチェックする方法ですが、本来ならクライアント側でJavascriptによってバリデーションチェックを行うことで、サーバー側へデータを送る前にエラーを通知する方がユーザーにとっては親切だと言えます。
しかしながらJavascriptはクライアント側で無効にすることもできるので、サーバー側でもバリデーションチェックを行うことでDBに変な値が入ることのないようにするべきです。
サーバー側ではDBを守る意味でバリデーションチェックを行い、クライアント側ではいちいち送信せずともユーザーがエラーに気づくようにバリデーションチェックを行うのが理想的と言えると思います。
[…] フォーム入力時のバリデーション機能 (値のチェック) を実装する | 初めてのRuby on Rails入門 […]
by バリデーション [Rails] – Site-Builder.wiki 2019年1月28日 5:51 PM