ウィザード形式でユーザ登録のフォームを作成してみた③-1　〜バリデーション〜

## 【この記事の説明】
現在、私はプログラミングスクールでプログラミング（主にRuby）の勉強をしています。
そして、その一環でチーム開発（メルカリもどきのサイト作成）を行っており、私はその中で記事のタイトルにあるように、ウィザード形式でユーザの登録ができるようにする作業を担当致しました。
又、スクールからの指示で、この登録フォームにはdeviseを使用するようにとのことでした。

この記事は、その担当作業についてまとめたものになります。
## 【作業】
ここから私が行った作業（そこで困ったこと）を記事として記載していこうと思います
※この記事では、バリデーションについて記載したいと思います

#### バリデーション
```ruby:必要部分のみ抜粋
def new_profileaddresses
    unless @user.valid?
      flash.now[:alert] = @user.errors.full_messages
      render :new and return
    end
end

def new_deliveryaddresses
    unless @profileaddress.valid?
      flash.now[:alert] = @profileaddress.errors.full_messages
      render :new_profileaddresses and return
    end
end

def create
    unless @deliveryaddress.valid?
      flash.now[:alert] = @deliveryaddress.errors.full_messages
      render :new_deliveryaddresses and return
    end
end

```
上記はunless xxx.valid?~endにより、バリデーションに引っかかった場合はrenderによってviewに飛ばされるようになっていることを記述しています

このvalid?のバリデーションはmodelに記述することで発動します
その為、私は下記のようにmodelに記述し、バリデーションをかけました

#### model
```ruby:/app/models/user.rb
class User < ApplicationRecord
  # Include default devise modules. Others available are:
  # :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :validatable,password_length: 7..128
         
  validates :nickname, presence: true
  validates :family_name, presence: true
  validates :given_name, presence: true
  validates :family_name_kana, presence: true
  validates :given_name_kana, presence: true
  validates :birthday, presence: true
  
  has_one :profileaddress, dependent: :destroy
  has_one :deliveryaddress, dependent: :destroy

  # パスワード英字数字１文字かつ７文字以上のバリデーション↓
  validate :password_complexity
  # 全角のバリデーション↓
  validate :name_em
  validate :name_kana_em
  # メールアドレスのバリデーション↓
  validate :valid_email?


  def valid_email?
    return if email.blank? || email =~ /^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/
    # blank?はblankであれば"true"でblankでなければ"flase"を返す
    # ||は"または"であり左側が"false"なら右側を"return"する
    # つまり"email.blank?"が"false(ブランクではない)"場合、"email"を正規表現にかけるということになる
  end
  def password_complexity
    # Regexp extracted from https://stackoverflow.com/questions/19605150/regex-for-password-must-contain-at-least-eight-characters-at-least-one-number-a
    return if password.blank? || password =~ /^(?=.*?[a-zA-Z])(?=.*?[0-9]).{7,70}$/
    # blank?-値がない状態がture
    errors.add :password, "は英字と数字をそれぞれ1文字以上含める必要があります"
    # password.blank? || password =~ のどちらも"false"だからエラーになり、エラー表示される
  end

  def name_em
    if !(family_name =~ /^[ぁ-んァ-ン一-龥]/)
      if !(given_name =~ /^[ぁ-んァ-ン一-龥]/)
        errors.add :family_name, "は全角で入力してください"
        errors.add :given_name, "は全角で入力してください"
      else
        errors.add :family_name, "は全角で入力してください"
      end
    elsif !(given_name =~ /^[ぁ-んァ-ン一-龥]/)
      errors.add :given_name, "は全角で入力してください"
    else
      return
    end
  end

  def name_kana_em
    if !(family_name_kana =~ /^([ァ-ン]|ー)+$/)
      if !(given_name_kana =~ /^([ァ-ン]|ー)+$/)
        errors.add :family_name_kana, "は全角カタカナで入力してください"
        errors.add :given_name_kana, "は全角カタカナで入力してください"
      else
        errors.add :family_name_kana, "は全角カタカナで入力してください"
      end
    elsif !(given_name_kana =~ /^([ァ-ン]|ー)+$/)
      errors.add :given_name_kana, "は全角カタカナで入力してください"
    else
      return
    end
  end
end
```
Userモデルに関しては、deviseに元々備わっているものも利用している為、このような形になりました
下の２つのモデルはdeviseが関係ないので、全て私がバリデーションを記述した形になります

```ruby:/app/models/profileaddress.rb
class Profileaddress < ApplicationRecord
  belongs_to :user, optional: true
  # optional: true は外部キーがnullであることを許可するオプション

  validate :zipcode
  # 郵便番号のバリデーション（ハイフンなし７桁）↑
  validate :full_width_city
  validate :full_width_address
  validate :full_width_building
  # 全角のみ入力設定（半角ではない設定）↑
  def zipcode
    return if postal_code.blank? || postal_code =~ /\A\d{7}\z/
    @error_name = I18n.t(User.human_attribute_name(:postal_code))
    # ja.ymlからデータを引っ張ってきている↑
    errors.add @error_name, "は不当な値です。ハイフンなし、７桁の数字で入力してください"
  end

  def full_width_city
    return if city.blank? || city =~ /^[^ -~｡-ﾟ]*$/
    @error_name = I18n.t(User.human_attribute_name(:city))
    errors.add @error_name, "は全角で入力してください"
  end
  def full_width_address
    return if address.blank? || address =~ /^[^ -~｡-ﾟ]*$/
    @error_name = I18n.t(User.human_attribute_name(:address))
    errors.add @error_name, "は全角で入力してください"
  end
  def full_width_building
    return if building.blank? || building =~ /^[^ -~｡-ﾟ]*$/
    @error_name = I18n.t(User.human_attribute_name(:building))
    errors.add @error_name, "は全角で入力してください"
  end

  enum prefecture:{
    ーーー:0,北海道:1,青森県:2,岩手県:3,宮城県:4,秋田県:5,山形県:6,福島県:7,
    茨城県:8,栃木県:9,群馬県:10,埼玉県:11,千葉県:12,東京都:13,神奈川県:14,
    新潟県:15,富山県:16,石川県:17,福井県:18,山梨県:19,長野県:20,
    岐阜県:21,静岡県:22,愛知県:23,三重県:24,
    滋賀県:25,京都府:26,大阪府:27,兵庫県:28,奈良県:29,和歌山県:30,
    鳥取県:31,島根県:32,岡山県:33,広島県:34,山口県:35,
    徳島県:36,香川県:37,愛媛県:38,高知県:39,
    福岡県:40,佐賀県:41,長崎県:42,熊本県:43,大分県:44,宮崎県:45,鹿児島県:46,沖縄県:47
  }
  
end
```
```ruby:/app/models/deliveryaddress.rb
class Deliveryaddress < ApplicationRecord
  # validates :family_name, presence: true
  # ↑のようにバリデーションすると日本語化できないので↓のメソッドでバリデーションしてます

  belongs_to :user,optional: true

  # 全角(＆空白)のバリデーション↓
  validate :name_em
  validate :name_kana_em

  # 決まった桁の数字を入力するバリデーション↓
  validate :zipcode
  validate :phone_number_check

  # 全角のみ入力設定（半角ではない設定）↓
  validate :full_width_city
  validate :full_width_address
  validate :full_width_building
  

  enum prefecture:{
    北海道:1,青森県:2,岩手県:3,宮城県:4,秋田県:5,山形県:6,福島県:7,
    茨城県:8,栃木県:9,群馬県:10,埼玉県:11,千葉県:12,東京都:13,神奈川県:14,
    新潟県:15,富山県:16,石川県:17,福井県:18,山梨県:19,長野県:20,
    岐阜県:21,静岡県:22,愛知県:23,三重県:24,
    滋賀県:25,京都府:26,大阪府:27,兵庫県:28,奈良県:29,和歌山県:30,
    鳥取県:31,島根県:32,岡山県:33,広島県:34,山口県:35,
    徳島県:36,香川県:37,愛媛県:38,高知県:39,
    福岡県:40,佐賀県:41,長崎県:42,熊本県:43,大分県:44,宮崎県:45,鹿児島県:46,沖縄県:47
  }

  def name_em
    @error_name1 = I18n.t(User.human_attribute_name(:family_name))
    @error_name2 = I18n.t(User.human_attribute_name(:given_name))
    if !(family_name =~ /^[ぁ-んァ-ン一-龥]/)
      if !(given_name =~ /^[ぁ-んァ-ン一-龥]/)
        errors.add @error_name1, "は全角で入力してください"
        errors.add @error_name2, "は全角で入力してください"
      else
        errors.add @error_name1, "は全角で入力してください"
      end
    elsif !(given_name =~ /^[ぁ-んァ-ン一-龥]/)
      errors.add @error_name2, "は全角で入力してください"
    else
      return
    end
  end

  def name_kana_em
    @error_name3 = I18n.t(User.human_attribute_name(:family_name_kana))
    @error_name4 = I18n.t(User.human_attribute_name(:given_name_kana))
    if !(family_name_kana =~ /^([ァ-ン]|ー)+$/)
      if !(given_name_kana =~ /^([ァ-ン]|ー)+$/)
        errors.add @error_name3, "は全角カタカナで入力してください"
        errors.add @error_name4, "は全角カタカナで入力してください"
      else
        errors.add @error_name3, "は全角カタカナで入力してください"
      end
    elsif !(given_name_kana =~ /^([ァ-ン]|ー)+$/)
      errors.add @error_name4, "は全角カタカナで入力してください"
    else
      return
    end
  end

  def phone_number_check
    return if phone_number.blank? || phone_number =~ /\A\d{10,11}\z/
    @error_name5 = I18n.t(User.human_attribute_name(:phone_number))
    errors.add @error_name5, "は不当な値です。ハイフンなし、10桁,又は11桁の番号で入力してください"
  end

  def zipcode
    return if postal_code =~ /\A\d{7}\z/
    @error_name6 = I18n.t(User.human_attribute_name(:postal_code))
    errors.add @error_name6, "はハイフンなし、７桁の数字で入力してください"
  end

  def full_width_city
    if city.blank? 
      @error_name7 = I18n.t(User.human_attribute_name(:city))
      errors.add @error_name7, "は全角で入力してください"
    elsif !(city =~ /^[^ -~｡-ﾟ]*$/)
      @error_name7 = I18n.t(User.human_attribute_name(:city))
      errors.add @error_name7, "は全角で入力してください"
    else
      return
    end
  end

  def full_width_address
    if address.blank?
      @error_name8 = I18n.t(User.human_attribute_name(:address))
      errors.add @error_name8, "は全角で入力してください"
    elsif !(address =~ /^[^ -~｡-ﾟ]*$/)
      @error_name8 = I18n.t(User.human_attribute_name(:address))
      errors.add @error_name8, "は全角で入力してください"
    else
    end
  end
  def full_width_building
    return if building.blank? || building =~ /^[^ -~｡-ﾟ]*$/
    @error_name9 = I18n.t(User.human_attribute_name(:building))
    errors.add @error_name9, "は全角で入力してください"
  end
end

```
**必須と任意**
今回の入力フォームには、入力必須のフォームと任意のフォームがあり、バリデーションはそれに合わせて作成しました
例えば```deliveryaddress.rb```の場合は下記のような形になります
addressは入力必須項目
buildingは入力任意項目


```ruby:必要部分のみ抜粋

  def full_width_address
    if address.blank?
      @error_name8 = I18n.t(User.human_attribute_name(:address))
      errors.add @error_name8, "は全角で入力してください"
      # 空白ならエラーを表示する
    elsif !(address =~ /^[^ -~｡-ﾟ]*$/)
      @error_name8 = I18n.t(User.human_attribute_name(:address))
      errors.add @error_name8, "は全角で入力してください"
      # 正規表現にあっていない場合はエラーを表示する
    else
      # それ以外はバリデーション通過
    end
  end
  def full_width_building
    return if building.blank? || building =~ /^[^ -~｡-ﾟ]*$/
     # ブランク又は正規表現通り（この場合は半角ではない、つまり全角）だったらtrueでそのまma
     # ブランクでもなく、正規表現通りでもない（つまりは半角）だったらどちらもfalseでエラーとなり、エラー表示対象
    @error_name9 = I18n.t(User.human_attribute_name(:building))
    errors.add @error_name9, "は全角で入力してください"
  end

```
#### 【次の記事】
バリデーションをかければ、データ（一時）保存する時も、不必要なデータが入ることは無くなります
しかし、そこにエラー表示がないと入力しているユーザは何故データが保存されないのかわからず、困ってしまいます
その為、エラー表示はユーザの為にも必要なものです
次の記事では、そのエラー表示について記載したいと思います

**次の記事**　→　[ウィザード形式でユーザ登録のフォームを作成してみた③-2　〜バリデーション(エラー表示)〜](https://qiita.com/niisan3211/items/01a3646ef2ddfaa99d85)

####【参考】
[form用正規表現判定/備忘](https://qiita.com/fubarworld2/items/9da655df4d6d69750c06)
[deviseでパスワードの最低文字数を変更する方法。](https://qiita.com/hirokihello/items/862284c60429be5e01cd)