ActiveRecordのEnumの取り扱い方


概要

ActiveRecordを継承したモデルでバリデーションエラーを発生させた際に、特定のバリデーションに反応したのか判定する

どういうときに使うかと言うと、具体的な例を挙げると、valid?とかsave際にある属性の空文字チェックでエラーになっているかどうかというようなことを調べる


前提条件

Rails: 5.2

Ruby: 2.6.1


本題

サンプルのユーザテーブルの定義

create_table :users do |t|

t.string :name
t.integer :state
t.timestamps
end

ユーザモデルの定義

nameの空文字チェックのバリエーションがある

class User < ApplicationRecord

validates :name, presence: true
enum state: { show: 0, hide: 1 }
end

モデルを一つ取得し、これをもとに説明する

> u = User.first

User Load (0.2ms) SELECT "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT ? [["LIMIT", 1]]
=> #<User id: 2, name: "テスト1", created_at: "2019-01-29 03:56:08", updated_at: "2019-03-11 02:52:09", state: "hide">


stateを単純に出力すると、DBに格納されている数値ではなく、enumで定義した文字列が表示される

> u.state

=> "hide"


代入方法

enumで定義したシンボルでも、文字列でも、DBに実際に格納される数値でも代入できる

シンボルの場合

u.state = :hide

=> :hide
irb(main):038:0> u.state
=> "hide"

文字列の場合

u.state = "show"

=> "show"
irb(main):046:0> u.state
=> "show"

数値の場合

> u.state = 0

=> 0
> u.state
=> "show"


定義外の値を代入すると

enumで定義した範囲外の数値を代入しようとするとエラーになる

> u.state = "show2"

ArgumentError ('show2' is not a valid state)

irb(main):047:0> u.state = "show2"
Traceback (most recent call last):
1: from (irb):47
ArgumentError ('show2' is not a valid state)

> u.state = :show2
ArgumentError ('show2' is not a valid state)

> u.state = 2
ArgumentError ('2' is not a valid state)

### 格納されている実際の値を参照する

デバッグやテストのときなどu.stateとすると実際にどの値が格納されているか確認したい場合は

read_attribute_before_type_castや属性名_before_type_castを使う

> u.state

=> "hide"

u.read_attribute_before_type_cast(:state)
=> 1
irb(main):070:0> u.state_before_type_cast
=> 1