更新日:
【Rails】 enumチュートリアル
enumとは、1つのカラムに指定した複数個の定数を保存できる様にする為のモノです。
enumとは、1つのカラムに指定した複数個の定数を保存できる様にする為のモノです。
1
2
# 定義
enum blood_type: { A: 0, B: 1, O: 2, AB: 3 }
1
2
3
4
5
6
7
# 複数個の定数リスト
User.blood_types
=> {"A"=>0, "B"=>1, "O"=>2, "AB"=>3}
# Userインスタンスのenumカラムの定数を表示
User.find_by(blood_type: 'A').blood_type
=> "A"
このenumを使うと指定した複数個の定数以外の値は保存できない様にしたり、カラムに指定した定数が入っているレコードを取り出すのが容易になったりと多くのエンジニアが頻繁に使用する大変便利なメソッドです。
enumの定義方法
enumの使い方や仕組みについては、定義のされ方とセットで覚えるとenumを簡単に理解できるので
早速enumを使う準備を整えて行きましょう。
enumを使うためには
- テーブルにenum用のカラムを用意する
- モデルにenumの定義をする
この2つの準備が必要になります。
enumは具体例を持って説明するほうが分かり易いので、プログラマンファミリーを例にenumを説明します。
以下はプログラマンファミリーのそれぞれのメンバーが載っているusersテーブル
の情報です。
usersテーブル
id | name | age |
---|---|---|
1 | programan | 25 |
2 | programan_father | 58 |
3 | programan_mother | 58 |
4 | programan_bigsister | 30 |
5 | programan_sister | 20 |
6 | programan_bigbrother | 28 |
7 | programan_brother | 22 |
このテーブルにenum用のカラムを追加してenumを説明していきます。
tableにenum用のカラムを用意
enumは、指定した複数個の定数を保存できると言いましたが、その型についてはInteger型かboolean型になります。
複数個の定数を保存できると言ったのになぜデータの型はInteger型かboolean型になるかは後述するので、ここではenumは整数(0, 1, 2等)か真偽値(true, false)でDBに保存されるということだけ覚えておきましょう。
integerの場合
integer型でenumを定義する場合を説明していきます。今tableはこの様なカラムの設計になっております。
1
2
3
4
5
6
7
8
9
10
class CreateUsers < ActiveRecord::Migration[5.2]
def change
create_table :users do |t|
t.string :name, null: false, default: ""
t.integer :age, null: false
t.timestamps
t.timestamps
end
end
end
ここにenum用のカラムblood_typeを追加します。
1
2
3
4
5
6
7
8
9
10
11
12
class CreateUsers < ActiveRecord::Migration[5.2]
def change
create_table :users do |t|
t.string :name, null: false, default: ""
t.integer :age, null: false
# 新しくenum用のinteger型のblood_typeカラムを追加
t.integer :blood_type, null: false, default: 0
t.timestamps
t.timestamps
end
end
end
今回追加したblood_typeカラム(血液型)がないデータは存在しない前提なので、null: false
にしdefault: 0(初期値には0)
を指定します。またinteger型は整数値を保存する型で2個以上の定数と紐づけることができます。理由は後述するので、2個以上の定数を紐付けたい場合は型はinteger型で定義すると覚えておきましょう。
booleanの場合
boolean型でenumを定義する場合を説明していきます。boolean型のenum用のis_marriedカラムを追加します。
1
2
3
4
5
6
7
8
9
10
11
12
13
class CreateUsers < ActiveRecord::Migration[5.2]
def change
create_table :users do |t|
t.string :name, null: false, default: ""
t.integer :age, null: false
t.integer :blood_type, null: false, default: 0
# 新しくenum用のboolean型のis_marriedカラムを追加
t.boolean :is_married, null: false, default: false
t.timestamps
t.timestamps
end
end
end
今回追加したis_marriedカラム(既婚者かどうかを表すカラム)でも必ずデータは入る前提なので、null: false
にしdefault: false(初期値にはfalse)
を指定します。is_marriedカラムがfalse
であれば独身を表し、true
であれば既婚者を表すという意味のカラムです。
またboolean型は真偽値を保存する型で2個の定数しか紐づけることができません。理由は後述するので、2個の定数を紐付けたい場合かつ真偽値を保存したい時はboolean型で定義すると覚えておきましょう。
これでテーブルの準備は出来ました。続いてモデルの定義に移っていきます。
モデルの定義
テーブルにenumのカラムを用意したら、次はenumのカラムに複数個の定数を紐付けていきます。定義の仕方と一緒に定数の紐付け方とデータ保存のされ方を見ていきましょう。
integerの場合
enumは1つのカラムに指定した複数個の定数を保存できる様にする為のモノと説明しました。
それは簡単にいうとenumはハッシュで複数個の定数を定義するので、定数の数だけhashの要素を増やすことでリストに登録してる定数を保存できるということです。どういうことか実際に定義と保存をして、データ保存のされ方を見ていきましょう。
1
2
3
class User < ApplicationRecord
enum blood_type: { A: 0, B: 1, O: 2, AB: 3 }
end
上記の様に定義します。
enum blood_type: { A: 0, B: 1, O: 2, AB: 3 }
がどういう意味かというと、blood_typeカラムに0が保存されていればA
という定数として扱うということです。その他の値も同様で1が保存されていればB
、2が保存されていればO
、3が保存されていればAB
とハッシュの様にそれぞれの整数と定数を紐付けています。
上記の様に定義するとデータはどの様に保存されるか確かめるために、実際にO型のユーザーを作成してみます。
1
2
3
4
5
6
7
8
9
10
11
12
User.create(
name: 'programan_mother',
age: 58,
# blood_typeに'O'を指定
blood_type: 'O'
)
INSERT INTO `users` (
`name`, `age`, `blood_type`, `created_at`, `updated_at`)
VALUES (
'programan_mother', 58, 2, '2020-01-25 07:01:24', '2020-01-25 07:01:24'
)
これでユーザーを作成できました!O型のユーザーが作成されているか確認してみましょう。
1
2
3
4
5
6
7
8
9
10
11
12
13
user = User.find_by(name: "programan_mother")
=> #<User:0x007fa7232290f8
id: 1,
name: "programan_mother",
age: 58,
blood_type: "O",
is_married: false,
created_at: Sat, 25 Jan 2020 07:01:24 UTC +00:00,
updated_at: Sat, 25 Jan 2020 07:01:24 UTC +00:00>
user.blood_type
=> "O"
上記の結果を見てみると、実際にO型のユーザーが作成されていることが確認できます。保存されたインスタンスを見てみるとblood_typeにはO
と表示されていますね。ただテーブルの型定義では、blood_typeはinteger型で定義されているのを思い出して下さい。
integer型で定義されているのでO
という文字は保存できないはずです。実際にSequel Proではどの様にデータが保存されているのでしょうか?
Sequel Proで確認してみると、数字の2が保存されています。つまりモデルのenumの定義部分でenum blood_type: { A: 0, B: 1, O: 2, AB: 3 }
とし、hashのkey部分の定数を保存すると、そのkeyに対応するvalueの整数が保存されるということです!
User.create(blood_type: 'A')
→ DBに0が保存されるUser.create(blood_type: 'B')
→ DBに1が保存されるUser.create(blood_type: 'AB')
→ DBに3が保存される
このrailsのインスタンス、モデル、DBの関係を表した画像が下記になります。
この様にDBのカラムの型をintegerに定義して、モデルに定数と整数をhashの形で紐付けることによって1つのカラムと複数個の定数を紐づけることができたのです。では、もし紐付けた定数以外で保存しようとすれば下記の様なエラーが出ます。
1
2
User.create(name: 'unknown_blood_type_programan',age: 40, blood_type: '血液型不明')
ArgumentError: '血液型不明' is not a valid blood_type
このエラーはblood_typeに血液型不明
なんて登録していないよ!というエラー内容です。つまり冒頭で説明した通り、1つのカラムに指定した複数個の定数以外は保存できないということですね。
この様に指定した複数個の定数を1つのカラムで管理でき、もし指定していない定数を保存しようとすれば弾くことができるenumは非常に便利でよく利用されるメソッドです。
今までの説明でenumの仕組みは分かったと思うので、次は配列でenumを定義する方法を簡単に説明していきます。
配列での定義方法
1
2
3
4
5
6
7
class User < ApplicationRecord
# シンボルで定義する場合
enum blood_type: [ :A, :B, :O, :AB ]
# 文字列で定義する場合
enum blood_type: [ "A", "B", "O", "AB" ]
end
配列定義のPointは2つあります。
配列のインデックスは先頭から順に0から数字が入って定数と紐づくので下記の様にDBに保存されます。
User.create(blood_type: 'A')
→ DBに0
が保存されるUser.create(blood_type: 'B')
→ DBに1
が保存されるUser.create(blood_type: 'O')
→ DBに2
が保存されるUser.create(blood_type: 'AB')
→ DBに3
が保存される
今回はAB型
のユーザーを作成しました。配列で定義した通り3が保存されているか確認してみましょう。
上記の画像の通り、3が保存されていることが確認できました。
配列の定義方法もenumの仕組みを理解しているとシンプルですね。保存のされ方を見ると、先ほどのhashの定義と同義の意味であったと理解できたと思います。
1
2
3
class User < ApplicationRecord
enum blood_type: { A: 0, B: 1, O: 2, AB: 3 }
end
上記のコードは下記のコードと実質同義で、整数と紐づいている定数が同じ・保存のされ方も同じです。
1
2
3
4
5
6
class User < ApplicationRecord
# シンボルで定義する場合
enum blood_type: [ :A, :B, :O, :AB ]
# 文字列で定義する場合
enum blood_type: [ "A", "B", "O", "AB" ]
end
ですから、基本的に配列
で定義してもhash
で定義してもどちらでも大丈夫です。特に違いはありません。強いて挙げるならば下記の2つが違いになります。
- 配列で定義する方が
インデックス
が自動で定数と紐づいてくれるので、記述量が少なくすっきりしたコードになる - hashの定数と整数の紐付けは0から始めなくても良い
1は記述の通り配列で定義した方が少なく記述できるので、登録する定数が多くなってくるほどメリットを感じます。
2はどういうことかというと、配列はインデックスが定数と紐づくので必ず0から順に紐付きますが、hashの場合は整数値を指定できるので、enum blood_type: { A: 0, B: 1, O: 2, AB: 3 }
としなくてもenum blood_type: { A: 0, B: 10, O: 20, AB: 30 }
の様なことができます。hashなら保存される整数値を指定できるということですね。
booleanの場合
boolean型で定義するenumの使い方を説明します。boolean型の場合も基本的にenumの仕組みは同じになります。
1
2
3
4
class User < ApplicationRecord
enum blood_type: { A: 0, B: 1, O: 2, AB: 3 }
enum is_married: { single: false, married: true } # 追加
end
boolean型のenumを使う場合はこの様に定義します。どの様に保存するか見てみましょう。
1
2
3
4
5
6
7
8
9
10
User.create(
name: 'programan_bigsister',
age: 22,
blood_type: 'B',
# enumで設定した定数を指定
is_married: 'married'
)
INSERT INTO `users` (`name`, `age`, `blood_type`, `is_married`, `created_at`, `updated_at`)
VALUES ('programan_bigsister', 22, 1, TRUE, '2020-01-28 06:32:16', '2020-01-28 06:32:16')
これでユーザーを作成できました!既婚しているユーザーが作成されているか確認してみましょう。
1
2
3
4
5
6
7
8
9
10
User.find_by(name: 'programan_bigsister')
=> #<User:0x007f82b384ec38
id: 3,
name: "programan_bigsister",
age: 22,
blood_type: "B",
is_married: true,
created_at: Tue, 28 Jan 2020 06:32:16 UTC +00:00,
updated_at: Tue, 28 Jan 2020 06:32:16 UTC +00:00>
booleanのenumはintegerで定義した様に定数とそれに紐づく真偽値(false or true)
を設定して、定数を保存したらそれに紐づく真偽値を保存します。ではDBにはどの様に保存されているか見てみましょう。
booleanの場合、DBではfalse
であれば0、true
の場合は1と保存されます。今回作成したprograman_bigsisterは既婚者として保存したので1が保存されています。
この様にbooleanでenumを設定できますが、booleanの場合にenumを利用することはあまりオススメしません。
理由としては、2点あります。
Rails 5.2系
でfalseにupdateする際にnull
に更新しようとするバグが生じている。- enumを設定しなくてもbooleanだけで充分機能は実装できるのでenumを設定する必要が特にない。
1についてですが現在このprogramanアプリがRails 5.2.1.1
のバージョンで動いてます。このバージョンでenumに設定したbooleanのデータをfalseにupdateしようとするとnil
でupdateされるバグが確認されています。
1
2
3
User.find_by(name: 'programan_bigsister').update(is_married: false)
ActiveRecord::NotNullViolation: Mysql2::Error: Column 'is_married' cannot be null: UPDATE `users` SET `is_married` = NULL,
is_married: 'single'
なら正常にupdate
されるのですが、falseでupdate
すると上記の様なエラーが出ます。また一部enumのメソッドも正常に働かないことがあるので、使用しない方が良さそうですね。
そこで2に話が移るのですが、そもそもenumは指定した複数の定数だけしか保存できないことが魅力なので、booleanの真偽値を入れる場合は、enumを設定しなくても充分にbooleanの役割は果たせます。
私も機能を実装するときは基本的にboolean
のカラムにはenumを設定しません。
ユーザー作成フォームから作成するユーザーのステータスを、独身か既婚者どちらかに設定したい場合があるとします。そのとき、checkbox
で既婚か独身かを選ぶのもtrueかfalseの真偽値をform
から送信すれば良いだけなので、特に指定した定数は必要ありません。
boolean型のカラムを作成したときは、is_married
カラムの様に二択しか入らない状態の様なカラムにすることが重要です。その様な設計になっていればboolean型でenumを使用する必要は特にないので、モデルでのboolean型のenumの指定は削除しましょう。
以上のことからenumを使うときはinteger型で定義するのをおすすめします。
それでは、次はenumを定義する上でのよくある注意点を説明します。
enumを定義する上での注意点
enumのカラムを設定するときに気をつけないといけないことは、カラムに予約語を設定することです。
予約語とは、言語側(今回で言うとruby)で既にこの単語は言語で使用しているから使わないでね!という単語のことです。例えばrubyではnil
とは何もないという意味があります。これを変数で定義すると、どうなるか見てみましょう。
1
2
nil = '何もない'
SyntaxError: (irb):1: Can't assign to nil
上記の様に、nil
は既にruby側で定義しているので変数として定義できないというエラーが出ています。これはつまり、ruby側でnil
という単語は何もないという意味で既に予約している(定義している)ので、変数としては使わないでね!ということですね。この様に言語側で既に使うと予約してる単語を予約語と言います。
enumは複数の定数を登録するので、カラム名をActiveRecordで使用している予約語のtype
にしてしまいがちです。予約語はカラム名として使えないためエラーになってしまいますので注意しましょう。
試しに先ほどのblood_typeカラムを予約語のtypeカラムにしてみます。
1
2
3
4
5
6
7
8
9
10
11
12
13
class CreateUsers < ActiveRecord::Migration[5.2]
def change
create_table :users do |t|
t.string :name, null: false, default: ""
t.integer :age, null: false
# blood_typeカラムを予約語のtypeカラムに変更
t.integer :type, null: false, default: 0
t.boolean :is_married, null: false, default: false
t.timestamps
t.timestamps
end
end
end
↑に変更して、ユーザーを作成してみます。
1
2
3
User.create(name: '予約語type登録', age: 0, type: 'A')
ActiveRecord::SubclassNotFound: The single-table inheritance mechanism failed to locate the subclass: 'A'. This error is raised because the column 'type' is reserved for storing the class in case of inheritance. Please rename this column if you didn't intend it to be used for storing the inheritance class or overwrite User.inheritance_column to use another column for that information.
↑の様なエラーが出ました。いろいろ書かれていますが、注目すべきなのは、This error is raised because the column 'type' is reserved for storing the class in case of inheritance. Please rename this colum
の部分で、「typeは予約語だからエラーが起こりました、カラム名を変えてください。」という内容です。
これをtype
からblood_type
に書き換えるとうまくいきます。
1
2
3
4
5
6
7
8
9
10
11
12
13
class CreateUsers < ActiveRecord::Migration[5.2]
def change
create_table :users do |t|
t.string :name, null: false, default: ""
t.integer :age, null: false
# 予約語のtypeからblood_typeに変更
t.integer :blood_type, null: false, default: 0
t.boolean :is_married, null: false, default: false
t.timestamps
t.timestamps
end
end
end
blood_typeカラムに変更しました。登録できるか試してみます。
登録できましたね!
enumは複数の定数を登録できるのでカラム名をtypeにしたくなりますが、typeは予約語でカラム名に設定するとエラーが出るので注意しましょう。
enumの便利なメソッド
1つのカラムに指定した複数の定数を入れられて、それ以外の定数の場合には弾くことができる便利なモノがenumと伝えてきました。今回は、そんなenumで利用できるさらに便利なメソッドを紹介していきます。この便利なメソッドを使いこなせる様になったら簡潔で読み易いコードになるので、しっかり理解していきましょう!
これまでusersテーブルのレコードがない状態でenumの仕組みを説明してきましたが、これから先はテーブルにレコードがある方が便利なメソッドや使い方について理解し易くなるので、下記のusersテーブルのレコードがある状態でenumについて説明していきます。
usersテーブル
id | name | age | blood_type | is_married |
---|---|---|---|---|
1 | programan | 25 | A | false |
2 | programan_father | 58 | A | true |
3 | programan_mother | 58 | O | true |
4 | programan_bigsister | 30 | B | true |
5 | programan_sister | 20 | AB | false |
6 | programan_bigbrother | 28 | A | true |
7 | programan_brother | 22 | O | true |
確認メソッド
enumには便利な確認メソッドがあります。確認メソッドとは何かというと、今enumカラム(blood_type)に入っている定数が何なのか確認するメソッドのことです。例題をみていきましょう。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
user = User.find_by(name: 'programan')
=> #<User:0x007f82b7b6fe40
id: 1,
name: "programan",
age: 25,
blood_type: "A",
is_married: false,
created_at: Wed, 29 Jan 2020 01:44:45 UTC +00:00,
updated_at: Wed, 29 Jan 2020 01:44:45 UTC +00:00>
user.blood_type
=> "A"
user.A?
=> true
user.B?
=> false
user.O?
=> false
user.AB?
=> false
user.C?
NoMethodError: undefined method `C?' for #<User:0x007f82b7b6fe40>
確認メソッドは上記の様に使用します。
モデルのインスタンスに対してインスタンス.定数名?
の形でenumカラムであるblood_typeに指定した定数が入っていればtrue
が返ってきて、指定した定数が入っていなければfalse
が返ってきます。
コンソールを見てみるとprogramanの血液型はA型ですね。ですからuser.A?
はtrue
が返ってきます。それ以外のB?
、O?
、AB?
に関しては、指定した定数が該当のインスタンスのblood_type
に入ってないのでfalse
が返ってきます。
そして登録していない定数であるuser.C?
に関しては、エラーが出ます。
このインスタンス.定数名?
の確認メソッドを使うと、簡潔で分かり易いコードになります。
実際の使われ方に関してはenumの確認メソッドを使って条件分岐してデータを表示しようで詳しく説明します。
更新メソッド
更新メソッドも確認メソッドと同様に、使い方は非常にシンプルです。
更新メソッドとは、今enumカラム(blood_type)
に入ってある定数を別の定数に更新するメソッドのことです。
モデルのインスタンスに対してインスタンス.定数名!
の形で使います。
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
user = User.find_by(name: "programan_father")
=> #<User:0x007f82b384d838
id: 2,
name: "programan_father",
age: 58,
blood_type: "A",
is_married: true,
created_at: Wed, 29 Jan 2020 01:44:45 UTC +00:00,
updated_at: Wed, 29 Jan 2020 01:44:45 UTC +00:00>
user.blood_type
=> "A"
user.B!
UPDATE `users` SET `blood_type` = 1, `updated_at` = '2020-01-29 03:41:33' WHERE `users`.`id` = 2
=> true
user.blood_type
=> "B"
user.A!
UPDATE `users` SET `blood_type` = 0, `updated_at` = '2020-01-29 03:42:40' WHERE `users`.`id` = 2
=> true
user.blood_type
=> "A"
user.C!
NoMethodError: undefined method `C?' for #<User:0x007f82b7b6fe40>
UPDATE users SET blood_type = 1, updated_at = '2020-01-29 03:41:33' WHERE users.id = 2
はSQLでidが2のユーザー(programan_father)のblood_typeを1(B)
に更新するという意味ですね。実際にuser.blood_type
でB
と表示されているので、更新されているのが分かると思います。
元々はA型のユーザーなので、またUser.A!
でA型のユーザーに戻しています。
もし指定した定数を定義していなければエラーが出ます。
詳しい使い方についてはこちらのajax(非同期通信)を使ってenumの更新メソッドを使ってデータを更新しようで説明します。
検索メソッド
次はenumカラム(今回であればblood_type)のデータを検索する検索メソッドの使い方について説明します。
この検索メソッドの使い方も非常にシンプルです。
モデルクラスに対してモデルクラス.定数名
の形で使用します。
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
a_type_users = User.A
SELECT `users`.* FROM `users` WHERE `users`.`blood_type` = 0
=> [#<User:0x007f82b50f12e0
id: 1,
name: "programan",
age: 25,
blood_type: "A",
is_married: false,
created_at: Wed, 29 Jan 2020 01:44:45 UTC +00:00,
updated_at: Wed, 29 Jan 2020 01:44:45 UTC +00:00>,
#<User:0x007f82b50f11a0
id: 2,
name: "programan_father",
age: 58,
blood_type: "A",
is_married: true,
created_at: Wed, 29 Jan 2020 01:44:45 UTC +00:00,
updated_at: Wed, 29 Jan 2020 03:42:40 UTC +00:00>,
#<User:0x007f82b50f1060
id: 6,
name: "programan_bigbrother",
age: 28,
blood_type: "A",
is_married: true,
created_at: Wed, 29 Jan 2020 01:44:45 UTC +00:00,
updated_at: Wed, 29 Jan 2020 01:44:45 UTC +00:00>
]
検索メソッドは上記の様にモデルクラスに対してモデルクラス.定数名
の形で使用するとenumカラム(blood_type)
で指定した定数が保存されている全てのデータを取得するメソッドです。今回の場合だとUser.A
とするとA型のユーザーを全て取得しました。
SQLのSELECT users.* FROM users WHERE users.blood_type = 0
を実行していて、enumのAという定数は実質DBでは0なので、blood_typeカラムが0のユーザーを全て取得するという意味になってます。
User.A
とUser.where(blood_type: 0)
は同義になります。
上記の画像を見てみると、コンソールの結果と同じでidが1, 2, 6
のデータが取得されてますね。この様な仕組みでデータを取得できています。
他の定数も同じ様に取得できます。もちろん定義してない定数を指定するとエラーになります。
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
b_type_users = User.B
=> [#<#<User:0x007f82b6217010
id: 4,
name: "programan_bigsister",
age: 30,
blood_type: "B",
is_married: true,
created_at: Wed, 29 Jan 2020 01:44:45 UTC +00:00,
updated_at: Wed, 29 Jan 2020 01:44:45 UTC +00:00>
]
o_type_users = User.O
=> [#<User:0x007f82b3964de8
id: 3,
name: "programan_mother",
age: 58,
blood_type: "O",
is_married: true,
created_at: Wed, 29 Jan 2020 01:44:45 UTC +00:00,
updated_at: Wed, 29 Jan 2020 01:44:45 UTC +00:00>,
#<User:0x007f82b39640a0
id: 7,
name: "programan_brother",
age: 22,
blood_type: "O",
is_married: true,
created_at: Wed, 29 Jan 2020 01:44:45 UTC +00:00,
updated_at: Wed, 29 Jan 2020 01:44:45 UTC +00:00>
]
ab_type_users = User.AB
=> [#<User:0x007f82b5120248
id: 5,
name: "programan_sister",
age: 20,
blood_type: "AB",
is_married: false,
created_at: Wed, 29 Jan 2020 01:44:45 UTC +00:00,
updated_at: Wed, 29 Jan 2020 01:44:45 UTC +00:00>
]
User.C
NoMethodError: undefined method `C' for #<Class:0x007f82bb9eabc0>
検索メソッドの詳しい使い方については、検索メソッドを使ってenumの属性ごとにデータを取得しようで詳しく説明します。
enumカラム_before_type_cast - 整数値取得メソッド
整数値取得メソッドとはDBに保存されている整数値を取得するメソッドです。enumカラム名_before_type_castとして使用します。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
インスタンス.enumカラム名_before_type_cast # 公式
user = User.find_by(blood_type: 'A')
=> [#<User:0x007fc8203c2518
id: 1,
name: "programan",
age: 25,
blood_type: "A",
is_married: false,
created_at: Wed, 29 Jan 2020 01:44:45 UTC +00:00,
updated_at: Wed, 29 Jan 2020 01:44:45 UTC +00:00>
]
user.blood_type_before_type_cast # 例: enumカラムがblood_typeの時
=> 0
例えばA型ユーザーのDBに保存されているblood_typeの整数値はenum blood_type: { A: 0, B: 1, O: 2, AB: 3 }
なので0になりますね。その整数値の0を取得するメソッドが整数値取得メソッドであるenumカラム_before_type_cast
になります。例題を見てみましょう。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
a_type_user = User.find_by(blood_type: 'A')
a_type_user.blood_type_before_type_cast
=> 0
b_type_user = User.find_by(blood_type: 'B')
b_type_user.blood_type_before_type_cast
=> 1
o_type_user = User.find_by(blood_type: 'O')
o_type_user.blood_type_before_type_cast
=> 2
ab_type_user = User.find_by(blood_type: 'AB')
ab_type_user.blood_type_before_type_cast
=> 3
上の例だとa_type_user.blood_type_before_type_cast
のようにすることで整数値を取得できます。DBの整数値を取得したい時に使用しましょう!
定数リスト取得メソッド
定数リスト取得メソッドとは、モデルファイルのenumに記載している複数個の定数リストを取得するメソッドです。
1
2
3
class User < ApplicationRecord
enum blood_type: { A: 0, B: 1, O: 2, AB: 3 }
end
この様にモデルファイルに複数個の定数リストをenumでhash形式で定義してます。
このhashを取得するメソッドが定数リスト取得メソッドになります。
モデルクラス.enumカラム名の複数形
という形で使用します。
1
2
User.blood_types
=> {"A"=>0, "B"=>1, "O"=>2, "AB"=>3}
上記のようにモデルクラス.enumカラム名の複数形
という形で、登録した複数個の定数リストを取得できます。
今回の場合で言うとモデルクラスがUser
、enumカラム名がblood_type
、その複数形なのでUser.blood_types
となります。
取得したハッシュである{"A"=>0, "B"=>1, "O"=>2, "AB"=>3}
の中で、keyだけ欲しい場合・valueだけ欲しい場合は下記の様に書くと取得できます。
1
2
3
4
5
6
7
#keyだけ欲しい場合
User.blood_types.keys
=> ["A", "B", "O", "AB"]
#valueだけ欲しい場合
User.blood_types.values
=> [0, 1, 2, 3]
この定数リスト取得メソッドは、次の章から始まる実際にenumを使っていこうで何度も活躍するので、実践での使い方は次の章でマスターしてもらえればと思います。
それでは、これまで学んできたenumをrailsアプリでどの様に使用できるか?
次の章で実際に自分の手でenumのソースコードを書いて理解することで、enumを自分が使ってるrailsアプリに組み込みましょう!
実際にenumを使っていこう
今までenumの仕組みや便利なメソッドを解説してきましたが、これからは実際にenumをどういう場面で利用できるのか手を動かして実装していきましょう。enumを理解するためのアプリを作成したので、git clone
して環境を整えていきましょう。
git cloneしてenumのアプリを実行できる環境を作ろう
enumのrailsアプリケーションの環境を整えるために、下記のコマンドを一つずつ実行していきましょう。
1
2
3
4
5
6
$ git clone -b enum https://github.com/miyagit/programan_dojo.git
$ cd programan_dojo
# programan_dojoのディレクトリにいるか確認
$ pwd
/Users/pikawaka/programan_dojo
これでenumアプリケーションのprograman_dojoまで移動できました。次はprograman_dojoの環境を構築していきます。下記の様にbundle install
を実行してください。
1
2
3
$ bundle install
Bundle complete! 22 Gemfile dependencies, 87 gems now installed.
Use `bundle info [gemname]` to see where a bundled gem is installed.
bundle installに成功した人は下記リンクをクリックしてDBの作成・データの挿入まで移動しましょう。
DB作成と初期データ投入
bundle installに失敗してrbenv: version '2.4.1' is not installedと表示された場合
下記のコマンドを実行してください。
1
2
# bundle installに失敗した人のみ実行してください。うまくいった人はこの部分は無視して進んでください。
$ rbenv install 2.4.1
rbenv installの処理が無事終わった場合は、インストールできているか確認してみましょう。
1
2
$ ls ~/.rbenv/versions | grep 2.4.1
2.4.1
2.4.1と表示されればインストールできています。
rubyのインストール方法について詳しく知りたい方は下記の記事を参考にしてください。
rbenvを使ってrubyをインストールする方法
rubyのバージョンが2.4.1か確認しましょう。
1
2
3
4
5
6
7
# programan_dojoのディレクトリにいるか確認
$ pwd
/Users/pikawaka/programan_dojo
# rubyのバージョンが2.4.1であるか確認
$ ruby -v
ruby 2.4.1p111 (2017-03-22 revision 58053) [x86_64-darwin16]
2.4.1と表示されていればrubyのバージョンをprograman_dojoに合わせることができました。
先ほど失敗したbundle install
を実行しましょう。
1
2
3
$ bundle install
Bundle complete! 22 Gemfile dependencies, 87 gems now installed.
Use `bundle info [gemname]` to see where a bundled gem is installed.
成功すればenumアプリのDB作成と初期データを入れていきましょう。
DB作成と初期データ投入
データベース作成と初期データを投入するために下記のコマンドを実行します。
1
2
$ rails db:create && rails db:migrate && rails db:seed
環境構築が完了しました。
「環境構築が完了しました。」と表示されると、準備完了です。rails applicationが動作するか確認しましょう。
rails s
を実行してください。
1
2
3
4
5
6
7
8
9
10
$ rails s
=> Booting Puma
=> Rails 5.2.1.1 application starting in development
=> Run `rails server -h` for more startup options
Puma starting in single mode...
* Version 3.12.0 (ruby 2.4.1-p111), codename: Llamas in Pajamas
* Min threads: 5, max threads: 5
* Environment: development
* Listening on tcp://0.0.0.0:3000
Use Ctrl-C to stop
ブラウザでlocalhost: 3000と入力して下記のような画面が出てくれば環境構築完了です!
localhost:3000にアクセス
上記の画像を見てみるとenumをまだ定義していないので、血液型の部分は数字が入っているのが確認出来ます。
それでは、次の章から実際に手を動かしてenumについて理解していきましょう。
formからenumのデータを送信してレコードを作成しよう
まず今git clone
した状態では、enumを定義していないのでapp/models/user.rb
に定義していきます。
1
2
3
4
class User < ApplicationRecord
# enumを定義
enum blood_type: { A: 0, B: 1, O: 2, AB: 3 }
end
enumを定義すれば、http://localhost:3000/
をリロードしましょう。するとユーザーの血液型の表示変わったと思います。
これはなぜ変わったかというと、cloneした当初はenumの定義をしていなかったからです。ユーザーの血液型の表示はuser.blood_type
で表示していたので、enumの定義をしていない状態では、DBに保存している数字が出てきました。
enumの定義をしたことでDBの数字とenumが紐づいたので、血液型がしっかり表示される様になりました。
次はユーザー登録ページへ移動しましょう。すると下記の画像が出てきたと思います。
血液型のセレクトボックスに注目してください。こちらはenumの定数リストのセレクトボックスになっております。どうやってこのenumのセレクトボックスを作成しているか解説していきます。
app/views/users/new.html.erb
を開いて12行目に注目してみてください。
1
<%= f.select :blood_type, User.blood_types.keys.map {|k| [k, k]}, {}, { class: 'form-control', style: 'margin-bottom: 15px;', data: {} } %>
12行目に書かれている記述でenumの定数リストが載っているセレクトボックスを作成しているのですが、注目して欲しいのがUser.blood_types.keys.map {|k| [k, k]}
の部分です。この記述の返り値が[["A", "A"], ["B", "B"], ["O", "O"], ["AB", "AB"]]
で二次元配列になります。
rails c
をしてコンソールで動きを確認してみましょう。
1
2
3
4
5
6
7
# enumで登録してる血液型の配列を作成
User.blood_types.keys
=> ["A", "B", "O", "AB"]
# ↑の配列からmapメソッドで二次元配列を作成
User.blood_types.keys.map {|k| [k, k]}
=> [["A", "A"], ["B", "B"], ["O", "O"], ["AB", "AB"]]
上記のように二次元配列を取得できたことが分かりますね。mapメソッドの動作が分からない方はmapメソッドの使い方に詳しい使い方が載っているので、参照してみてください。
この二次元配列 [["A", "A"], ["B", "B"], ["O", "O"], ["AB", "AB"]]
を下記のセレクトボックスで使う場合、どの様な動作になるか見ていきます。
1
<%= f.select :blood_type, User.blood_types.keys.map {|k| [k, k]}, {}, { class: 'form-control', style: 'margin-bottom: 15px;', data: {} } %>
二次元配列の1つ目の要素の["A", "A"]
の部分に注目してください。["A", "A"]
の配列の1つ目の要素がoptionタグの表示部分になり、2つ目の要素にvalueが入ります。
これが["B", "B"]
、["C", "C"]
、["D", "D"]
それぞれ展開され、セレクトボックスになります。
1
2
3
4
<select class="form-control" style="margin-bottom: 15px;" name="user[blood_type]" id="user_blood_type"><option selected="selected" value="A">A</option>
<option value="B">B</option>
<option value="O">O</option>
<option value="AB">AB</option></select>
enumでセレクトボックスに表示する方法は分かったと思うので、今度はこのenumの値をDBに保存します。
B型のユーザーを一人作成してみましょう。まずフォームに内容を入力します。
app/controllers/users_controller.rb
でbinding.pryを加えてみて、送られてきたパラメーターを調べてみましょう。
1
2
3
4
5
6
7
8
9
10
def create
# ↓を追加
binding.pry
@user = User.new(user_params)
if @user.save
redirect_to root_path, notice: 'userを作成できました。'
else
render :new
end
end
上記のコードの様にbinding.pry
を入力してみてください。binding.pryについて知らない方はbinding.pryを徹底解説に詳しく載っているので、参照してみてください。
binding.pry
をコントローラーに追加すれば、先ほど入力したフォームでCreate User を押してコンソールを確認しましょう。コンソール画面でparamsと打つと下記の動画の様に送られてきたデータを確認することができます。
{"blood_type"=>"B"}
が送られてきてるのが確認できたので、B
という定数がDBには1という数字で保存されます。
一覧画面で血液型B型一郎が表示されていることを確認できれば、無事保存されています。
ここまでの説明で投稿フォームの入力からenumがどの様にDBに保存されるかなど、enumの仕組みが分かりましたね。これからはenumの便利なメソッドで説明したenumのメソッドを使って、アプリケーションの中のどの様な場面でenumが活躍するか実際に手を動かして理解していきましょう。
enumの確認メソッドを使って条件分岐してデータを表示しよう
それでは、enumの確認メソッドを使って条件分岐してデータを表示してみましょう。
例えば、本日の血液型占いの結果が下記だとします。
血液型 | 順位 |
---|---|
B型 | 1位 |
O型 | 2位 |
AB型 | 3位 |
A型 | 4位 |
この血液型の占い結果をテーブルで表示します。表示する項目を追加しましょう。
app/views/main/top.html.erb
の8行目と16行目を追加しています。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<div class='p-top'>
<table border="1" class= 'p-top__introduce'>
<tr>
<th>名前</th>
<th>年齢</th>
<th>血液型</th>
<th>婚姻関係?</th>
<th>血液型占い結果</th> <%# このコードを追加する%>
</tr>
<% @users.each do |user| %>
<tr>
<td><%= user.name %></td>
<td><%= "#{user.age}歳" %></td>
<td><%= "#{user.blood_type}型" %></td>
<td><%= user.is_married? ? '既婚' : '未婚' %></td>
<td></td> <%# このコードを追加する%>
</tr>
<% end %>
</table>
</div>
そうすると下記のような表示になったと思います。
まだ血液型占い結果の順位が出ていません。ここから血液型占いの確認メソッドを使って順位を表示します。
下記の様にapp/views/main/top.html.erb
のコードを修正してください。
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
<div class='p-top'>
<table border="1" class= 'p-top__introduce'>
<tr>
<th>名前</th>
<th>年齢</th>
<th>血液型</th>
<th>婚姻関係?</th>
<th>血液型占い結果</th>
</tr>
<% @users.each do |user| %>
<tr>
<td><%= user.name %></td>
<td><%= "#{user.age}歳" %></td>
<td><%= "#{user.blood_type}型" %></td>
<td><%= user.is_married? ? '既婚' : '未婚' %></td>
<td>
<%# 18~26行目を追加%>
<% if user.A? %>
ビリ
<% elsif user.B? %>
一位
<% elsif user.O? %>
二位
<% elsif user.AB? %>
三位
<% end %>
<%# 18~26行目を追加%>
</td>
</tr>
<% end %>
</table>
</div>
上のようにソースを変更すると占い結果が表示されました。
上記のソースの様にif User.A?
の様な形でif
と一緒に確認メソッドを使うことがよくあります。
今回はビューで使いましたが、コントローラーでもモデルでもif
と確認メソッドを一緒に使う場面がよくあるので、確認メソッドはif
と一緒に使うことが多いと覚えておきましょう。
ajax(非同期通信)とenumの更新メソッドを使ってデータを更新しよう
非同期通信とenumの更新メソッドを使って一覧画面から血液型を更新する機能を作っていきます。アプリを作るいろいろな場面で応用できる機能なので、この機会にぜひ使い方を理解してください。
下記の動画のようにセレクトボックスで血液型を変えただけで血液型を更新できる機能を作っていきます。リロードしてもセレクトボックスの値が変更した血液型になってるんで、更新されているのが分かると思います。
この機能を作るには大きく分けて4つの実装が必要になります。
- 血液型の一覧画面の表示をセレクトボックスにする。
- 血液型更新用のルーティングを作成する。
- 非同期通信の処理をJSで作成する。
- controllerでenumの更新用メソッドを使って血液型を更新する。
血液型の一覧画面の表示をセレクトボックスにする。
一覧画面から血液型を更新するには血液型の表示をセレクトボックスに修正しなければいけません。ファイルの内容を下記のように更新しましょう。
1
2
3
4
5
# 変更前
<td><%= "#{user.blood_type}型" %></td>
# 変更後
<td><%= select :blood_type, :name, options_for_select(User.blood_types.keys.map{|k| [k, k]}, selected: user.blood_type), {}, { class: 'js-blood_type form-control', data: { id: user.id } } %></td>
form_forの記述を使えなくなったので、ユーザー登録画面で記述されていたnew.html.erb
の血液型セレクトボックスと少し書き方が変わっています。簡単に解説するとselected: user.blood_type
でユーザーの血液型を初期値にしています。第四引数の部分でクラス属性とdata属性を指定していますが、この2つの属性は非同期通信で使用します。
変更すると下記の画像のような表示になったと思います。
ちゃんと血液型の部分がセレクトボックスになっていれば無事動作しています。
血液型更新用のルーティングを作成する。
一覧画面から血液型を変更できるルーティングを作成していきましょう。
1
2
3
4
5
6
7
8
9
10
11
12
# 変更前Rails.application.routes.draw do
root 'main#top'
resources :users
end
# 変更後
Rails.application.routes.draw do
root 'main#top'
resources :users do
resource :blood_type, only: :update, controller: 'users/blood_type'
end
end
上記のスニペットを見るとresourcesでupdateアクションを定義しています。
上記の様に記述を変更してrake routesすると、/users/:user_id/blood_type
のルーティングが追加されたと思います。
このルーティングはupdateアクションになっていて、血液型を更新する処理を書いていきます。
/users/:user_id/blood_type
のルーティングが追加されていれば、ルーティングの設定は完了です。
非同期通信の処理をJSで作成する。
先ほど作成したルーティングに向けてjsファイルからajaxメソッドで処理を飛ばします。
まず下記のJSファイルを作成していきましょう。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
$(document).ready(function() {
$('.js-blood_type').change(function() {
var user_id = $(this).data('id');
var blood_type = $(this).val();
$.ajax({
type: 'PATCH',
url: '/users/' + user_id + '/blood_type',
data: {
user: {
id: user_id,
blood_type: blood_type
}
},
dataType: 'json',
})
.done(function(data) {
alert(data.user_name + 'さんの血液型を' + data.blood_type + '型に更新しました。');
})
});
});
作成したファイルの内容を解説していくと、血液型の一覧画面の表示をセレクトボックスにする。で作成したセレクトボックスのクラス名でjs-blood_type
という名前のセレクトボックスがあったことを思い出してください。
そのセレクトボックスを変えたら処理を実行するようにしています。
3行目のuser_idにはセレクトボックスのdata属性で指定した該当のuserのidを入れ、blood_typeには変更したセレクトボックスのvalue
を代入しています。
ここからajax
メソッドを使って非同期通信をしています。
それでは、簡単にajaxメソッドの書き方について説明しますね。指定するのは下記の4つです。
1. type
2. url
3. data
4. done
type
type
にはHTTPメソッド
で何を使うか指定します。今回の場合だと血液型の更新なので、PATCH
を指定しています。
url
url
には先ほど血液型更新用のルーティングを作成する。で作成したルーティングの'/users/' + user_id + '/blood_type'
を指定します。これでセレクトボックスを変えただけで先ほど作成したルーティングに処理が実行されます。
data
data
では、paramsに何を送るか指定できます。ここでは更新するためのuserのidとどの血液型にするかのblood_typeを指定してます。
1
2
3
4
5
6
data: {
user: {
id: user_id,
blood_type: blood_type
}
}
上記の様にdataを指定することにより、paramsで下記の様に受け取ることができます。
1
2
params
=> {"user"=><ActionController::Parameters {"id"=>"2", "blood_type"=>"B"}
done
最後のdone
では実際にDB側で処理が実行されて血液型が更新された後に、ビュー側でどの様な処理をするかJSで書けます。今回はどのユーザーがどの血液型に更新したかalertで通知する様にしてます。またcontroller側の変数などをdoneの引数のdata
に渡すことができます。詳しくは次の章で後述します。
これで非同期通信を使ってセレクトボックスを変えただけで、'/users/' + user_id + '/blood_type'
のルーティングで処理が実行される様になりました。非同期通信でセレクトボックスを変えた後にcontrollerの処理が動く様になったので、controllerに更新の処理を書いていきます。
controllerでenumの更新用メソッドを使って血液型を更新する
'/users/' + user_id + '/blood_type'
からリクエストが来たときのcontrollerの処理を書いていきます。
下記にcontrollerファイルを作ってください。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class Users::BloodTypeController < UsersController
def update
binding.pry
@user = User.find(params[:user][:id])
case params[:user][:blood_type]
when 'A'
@user.A!
when 'B'
@user.B!
when 'O'
@user.O!
when 'AB'
@user.AB!
end
respond_to do |format|
format.json { render json: {user_name: @user.name, blood_type: @user.blood_type} }
end
end
end
この処理についてはbinding.pryを使ってデータがどの様に送られているか見ていきます。
まずセレクトボックスで血液型を変更します。
血液型を変更し'/users/' + user_id + '/blood_type'
に処理が送られたので、binding.pryで処理を見ていきます。
上の動画を見てみるとparams[:user][:id]
にuserのidの2が送られていて、params[:user][:blood_type]
には変更した血液型のBが送られているのが分かります。
ここの処理で@user = User.find(params[:user][:id])
としてインスタンスを作成し、送られてきた値がB
ならば@user.B!
でB型に更新してます。
「respond_to」に書いてあるのは、js側に処理を返すフォーマットを指定してます。format.json
の引数でjson形式で{user_name: @user.name, blood_type: @user.blood_type}
とすることで
非同期通信のdone
の部分で引数のdata{user_name: @user.name, blood_type: @user.blood_type}
を受け取っています。
1
2
3
4
5
.done(function(data) {
// data.usernameに@user.nameが入っており、blood_typeに@user.blood_typeが入ってます。
// data == {user_name: "programan_father", blood_type: "B"}
alert(data.user_name + 'さんの血液型を' + data.blood_type + '型に更新しました。');
})
この様な原理で、alert
にどのユーザーがどの血液型に更新できたか表示されてます。
下記の画像の様にalert
が表示されていれば、処理がうまくいってます。
最後にbeofe_action
で処理をまとめたりメソッド
に分割して見やすいコードになる様にリファクタリングしましょう。下記の様にファイルを更新してください。
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
class Users::BloodTypeController < UsersController
before_action :set_user, :update_blood_type, only: :update
def update
respond_to do |format|
format.json { render json: {user_name: @user.name, blood_type: @user.blood_type} }
end
end
private
def set_user
@user = User.find(params[:user][:id])
end
def update_blood_type
case params[:user][:blood_type]
when 'A'
@user.A!
when 'B'
@user.B!
when 'O'
@user.O!
when 'AB'
@user.AB!
end
end
end
これで見やすいコードになりました。
before_actionでfindメソッドを使ってインスタンス変数をセットしたり、処理をメソッドに分割することによりupdateアクションの記述が簡潔になりました。
beofore_actionで複数のメソッドを指定する方法について知らない方は、こちらで詳しく解説していますのでご参照ください。
beofore_actionで複数のメソッドを指定する方法について解説
findメソッドを使ってインスタンスを作成する方法について知らない方はこちらをご参照ください。
findについて徹底解説
今回説明した様な一覧画面のセレクトボックスを変えることで、リアルタイムでそのデータを更新する場面(enumの更新メソッドと非同期を使う場面)はよくあるので、ぜひその様な実装があるときは参考にしてもらえればと思います。
検索メソッドを使ってenumの属性ごとにデータを取得しよう
次はenumの検索メソッドを使って、血液型ごとにユーザーテーブルを作って表示します。
下記の画像の様なページを作成していきます。
上記の様な血液型一覧画面を作成するには、まず血液型ごとのユーザーを取得する必要があります。
そしてその後に血液型ごとに取得したユーザーをビューで表示する必要があります。
その手順をこの章では下記の様な順番で進めていきます。
- 検索メソッドを使って血液型ごとのユーザーをcontrollerで取得する。
- ユーザーテーブルで表示している部分を部分テンプレート化する。
- 血液型ごとのユーザーテーブルを表示する。
- メソッドチェーンを使って血液型ユーザー一覧表示に条件を追加しよう!
それでは、まずcontrollerで血液型ごとにユーザーを取得しましょう。
検索メソッドを使って血液型ごとのユーザーをcontrollerで取得する。
まずcontrollerで血液型ごとのユーザー取得メソッドに記述してある様に、User.A
の様に記述することで、血液型ごとのユーザーを取得する必要があります。
1
2
3
4
5
6
7
8
9
10
class MainController < ApplicationController
def top
@users = User.all
# 5 〜 8行目を追加しましょう。
@a_type_users = User.A
@b_type_users = User.B
@o_type_users = User.O
@ab_type_users = User.AB
end
end
上記のスニペットの様に変更して、血液型ごとのユーザーを取得できているか確認してください。取得できていれば、次はビュー表示の部分を記述していきましょう。
ユーザーテーブルで表示している部分を部分テンプレート化する。
完成系の画像を確認してみると、ユーザー一覧のテーブルと血液型ごとのユーザーのテーブルは同じ見た目になっていますね。
ですから、ユーザー一覧のテーブル表示している部分を血液型ごとのユーザーのテーブルの部分でも、共通化して使える様に部分テンプレート化していきます。
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
<div class='p-top'>
<p class='p-top__label'>ユーザー一覧</p>
<table border="1" class= 'p-top__introduce'>
<tr>
<th>名前</th>
<th>年齢</th>
<th>血液型</th>
<th>婚姻関係?</th>
<th>血液型占い結果</th>
</tr>
<% @users.each do |user| %>
<tr>
<td><%= user.name %></td>
<td><%= "#{user.age}歳" %></td>
<td><%= select :blood_type, :name, options_for_select(User.blood_types.keys.map{|k| [k, k]}, selected: user.blood_type), {}, { class: 'js-blood_type form-control', data: { id: user.id } } %></td>
<td><%= user.is_married? ? '既婚' : '未婚' %></td>
<td>
<% if user.A? %>
ビリ
<% elsif user.B? %>
一位
<% elsif user.O? %>
二位
<% elsif user.AB? %>
三位
<% end %>
</td>
</tr>
<% end %>
</table>
</div>
部分テンプレート化する前に↑の記述を↓の記述に変更して、まず占い結果の表示を消しましょう。(4つのテーブルが並んだ場合の幅の問題で小さく表示されるカラムがあるため。)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<div class='p-top'>
<p class='p-top__label'>ユーザー一覧</p>
<table border="1" class= 'p-top__introduce'>
<tr>
<th>名前</th>
<th>年齢</th>
<th>血液型</th>
<th>婚姻関係?</th>
</tr>
<% @users.each do |user| %>
<tr>
<td><%= user.name %></td>
<td><%= "#{user.age}歳" %></td>
<td><%= select :blood_type, :name, options_for_select(User.blood_types.keys.map{|k| [k, k]}, selected: user.blood_type), {}, { class: 'js-blood_type form-control', data: { id: user.id } } %></td>
<td><%= user.is_married? ? '既婚' : '未婚' %></td>
</tr>
<% end %>
</table>
</div>
すると下記の画像の様に表示されたと思います。
占い結果の表示を消えていることが確認できれば、このユーザー一覧のテーブルが他の血液型のユーザー一覧テーブルと共通化できる様にまず部分テンプレート化します。
10 ~ 17行目の部分がユーザーテーブルの一覧を表示してる部分なので、その部分を部分テンプレートにします。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<div class='p-top'>
<p class='p-top__label'>ユーザー一覧</p>
<table border="1" class= 'p-top__introduce'>
<tr>
<th>名前</th>
<th>年齢</th>
<th>血液型</th>
<th>婚姻関係?</th>
</tr>
<% @users.each do |user| %> # each 〜 endまでを切り出す。
<tr>
<td><%= user.name %></td>
<td><%= "#{user.age}歳" %></td>
<td><%= select :blood_type, :name, options_for_select(User.blood_types.keys.map{|k| [k, k]}, selected: user.blood_type), {}, { class: 'js-blood_type form-control', data: { id: user.id } } %></td>
<td><%= user.is_married? ? '既婚' : '未婚' %></td>
</tr>
<% end %>
</table>
</div>
↑上のコメントに書かれている部分を切り出して、下記のファイルを作成してください。
1
2
3
4
5
6
<tr>
<td><%= user.name %></td>
<td><%= "#{user.age}歳" %></td>
<td><%= select :blood_type, :name, options_for_select(User.blood_types.keys.map{|k| [k, k]}, selected: user.blood_type), {}, { class: 'js-blood_type form-control', data: { id: user.id } } %></td>
<td><%= user.is_married? ? '既婚' : '未婚' %></td>
</tr>
部分テンプレートファイルが作成されたので、先ほど「# each 〜 endまでを切り出す。」とコメントしていた部分をpartial
を使って記述を変更します。下記の様にファイルを修正してください。
1
2
3
4
5
6
7
8
9
10
11
<div class='p-top'>
<table border="1" class= 'p-top__introduce'>
<tr>
<th>名前</th>
<th>年齢</th>
<th>血液型</th>
<th>婚姻関係?</th>
</tr>
<%= render partial: 'table_user', collection: @users, as: 'user' %>
</table>
</div>
部分テンプレートのcollectionオプションを使うと、アプリのパフォーマンスがよくなります。
部分テンプレートのcollectionオプションについて知らない方は、こちらでcollectionオプションについて詳しく解説しているので参考にしてください。
見た目は先ほどと変わりませんが、部分テンプレートを使ってエラーを出さずに先ほどと同じ表示になっているかここで確認してください。
それでは、ユーザー一覧のテーブルの共通化の準備はできたので、次は血液型ごとのユーザーを表示する準備をしていきます。
血液型ごとのユーザーテーブルを表示する。
血液型ごとのユーザーを表示するためにファイルを下記の様に修正してください。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<div class='p-top'>
<p class='p-top__label'>ユーザー一覧</p>
<table border="1" class= 'p-top__introduce'>
<tr>
<th>名前</th>
<th>年齢</th>
<th>血液型</th>
<th>婚姻関係?</th>
</tr>
<%= render partial: 'table_user', collection: @users, as: 'user' %>
</table>
<div class='p-top__section'>
<% User.blood_types.keys.each do |blood_type| %>
<%= render 'blood_type_box', blood_type: blood_type %>
<% end %>
</div>
</div>
14行目の記述User.blood_types.keys
の返り値は、血液型一覧が配列でかえって来ます。
1
2
User.blood_types.keys
=> ["A", "B", "O", "AB"]
完成系の画像を見てみると血液型の数の分だけ、合計4つのテーブルを作る必要があります。
そのテーブルを作るのが4つ必要になるので、4回分blood_type_box
という血液型のテーブルを作る部分テンプレートにblood_type
という変数を渡してレンダリングしています。
それでは_blood_type_box.html.erb
に血液型のテーブルを作る部分テンプレートを作成しましょう。
下記の様に部分テンプレートファイルを作成してください。
1
2
3
4
5
6
7
8
9
10
11
12
<div class='p-top__section__box'>
<p class='p-top__section__box__label'><%= "#{blood_type}型一覧" %></p>
<table border="1" class= 'p-top__section__box__table'>
<tr>
<th>名前</th>
<th>年齢</th>
<th>血液型</th>
<th>婚姻関係?</th>
</tr>
<%= render partial: 'table_user', collection: blood_type_users(blood_type), as: 'user' %>
</table>
</div>
2行目の「どの血液型テーブルを表示してるかのラベル」には、渡してきた変数のblood_typeを表示します。
10行目では先ほどの章で作成したユーザーテーブル一覧で、共通の見た目のtable_userを部分テンプレートで表示してます。
collection
に指定しているblood_type_users
は一体何でしょうか?
blood_type_usersは実はまだ定義していません。ただこのcollectionに渡す部分は、血液型ごとのユーザーを渡す必要があります。血液型ごとのユーザーを渡すためにblood_type_usersメソッドを定義しましょう。
application_helper.rb
に下記のメソッドを追加してください。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
module ApplicationHelper
def blood_type_users(blood_type)
case blood_type
when 'A'
@a_type_users
when 'B'
@b_type_users
when 'O'
@o_type_users
when 'AB'
@ab_type_users
end
end
end
このコードを解説すると、送られてきたblood_typeがA
であればA型のユーザー一覧、B
であればB型のユーザー一覧、O
であればO型のユーザー一覧、AB
であればAB型のユーザー一覧を取得してます。
1
2
3
4
5
<div class='p-top__section'>
<% User.blood_types.keys.each do |blood_type| %>
<%= render 'blood_type_box', blood_type: blood_type %>
<% end %>
</div>
上記のコードをもう一度見返してみるとUser.blood_types.keys
で血液型一覧を取得しているので、blood_type_boxにはA, B, O, AB
の順番で変数が渡されています。
この渡された変数をblood_type_users(blood_type)
の引数に設定して、先ほどコントローラーで定義したそれぞれの血液型ユーザー一覧を返り値(例: @a_type_users)に指定することで
- blood_typeがAであれば@a_type_users
- blood_typeがBであれば@b_type_users
- blood_typeがOであれば@o_type_users
- blood_typeがABであれば@ab_type_users
と返り値としてcollectionのblood_type_users(blood_type)
に返すことができます。
<%= render partial: 'table_user', collection: blood_type_users(blood_type), as: 'user' %>
の記述のcollectionに血液型ごとのユーザー一覧を指定することができました。
ここまでで来れば、localhost:3000
を表示してください。
下記の完成系の画像になっていれば、うまくいってます。
メソッドチェーンを使って血液型ユーザー一覧表示に条件を追加しよう!
先ほどcontrollerで定義した@a_type_users
の様な血液型ごとのユーザーに対してメソッドチェーン
で条件を追加できます。条件を追加できる理由はUser.A
の返り値がUser::ActiveRecord_Relation
だからです。
メソッドチェーンについて知らない方は、下記のサイトを参考にしてください。
それでは、メソッドチェーンで下記のスニペットの様に条件を追加してみましょう。
1
2
3
4
5
6
7
8
9
10
11
12
13
class MainController < ApplicationController
def top
@users = User.all
# 20歳~40歳のA型ユーザー一覧
@a_type_users = User.A.where(age: 20..40)
# 結婚しているB型ユーザー一覧
@b_type_users = User.B.where(is_married: true)
# 結婚していて50代のO型ユーザー一覧
@o_type_users = User.O.where(age: 50..59).where(is_married: true)
# 未婚で20代のAB型のユーザー一覧
@ab_type_users = User.AB.where(age: 21..29).where(is_married: false)
end
end
上の様な条件を追加してどんな表示になるか見てみましょう。
上記の様な表示になればうまくいってます。開発をしている時はenumの検索メソッドを単体で使うというよりかは、メソッドチェーンと併用して他の条件と合わせてデータを取得するケースが多いです。
メソッドチェーンを使うパターンもしっかり理解しておきましょう。
enumとi18nの使い方
enumとi18nを併用した方法について解説していきます。
i18nとは何かと簡単にいうと、翻訳ファイルと言われています。外国語を日本語に翻訳するファイルとして使われることがあります。
例えば、英語のエラーメッセージを日本語に翻訳したり、韓国人が多くアクセスするページであれば、英語を韓国語に翻訳して表示することもできます。この様な翻訳という意味合いで使われることが多いです。
そこで今回英語から日本語に変換する用途でi18nとenumを併用する方法を説明します。
ユーザー登録ページに移動してください。
下記の画像が今表示されていると思いますが、ここのAが分かりづらいのでA
からA型
への表示の変更がi18nを使うとできます。
i18nとenumを使うと↑の血液型がAの表示を↓のA型などに変更できます。
そして、validationのエラーメッセージを日本語で表示できたりします。
上記↑の様な英語の表示を下記↓の日本語の表示にすることができます。
上記の画像で見せたセレクトボックスのAの表示をA型に変更したり、エラーメッセージを日本語化するといったことがi18nとenumを併用するとできます。
それでは、どうすれば上記の様な日本語翻訳設定ができるのか?その方法を説明していきます。
まず日本語の表示をするには、3つのファイルの変更が必要になります。
config/application.rb
にi18nのデフォルトの言語を日本語に設定config/locales/ja.yml
に英語から日本語への翻訳内容を追加app/views/users/new.html.erb
の記述を変更して日本語表示のselectboxを作成
それでは、1から作業をおこなっていきましょう。
i18nのデフォルトの言語を日本語に設定
application.rb
に下記の様にconfig.i18n.default_locale = :ja
を追加することによって、設定を日本語にすることが出来ます。
1
2
3
4
5
6
7
8
9
10
11
12
require_relative 'boot'
require 'rails/all'
Bundler.require(*Rails.groups)
module ProgramanDojo
class Application < Rails::Application
config.load_defaults 5.2
# 下記を追加
config.i18n.default_locale = :ja
end
end
これを追加することによって、config/locales/以下にあるja.ymlファイルを読み込みます。
これでi18nの日本語に翻訳するという設定ができました。
application.rbを操作した場合は一度control cでサーバーを停止した後に、rails sをして再起動する様にしてください。再起動しなければapplication.rbに追加したことが反映されないためです。
config/locales/ja.ymlに英語から日本語への翻訳内容を追加
英語から日本語への翻訳を可能にするためにconfig/locales/ja.yml
を作成します。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 下記の4~16行目の記述をja.ymlの既に書かれているactiverecordとerrosの間に入れくてください。
ja:
activerecord:
models:
user: ユーザー
attributes:
user:
name: 名前
age: 年齢
blood_type: 血液型
blood_types:
A: A型
B: B型
O: O型
AB: AB型
is_married: 婚姻関係
errors:
この様に書くと日本語化されます。
実際にvalidationのメッセージで日本語化されているか見てみましょう。
user.rb
にvalidationの設定をしましょう。
1
2
3
4
class User < ApplicationRecord
enum blood_type: { A: 0, B: 1, O: 2, AB: 3 }
validates :name, :age, :blood_type, presence: true
end
validationのpresenceオプションについて知らない方はこちらの記事を参考にしてください。
validationのpresenceオプションについて解説
エラーメッセージが日本語で表示されましたね。ただ今血液型はセレクトボックスの初期値にA型が設定されているので、血液型のエラーメッセージを表示できていません。血液型のエラーメッセージを日本語で表示する方法については後述します。
app/views/users/new.html.erbの記述を変更して日本語表示のselectboxを作成
それでは日本語表示のセレクトボックスを作って、日本語を選択して送信しても英字で送られるようにしていきます。app/views/users/new.html.erb
を開いて、セレクトボックスの記述を修正していきましょう。
1
2
3
4
5
# 変更前
<%= f.select :blood_type, User.blood_types.keys.map {|k| [k, k]}, {}, { class: 'form-control', style: 'margin-bottom: 15px;', data: {} } %>
# 変更後
<%= f.select :blood_type, options_for_select(User.blood_types.map { |k, _v| [t("activerecord.attributes.user.blood_types.#{k}"), k] }), {include_blank: true}, { class: 'form-control', style: 'margin-bottom: 15px;', data: {} } %>
変更した点は2点です。
- 第一引数の
User.blood_types.keys.map {|k| [k, k]}
をUser.blood_types.map { |k, _v| [t("activerecord.attributes.user.blood_types.#{k}"), k] })
に変更 - 第三引数に
include_blank: true
を追加
1のUser.blood_types.map { |k, _v| [t("activerecord.attributes.user.blood_types.#{k}"), k] })
に変更したことにより、日本語の表示ができる様になりました。
1
2
3
4
5
6
blood_types:
# keyの部分がt("activerecord.attributes.user.blood_types.#{k}")のkに当たり、A型などに翻訳される。
A: A型
B: B型
O: O型
AB: AB型
この様な理屈でi18nを使って日本語で表示ができました。
このkに入っているものはmapの一番最初の繰り返しだとkにAが入り、k(A): A型
という理屈でA型が表示されているということですね。
そして2の第三引数にinclude_blank: true
を追加することによって、空欄を先頭に追加できます。先ほどはセレクトボックスに空欄がなくてバリデーションのエラーメッセージを表示できなかったんですが、これを追加することによって空で送ってバリデーションのエラーメッセージを表示できる様になります。
まず見た目を確認してみましょう。
上記の様にセレクトボックスに空欄、A型
の様にしっかり日本語に変換されていれば実装できています。
では実際に登録できるか確かめてみるのと、エラーを出した時に日本語で表示されるか確認してみましょう。
上記の様にAB型二郎さんが追加されていればしっかり実装できています。
次はエラーの表示を見てみましょう。
上記の様にエラーメッセージが出ていれば完了です。
i18nとenumを使えば、日本語の表示をしながら実際に保存する値は英語の定数ということができるので、非常に便利です。実際にenumを使って実装するときは必須の機能になると思うので、ぜひ自分の実装に役立ててください。
enum_help・rails6で追加されたenumメソッド
前回までの章で実践で使うenumについての説明は終わりです。
この章からはenumをさらに便利にするgemについての説明やrails6で新しく追加されたenumの新たなメソッドについて解説します。
enum_help
enum_helpとは、簡単にenumとi18nを結び付けられるgemです。
enumとi18nの使い方では、enumとi18nを使って日本語化する方法について説明しました。mapメソッド
との併用もしており応用的な使い方をしていたと思います。gemを使えばもっと簡単にenumとi18nを結び付けられるので早速enum_helpを使っていきましょう。
enum_helpの使い方について、下記の順番で説明していきます。
- enum_helpのインストール
- enum_helpの定義
- enum_helpの便利なメソッド
1.enum_helpのインストール
enum_helpを早速インストールしましょう。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
source 'https://rubygems.org'
git_source(:github) { |repo| "https://github.com/#{repo}.git" }
ruby '2.4.1'
gem 'rails', '~> 5.2.0'
gem 'mysql2', '>= 0.3.18', '< 0.5'
gem 'puma', '~> 3.11'
gem 'sass-rails', '~> 5.0'
gem 'uglifier', '>= 1.3.0'
gem 'pry-rails'
gem 'coffee-rails', '~> 4.2'
gem 'turbolinks', '~> 5'
gem 'jbuilder', '~> 2.5'
gem 'bootsnap', '>= 1.1.0', require: false
gem 'bootstrap', '~> 4.1.1'
gem 'jquery-rails'
gem 'jquery-turbolinks'
# enum_helpを追加
gem 'enum_help'
...
bundle install
を実行しましょう。
bundle installした結果にUsing enum_help バージョン名
と表示されていれば、インストールできています。
2.enum_helpの定義
enum_helpを使用するためにはja.yml
にenum_help専用の記述を追加しなければいけません。
1
2
3
4
5
6
7
8
9
ja:
# 3行目から9行目を追加しましょう。
enums:
user:
blood_type:
A: A型
B: B型
O: O型
AB: AB型
jaの直下に上記の様な形で追加しましょう。追加すればenum_helpの便利なメソッドを使用できるようになります。早速どんな便利なメソッドを使えるか見ていきましょう。
3.enum_helpの便利なメソッド
enum_helpを使うと簡単にenumの定数を日本語に翻訳できます。
例えば、enum_help
を使わずにユーザーの血液型を日本語で表示するにはどうすれば良いでしょうか?
1
2
3
4
5
6
7
8
9
10
11
12
user = User.find_by(name: 'programan')
=> #<User:0x007f9ab7e01358
id: 1,
name: "programan",
age: 25,
blood_type: "A",
is_married: false,
created_at: Thu, 30 Jan 2020 06:55:05 UTC +00:00,
updated_at: Fri, 31 Jan 2020 04:48:28 UTC +00:00>
I18n.t("activerecord.attributes.user.blood_types.#{user.blood_type}")
=> "A型"
こうしなければいけました。ただ記述も長いですし、毎回I18n
のメソッドを直接指定して呼び出さなければいけません。その点enum_helpを使えば簡単に日本語表示できます。
1
2
3
4
5
6
7
8
9
10
11
12
user = User.find_by(name: 'programan')
=> #<User:0x007f9ab7e01358
id: 1,
name: "programan",
age: 25,
blood_type: "A",
is_married: false,
created_at: Thu, 30 Jan 2020 06:55:05 UTC +00:00,
updated_at: Fri, 31 Jan 2020 04:48:28 UTC +00:00>
user.blood_type_i18n
=> "A型"
かなり簡単に書ける様になりましたね!それ以外にも日本語と英語のハッシュも簡単に作るメソッドが用意されています。
1
2
3
4
5
6
7
8
9
10
# enum_helpを使わずに書いた場合
User.blood_types.map { |k, _v| [I18n.t("activerecord.attributes.user.blood_types.#{k}"), k] }.to_h
=> {"A型"=>"A", "B型"=>"B", "O型"=>"O", "AB型"=>"AB"}
# enum_helpを使って書いた場合
User.blood_types_i18n.invert
=> {"A型"=>"A", "B型"=>"B", "O型"=>"O", "AB型"=>"AB"}
User.blood_types.map { |k, _v| [I18n.t("activerecord.attributes.user.blood_types.#{k}"), k] }.to_h == User.blood_types_i18n.invert
=> true
enum_helpを使わなければ、mapでi18nと定数の配列を作った後にto_hメソッドでハッシュ化しなければいけません。
その点enum_helpを使うと日本語と英語のハッシュを作る際にも非常に簡単になります。
使い所はselectbox
などで有効に使えそうですね!
ぜひenum_helpを導入してenumとi18nの結びつきを簡単にしましょう。
rails6で追加されたenumで便利な機能
rails6に新たに追加されたenumのメソッドがあります。そのメソッドはenumの否定系メソッドです。
否定系メソッドとは、User.A(検索メソッド)
の否定系の様なイメージのメソッドです。
下記の順番でrails6で追加された既存の検索メソッドについて説明します。
- 既存の検索メソッドと否定系メソッドの違い
- rails5で否定系メソッドを書く場合
既存の検索メソッドと否定系メソッドの違い
既存の検索メソッドとどう違うか比較するためにまず既存の検索メソッドが見ていきましょう。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
User.A
SELECT "users".* FROM "users" WHERE "users"."blood_type" = ? [["blood_type", 0]]
=> [#<User:0x00007ff37a4c0868
id: 1,
name: "programan",
age: 25,
blood_type: "A",
is_married: false>,
#<User:0x00007ff37a4c07a0
id: 2,
name: "programan_father",
age: 58,
blood_type: "A",
is_married: true>,
#<User:0x00007ff37a4c06d8
id: 6,
name: "programan_bigbrother",
age: 28,
blood_type: "A",
is_married: true>
]
この様にUser.A
はA型だけのユーザーを取得しています。
SQLの話になりますがWHERE "users"."blood_type" = ? [["blood_type", 0]]
のところを見ると、blood_typeの値が0だけのモノを取得していることが分かります。
対して否定系メソッドはA型以外のユーザーを取得します。
モデルクラス.not_定数名
で実行します。
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
User.not_A
SELECT "users".* FROM "users" WHERE "users"."blood_type" != ? [["blood_type", 0]]
=> [#<User:0x00007ff37dc31018
id: 3,
name: "programan_mother",
age: 58,
blood_type: "O",
is_married: true>,
#<User:0x00007ff37dc30eb0
id: 4,
name: "programan_bigsister",
age: 30,
blood_type: "B",
is_married: true>,
#<User:0x00007ff37dc30d70
id: 5,
name: "programan_sister",
age: 20, blood_type: "AB",
is_married: false>,
#<User:0x00007ff37dc30c08
id: 7,
name: "programan_brother",
age: 22,
blood_type: "O",
is_married: true>,
#<User:0x00007ff37dc309d8
id: 8,
name: "血液型B型一郎",
age: 40,
blood_type: "B",
is_married: false>,
#<User:0x00007ff37dc30898
id: 9,
name: "AB型二郎",
age: 29,
blood_type: "AB",
is_married: false>
]
上記の結果を見るとA型以外のユーザーを取得できていることが分かります。
SQLのWHERE "users"."blood_type" != ? [["blood_type", 0]]
のところを見ると!=
となっていてblood_typeが0以外のユーザーを取得というSQLの意味になります。
このように否定系メソッドは、モデルクラスに対してモデルクラス.not_定数名
で実行するメソッドです。
かなり直感的に書けるので、メソッドがどのような返り値になるか想像しやすいですね。
この否定系メソッドをrails5で書いた場合と比較して、どれくらい直感的に書けているか見てみましょう。
rails5で否定系メソッドを書く場合
rails5で否定系メソッドを使った場合を見てみます。当然先ほどのモデルクラス.not_定数名
で実行するとrails5であれば、エラーになります。
1
2
User.not_A
NoMethodError: undefined method `not_A' for #<Class:0x007fa8f556dec0>
ですから、rails5で否定系の検索メソッドを使う場合はwhereメソッドで指定します。
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
User.where.not(blood_type: 'A')
=> [#<User:0x00007ff37dc31018
id: 3,
name: "programan_mother",
age: 58,
blood_type: "O",
is_married: true>,
#<User:0x00007ff37dc30eb0
id: 4,
name: "programan_bigsister",
age: 30,
blood_type: "B",
is_married: true>,
#<User:0x00007ff37dc30d70
id: 5,
name: "programan_sister",
age: 20, blood_type: "AB",
is_married: false>,
#<User:0x00007ff37dc30c08
id: 7,
name: "programan_brother",
age: 22,
blood_type: "O",
is_married: true>,
#<User:0x00007ff37dc309d8
id: 8,
name: "血液型B型一郎",
age: 40,
blood_type: "B",
is_married: false>,
#<User:0x00007ff37dc30898
id: 9,
name: "AB型二郎",
age: 29,
blood_type: "AB",
is_married: false>
]
rails5で書く場合はwhere.not(blood_type: 'A')
と書くとrails6で書いたnot_A
と同じ結果を得られます。
1
2
3
4
5
# rails5の場合
User.where.not(blood_type: 'A')
# rails6の場合
User.not_A
人によるかもしれませんが、rails6の否定系メソッドのほうが直感的に書けるし記述が短いですね。今rails6のアプリを使っててenumを使っている人はぜひ新しく追加された否定系メソッドを使ってみてください。
enumについては、こちらの参考書でも詳しく解説されています。『Ruby on Rails チュートリアル』を完走している方は、これまで学習した内容も実用可能な知識として定着できるのでぜひ参考にしてください。
この記事のまとめ
- enumとは、1つのカラムに指定した複数個の定数を保存できる様にする為の機能のこと
- enumには直感的で使いやすいメソッドが用意されている
- i18nとenumを使うと日本語表示でenumの機能を使用出来る
- enumにはgemのenum_helpやrails6で新しく追加されたenumメソッドがあるので、enumの基礎を理解できた後に積極的に取り入れよう