active hashでdbに登録させる時の注意点

# １　はじめに
active hashについては以下の記事に書いています。

**「active hash でセレクトボックスをつくる」**
>https://qiita.com/DON4024/items/78edb7a309ee96766952

今回は某フリマサイトを作成中に起こった思わぬ動作について書いています。


# 2　生じた問題
今回のアプリケーションではactive hashで複数のモデルを作成していました。
年、月、日、都道府県、配送方法、配送負担、発送日数などです。
すべて入力必須項目なのでモデルに**null false**のバリデーションをかけていました。


しかし、ユーザー登録の動作を確認中に問題が生じました。
ミスで生年月日を何も選択せずに登録ボタンを押してしまった時です。
バリデーションをかけているので、当然エラーメッセージが出ると思っていたのですが、**登録できて**しまいました。

すぐに登録先のモデルとマイグレーションファイルを確認。
**null false**のバリデーションは問題なく効いていました。


# 2　原因

### 1) active hashのコード

以下が使用していた、生年月日の年のactive hashのモデルです。

```Birthdayy.rb
class Birthdayy < ActiveHash::Base
  self.data = [
      {id: 0, year: '---'},
      {id: 1, year: '2020'}, {id: 2, year: '2019'}, {id: 3, year: '2018'}, {id: 4, year: '2017'}, {id: 5, year: '2016'}, 
      {id: 6, year: '2015'}, {id: 7, year: '2014'}, {id: 8, year: '2013'}, {id: 9, year: '2012'}, {id: 10, year: '2011'}, 
      {id: 11, year: '2010'}, {id: 12, year: '2009'}, {id: 13, year: '2008'}, {id: 14, year: '2007'}, {id: 15, year: '2006'}, 
      {id: 16, year: '2005'}, {id: 17, year: '2004'}, {id: 18, year: '2003'}, {id: 19, year: '2002'}, {id: 20, year: '2001'}, 
      {id: 21, year: '2000'}, {id: 22, year: '1999'}, {id: 23, year: '1998'}, {id: 24, year: '1997'}, {id: 25, year: '1996'}, 
      {id: 26, year: '1995'}, {id: 27, year: '1994'}, {id: 28, year: '1993'}, {id: 29, year: '1992'}, {id: 30, year: '1991'}, 
      {id: 31, year: '1990'}, {id: 32, year: '1989'}, {id: 33, year: '1988'}, {id: 34, year: '1987'}, {id: 35, year: '1986'}, 
      {id: 36, year: '1985'}, {id: 37, year: '1984'}, {id: 38, year: '1983'}, {id: 39, year: '1982'}, {id: 40, year: '1981'}, 
      {id: 41, year: '1980'}, {id: 42, year: '1979'}, {id: 43, year: '1978'}, {id: 44, year: '1977'}, {id: 45, year: '1976'}, 
      {id: 46, year: '1975'}, {id: 47, year: '1974'}, {id: 48, year: '1973'}, {id: 49, year: '1972'}, {id: 50, year: '1971'}, 
      {id: 51, year: '1970'}, {id: 52, year: '1969'}, {id: 53, year: '1968'}, {id: 54, year: '1967'}, {id: 55, year: '1966'}, 
      {id: 56, year: '1965'}, {id: 57, year: '1964'}, {id: 58, year: '1963'}, {id: 59, year: '1962'}, {id: 60, year: '1961'}, 
      {id: 61, year: '1960'}, {id: 62, year: '1959'}, {id: 63, year: '1958'}, {id: 64, year: '1957'}, {id: 65, year: '1956'}, 
      {id: 66, year: '1955'}, {id: 67, year: '1954'}, {id: 68, year: '1953'}, {id: 69, year: '1952'}, {id: 70, year: '1951'}, 
      {id: 71, year: '1950'}, {id: 72, year: '1949'}, {id: 73, year: '1948'}, {id: 74, year: '1947'}, {id: 75, year: '1946'}, 
      {id: 76, year: '1945'}, {id: 77, year: '1944'}, {id: 78, year: '1943'}, {id: 79, year: '1942'}, {id: 80, year: '1941'}, 
      {id: 81, year: '1940'}, {id: 82, year: '1939'}, {id: 83, year: '1938'}, {id: 84, year: '1937'}, {id: 85, year: '1936'}, 
      {id: 86, year: '1935'}, {id: 87, year: '1934'}, {id: 88, year: '1933'}, {id: 89, year: '1932'}, {id: 90, year: '1931'}, 
      {id: 91, year: '1930'}, {id: 92, year: '1929'}, {id: 93, year: '1928'}, {id: 94, year: '1927'}, {id: 95, year: '1926'}, 
      {id: 96, year: '1925'}, {id: 97, year: '1924'}, {id: 98, year: '1923'}, {id: 99, year: '1922'}, {id: 100, year: '1921'}, 
  ]
end
```

###2) registrationコントローラー　new.html.haml

ユーザー登録ページのhamlの記述です。

```new.html.haml
= f.collection_select :birthdayy_id, Birthdayy.all, :id, :year
```

###3) userマイグレーションファイルのバリデーション

必須事項にバリデーションをかけています。

```devise_create_users.rb

class DeviseCreateUsers < ActiveRecord::Migration[5.2]
  def change
    create_table :users do |t|
      ## Database authenticatable
      ---省略---
      t.integer :birthdayy_id, null: false
      t.integer :birthdaym_id, null: false
      t.integer :birthdayd_id, null: false
      ---省略---
  end
end

```

###4) userモデルのバリデーション

必須事項にバリデーションをかけています。

```user.rb
class User < ApplicationRecord
  ---省略---
  extend ActiveHash::Associations::ActiveRecordExtensions
  belongs_to_active_hash :birthdayy
  belongs_to_active_hash :birthdaym
  belongs_to_active_hash :birthdayd

  ---省略---
  validates :birthdayy_id, presence: true
  validates :birthdaym_id, presence: true
  validates :birthdayd_id, presence: true
  ---省略---
end
```

一見問題なさそうですが、原因はこれでした。
１)　`Birthdayy.rb`の **'---'** のidが 「**0**」
２)　`devise_create_users.rb`でカラムの型を**integer**にしている
３)　`collection_select`で**:id**をparamsで送っている

1~3により、何も選択しなかった場合、「**0**」が`createアクション`に送られたためバリデーションをすり抜けてしまったようでした。


# ３　解決策

解決方法はいくつかあると思います。

- 保存させる数字の範囲を指定する
- integerのうち「**0**」という数字以外を登録させる
- '---'を使うのを諦める
など

今回は以下の方法を教えてもらったので使用しました。

```
= f.collection_select :birthdayy_id, Birthdayy.all, :id, :year, prompt: '---'

```
最後の

```
prompt: '---'
```
を記述することで、セレクトタブでは問題なく選択肢に'---'が表示されます。

<br>

<img width="300" alt="" src="https://i.gyazo.com/a16d5823087a1cc04b9344ed2811bc4d.png">  <img width="300" alt="" src="https://i.gyazo.com/555ac774f124190e99a88dc57d4b49e7.png">

---

また、'---'を選択した状態でsubmitを押すと、nullとして送信されるため、null falseでバリデーションに引っ掛かることになるため設定も簡単です。


<img width="500" alt="" src="https://i.gyazo.com/814cc4c6fec61bba22ba3eee5f48b8c3.png">

# ４、終わりに

チームで開発すると繋がりができて今まで話したことがない人から情報を得られる機会が増えるので大事な期間です。
積極的に他チームの人と繋がりましょう。

<br>
以上です。最後までご覧いただきありがとうございました。
<br>