Rails ｜onオプションを使ってバリデーションのタイミングを指定

## はじめに
こんにちは、[waruby510](https://twitter.com/waruby510)です。

今回、初めてQiitaへの記事を投稿させていただきます。

最近、色んな方の記事に助けてもらってばかりの状況なので、
**備忘録＆同じ初学者の力になれる内容** を簡単にですが、記事にしてみました。

<br>

内容は、タイトル通りですが、

**validatesメソッドのonオプションを使って、バリデーションのタイミングを指定してみた** 

と言う感じです。

もちろん経験者にとっては、かなりイージーな内容になっています。初心者目線でこの記事を書いていますので、ご了承ください。
また、あまり奥深いところまでは書いていないので、今後更新していければと思います。


<補足>
※初心者の立場で記事を書いています。最低限の下調べと実際に動くかどうかは確認していますが、もし誤った内容を記載していた場合は、ご指摘いただければと思います。

※まだまだ文章を書くことに慣れていません。読みにくいかもしれませんが、どうかお付き合いください。


##開発環境

Rails バージョン5.2.2
ruby バージョン2.5.3
※ログイン機能等に関しては、gemのdeviseは使っていません。

## アプリケーション詳細


* ユーザー登録・編集機能　←　今回の記事の問題箇所
* 画像投稿、編集、削除機能 & いいね機能

簡単に言うと、インスタのようなアプリです。

## 発生した問題

ユーザー編集機能を追加した時にある問題に差し掛かりました。
それは、ユーザー編集画面にてパスワード欄を無くしたはずなのに、バリデーションがかかってしまう問題。

<details><summary>参考画像１: ユーザー編集画面にてバリデーション起動</summary>
<img width="487" alt="スクリーンショット 2019-01-27 11.32.43.png" src="https://qiita-image-store.s3.amazonaws.com/0/308269/b2c66598-722f-ac81-e177-0e4ccf272a84.png">
</details>

仕方なく、編集画面にもパスワード入力欄を設けて対応しましたが、
ユーザー目線で考えたら、使いにくいの一言。

実際、userモデルに対しては、以下のようなバリデーションを追加していました。

```ruby:user.rb
class User < ApplicationRecord
  #名前とメールアドレスに対するバリデーション
  validates :name, presence: true, length: {maximum: 30}
  validates :email, presence: true, length: {maximum: 255},format: { with: /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i },uniqueness: true
    
   #略

  #パスワードをハッシュ化
  has_secure_password
  #パスワードに対するバリデーション
  validates :password, presence: true, length: {minimum: 6}
 
   #略

end
```

## 考えられる原因

バリデーションのデフォルトでは、レコードの作成時、更新時。つまり保存が促されるときに実行されるように設定されている。つまり、編集時にパスワードがないとバリデーションがかかってしまいます。
冷静に考えてみると、ただ編集画面のパスワード欄の表示を消しているだけなので、バリデーションがかかるのも当たり前ですよね。笑

考えれる対応策としては、バリデーションのかかるタイミングを指定できれば解決できそう。


## 実際にやったこと

Userモデルのpasswordカラムに対して、`on: :create`　を追加

```ruby:user.rb
#on: :create　を追加
validates :password, presence: true, length: {minimum: 6}, on: :create
```
<br>




ここでようやく`on`オプションの登場です。
ここまで、長々と書いてきましたが、たったこれだけです......笑


バリデーションのタイミングを特定して実行したい場合、`on: メソッド名`とオプションを追加することで、そのアクションの時のみバリデーションを実行することができるみたいです。

今回は、ユーザー登録時のみパスワードのバリデーションを起動させたいので、`on: :create`とします。

もしメソッド名を`on: update`にすれば、編集の更新時のみバリデーションがかかるという仕組みなのです。
個人的には結構使いそうな予感。

今回は、RailsGuideの下記リンクを参考にしました。


>参考リンク: [RailsGuide](https://railsguides.jp/active_record_validations.html#on)

>3.4 :on
:onオプションは、バリデーション実行のタイミングを指定します。ビルトインのバリデーションヘルパーは、デフォルトでは保存時に実行されます。これはレコードの作成時および更新時のどちらの場合にも行われます。バリデーションのタイミングを変更したい場合、on: :createを指定すればレコード新規作成時にのみ検証が行われ、on: :updateを指定すればレコードの更新時にのみ検証が行われます。

>```ruby:
>class Person < ApplicationRecord
  ># 値が重複していてもemailを更新できる
  >validates :email, uniqueness: true, on: :create
 
  ># 新規レコード作成時に、数字でない年齢表現を使用できる
  >validates :age, numericality: true, on: :update
 
  ># デフォルト (作成時と更新時のどちらの場合にもバリデーションを行なう)
  >validates :name, presence: true
>end
>```


実際に、編集画面の動作を確認してみました。

<details><summary>参考画像2: ユーザー編集画面にてバリデーション回避</summary>
<img width="422" alt="スクリーンショット 2019-01-27 12.35.13.png" src="https://qiita-image-store.s3.amazonaws.com/0/308269/734aca77-adfd-93f3-b68d-25aa51f917e7.png">
</details>

見事にパスワードに対するバリデーションが回避されています。
少しはユーザー目線の機能に近づけた気がします。
今の自分の良いところは、初心者ということもあり、ユーザー目線に近い状態で開発ができるということ。この目線は今後も大事にしていきたいと思います。

## さいごに

結論が呆気なくて、すみませんでした。
自分自身もこれだけ？っていう感じでしたが、とてもいい勉強になりました。

ただ、まだまだ便利な使い方が間違いなくあるはずなので、これから学習していく中で整理していき、また記事にできればと思います。

ここまで読んでくださった方、本当にありがとうございます。

今回は、初めてということもあり、Markdown記法に慣れるために色々な記法を使って書いてみました。そのため、無駄に記事が長くなってしまいましたが、個人的にはかなりいい練習ができたと思います。

この記事が誰かのお役に立てれれば本望です。

以上です。