Help us understand the problem. What is going on with this article?

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

More than 1 year has passed since last update.

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

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

まずバリデーションを振り返る

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

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

バリデーションの認識の違い

初心者なワイの認識

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

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

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

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

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にできるのでバリデーションの強度としては微妙です。ですがユーザビリティを考慮するなら入れるべきバリデーションでしょう。

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

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

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

Why do not you register as a user and use Qiita more conveniently?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away