1 はじめに
active hashについては以下の記事に書いています。
「active hash でセレクトボックスをつくる」
今回は某フリマサイトを作成中に起こった思わぬ動作について書いています。
2 生じた問題
今回のアプリケーションではactive hashで複数のモデルを作成していました。
年、月、日、都道府県、配送方法、配送負担、発送日数などです。
すべて入力必須項目なのでモデルにnull falseのバリデーションをかけていました。
しかし、ユーザー登録の動作を確認中に問題が生じました。
ミスで生年月日を何も選択せずに登録ボタンを押してしまった時です。
バリデーションをかけているので、当然エラーメッセージが出ると思っていたのですが、登録できてしまいました。
すぐに登録先のモデルとマイグレーションファイルを確認。
null falseのバリデーションは問題なく効いていました。
2 原因
1) active hashのコード
以下が使用していた、生年月日の年のactive hashのモデルです。
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の記述です。
= f.collection_select :birthdayy_id, Birthdayy.all, :id, :year
###3) userマイグレーションファイルのバリデーション
必須事項にバリデーションをかけています。
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モデルのバリデーション
必須事項にバリデーションをかけています。
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
一見問題なさそうですが、原因はこれでした。
1) Birthdayy.rb
の '---' のidが 「0」
2) devise_create_users.rb
でカラムの型をintegerにしている
3) collection_select
で**:id**をparamsで送っている
1~3により、何も選択しなかった場合、「0」がcreateアクション
に送られたためバリデーションをすり抜けてしまったようでした。
3 解決策
解決方法はいくつかあると思います。
- 保存させる数字の範囲を指定する
- integerのうち「0」という数字以外を登録させる
- '---'を使うのを諦める
など
今回は以下の方法を教えてもらったので使用しました。
= f.collection_select :birthdayy_id, Birthdayy.all, :id, :year, prompt: '---'
最後の
prompt: '---'
を記述することで、セレクトタブでは問題なく選択肢に'---'が表示されます。
また、'---'を選択した状態でsubmitを押すと、nullとして送信されるため、null falseでバリデーションに引っ掛かることになるため設定も簡単です。
4、終わりに
チームで開発すると繋がりができて今まで話したことがない人から情報を得られる機会が増えるので大事な期間です。
積極的に他チームの人と繋がりましょう。
以上です。最後までご覧いただきありがとうございました。