知っとくべきRailsの各バリデーションレベルでの役割　初心者→中級者へのSTEP1/25

#知っとくべきRailsの各バリデーションレベルでの役割

**はじめに**
カレンダー１発目の記事です。初心者が中級者になるということで、チュートリアルや入門書に載ってないもので知っとくべきことを書いてきます。最初はバリデーションについて掘り下げていこうかなあと思ってます。
今回はその中でバリデーションレベルについてです。このような考え方、概論的なものは知らなくても、一応Webアプリケーションは作れてしまいますが、そこを知るか知らないかが初級者と中級者の違いかな〜と勝手に思ってます。

##まずバリデーションを振り返る
バリデーションとは、簡単にいえばデータの正しさを検証すること。Emailがあるか、名前があるか、一意のものか等、データがあって欲しい形式をとっているか検証するもの。
（下は超基本的なname属性が存在するかの検証)

```User.rb
class User < ApplicationRecord
  validates :name, presence: true
end
```


##バリデーションの認識の違い
**初心者なワイの認識**

- オブジェクトをDBに保存する時に、データの正当性を検証するンゴ！
- とりあえずmodelにバリデーション書いとけば安心ンゴ！
- 不正なデータは保存されないンゴ！


**バリデーションレベルを知ったワイの認識**

- バリデーションをかけるタイミングは４つある。saveする時だけではない。
- セキュアなバリデーションは多層構造
- 各レベルでのバリデーションの役割を把握することが重要。


##４つのバリデーションレベル

###Modelでのバリデーション###
一番基本的なバリデーション。上述の例では、nameがUserのレコードに確実に存在するように定義してる。
初心者はこのアプローチをまず学ぶはず。
当時、ワイは「modelで`presence: true`と書けば一安心、nameは絶対なきゃ保存できないンゴ」とか思ってました。モデルでの検証の役割など考えず、自分が検証して欲しいように検証させてました。

認識としてはかなり雑魚です。まず、以下のようなメソッドによってはnameがなくても保存できてしまいます。(以下のメソッドはバリデーションをスキップします。)
`decrement!
decrement_counter
increment!
increment_counter
toggle!
touch
update_all
update_attribute
update_column
update_columns
update_counters`

また、ここでのバリデーションの役割の認識としては論理性の検証です。名前は一意か、日付は矛盾してないか、住所の都道府県と郵便番号に矛盾は無いか、保存するデータの組み合わせとして正しいか、（アルバム名はあるのに曲の名前が無いなど）。
上記のようなロジック的な検証をここでします。

###Controllerでのバリデーション###
コントローラで行うバリデーションは、Modelに渡す入力データを検証することです。
プログラムが正しく処理できる入力データか検証します。
不要なパラメーターは無いか、逆に必要なパラメーターはあるか、指定数内の文字数か、数字なのに文字が入って無いか、、
みなさんご存知`StrongParameters`もバリデーションの一つです。不正な入力値ははじきます。

```users_controller.rb
class UsersController < ApplicationController

  def user_params
    params.require(:user).permit(:name, :email, :tel_no, :sex, :birth, :discription) 
  end

end
```


またコントローラーで行うバリデーションにはフォームオブジェクトと呼ばれるものがあり、次回はそこを掘り下げてみます。



###DBでのバリデーション###
もっともセキュリティの高いバリデーションです。とりあえず書いとけば安心ンゴ！！と言ってましたが、それはむしろこっちです。

```schema.rb
ActiveRecord::Schema.define(version: 20181121160237) do
  create_table "users", force: :cascade do |t|
    t.string   "name"     
    t.string   "email",           null: false                                                                                                                                                                                    
    t.string   "password_digest"                                                                                                                                                                          
    t.datetime "created_at",      null: false                                                                                                                                                               
    t.datetime "updated_at",      null: false                                                                                                                                                             
    t.boolean  "admin"       
  end
end
```

上記のような場合、メールアドレスを持っていないユーザーは前述した、バリデーションをスキップするメソッドを使っても保存できません。


###フロントエンドのバリデーション###
安全性の為というより、ユーザーの為のバリデーション？です。
フォームなどで必須項目に入力していないと、JSでエラーメッセージなどが出たりするなどのものです。ただ、これはブラウザ側の操作でOffにできるのでバリデーションの強度としては微妙です。ですがユーザビリティを考慮するなら入れるべきバリデーションでしょう。


##多層のバリデーションでセキュアなアプリケーションを実現##

以上の４つの多層の検証によって、不正なデータをはじき、正しいデータを保存することができるのです。

1.フロントエンドレベルでユーザーの入力忘れなどのミスを検証。
2.コントローラーで正しい入力データが送られているか検証。
3.モデルでその入力データの論理性が正しいか検証。
4.DBにて絶対なるデータの検証。



##まとめ##
以上、各バリデーションレベルでの役割でした。正直大したこと書いてません。難しくもありません。がこれを把握しとくと正しいrailsチックなwebアプリケーションを作ることができるのです。
というわけで次回は、このバリデーションレベルをきちんと考慮した、**フォームオブジェクト**なるものを用いたアプリケーション例をご紹介。


##参考にしたの##
バリデーションには3種類のバリデーションがある 〜 セキュアなアプリケーションの構造 〜
https://blog.ohgaki.net/there-are-3-types-of-validations

Rails tips: 知らないと損する4つのバリデーションレベル（翻訳）
https://techracho.bpsinc.jp/hachi8833/2018_05_09/55771