Rails 4.1のenumの挙動
みんな大好きenum型
DBのカラムでステータスとか使うとき、ぼくは数値派なんですけど、enumで掛けたら楽で良いですよねみたいのあります。ありますよね。
で、Rails 4.1ではそういうのが導入されたっぽいので試してみました。
rails 4.1をインストールしてプロジェクト作ったりする
$ gem install rails --pre --no-ri --no-rdoc $ rails new sample $ cd sample $ ./bin/rails g scaffold product name:string status:integer $ ./bin/rake db:migrate
rails c
でフツーに登録してみる(ここは何の変哲も無い)。
irb(main):005:0> Product.create!(name: "hoge", status: 99) (0.1ms) begin transaction SQL (0.2ms) INSERT INTO "products" ("created_at", "name", "status", "updated_at") VALUES (?, ?, ?, ?) [["created_at", "2014-03-26 01:25:21.026233"], ["name", "hoge"], ["status", 99], ["updated_at", "2014-03-26 01:25:21.026233"]] (1.9ms) commit transaction => #<Product id: 2, name: "hoge", status: 99, created_at: "2014-03-26 01:25:21", updated_at: "2014-03-26 01:25:21">
statusの値が99でも保存できちゃう。そのままでも良いんだけど、validatesのおさらいとして例えば0〜2までに制限してみようか。
class Product < ActiveRecord::Base validates :status, inclusion: {in: 0..2} end
ためしてみよう
Loading development environment (Rails 4.1.0.rc2) irb(main):001:0> Product.create!(name: "hoge", status: 99) (0.1ms) begin transaction (0.1ms) rollback transaction ActiveRecord::RecordInvalid: Validation failed: Status is not included in the list irb(main):003:0* Product.create!(name: "hoge", status: 2) (0.1ms) begin transaction SQL (0.4ms) INSERT INTO "products" ("created_at", "name", "status", "updated_at") VALUES (?, ?, ?, ?) [["created_at", "2014-03-26 01:27:51.238248"], ["name", "hoge"], ["status", 2], ["updated_at", "2014-03-26 01:27:51.238248"]] (1.6ms) commit transaction => #<Product id: 3, name: "hoge", status: 2, created_at: "2014-03-26 01:27:51", updated_at: "2014-03-26 01:27:51">
数値の範囲指定ができましたね。
それではenumを使ってみよう
enumの設定をしてみよう。ややこしくなるので、validatesは消します。ついでに書いておくと、enumの項目自体はテキトウなのでスルー推奨です。
class Product < ActiveRecord::Base enum status: { normal: 0, # 通常 sale: 1, # 特売 empty: 2, # 在庫切れ } end
これで試してみよう。まずは正常系で。
irb(main):005:0* Product.create!(name: "hoge", status: 2) (0.1ms) begin transaction SQL (0.2ms) INSERT INTO "products" ("created_at", "name", "status", "updated_at") VALUES (?, ?, ?, ?) [["created_at", "2014-03-26 01:33:06.501462"], ["name", "hoge"], ["status", 2], ["updated_at", "2014-03-26 01:33:06.501462"]] (1.6ms) commit transaction => #<Product id: 6, name: "hoge", status: 2, created_at: "2014-03-26 01:33:06", updated_at: "2014-03-26 01:33:06"> irb(main):006:0> Product.create!(name: "hoge", status: :sale) (0.1ms) begin transaction SQL (0.6ms) INSERT INTO "products" ("created_at", "name", "status", "updated_at") VALUES (?, ?, ?, ?) [["created_at", "2014-03-26 01:33:13.877152"], ["name", "hoge"], ["status", 1], ["updated_at", "2014-03-26 01:33:13.877152"]] (1.5ms) commit transaction => #<Product id: 7, name: "hoge", status: 1, created_at: "2014-03-26 01:33:13", updated_at: "2014-03-26 01:33:13"> irb(main):005:0> Product.create!(name: "hoge", status: 'sale') (0.1ms) begin transaction SQL (0.6ms) INSERT INTO "products" ("created_at", "name", "status", "updated_at") VALUES (?, ?, ?, ?) [["created_at", "2014-03-26 01:57:26.957196"], ["name", "hoge"], ["status", 1], ["updated_at", "2014-03-26 01:57:26.957196"]] (1.4ms) commit transaction => #<Product id: 15, name: "hoge", status: 1, created_at: "2014-03-26 01:57:26", updated_at: "2014-03-26 01:57:26">
このように、シンボルや文字列、そして数値でも保存してくれるようになった。便利。
では範囲外の値を入力すると?
irb(main):007:0> Product.create!(name: "hoge", status: 99) ArgumentError: '99' is not a valid status irb(main):009:0* Product.create!(name: "hoge", status: :hoge) ArgumentError: 'hoge' is not a valid status irb(main):011:0* Product.create!(name: "hoge", status: 'hogehoge') ArgumentError: 'hogehoge' is not a valid status
ことごとくArgumentErrorとなる。create!
で試しているけど、create
やnew
でも試してみよう。
irb(main):007:0> Product.create(name: "hoge", status: 99) ArgumentError: '99' is not a valid status irb(main):009:0* Product.new(name: "hoge", status: 99) ArgumentError: '99' is not a valid status
create!だけに限らず、newメソッドとかでも引数に異なる範囲の値が入るとArgumentErrorになる。
普通のvalidatesに条件を書く場合は ActiveRecord::RecordInvalid: Validation failed: Status is not included in the list
みたいにActiveRecord::RecordInvalidの例外クラスが送出されるけど、そうではない(例外クラス的にも、発生タイミング的にも)ので気をつけた方が良さそう。
validatesではないから挙動が異なるのは当然といえば当然だけど、使い勝手としては同じような挙動のほうが嬉しかったんだけどそうではなかったという備忘録エントリーです。
Rails詳しくないのでよくわかりませんが、ここら辺、正式リリースまでに挙動が変わったりするかしら?
書かなくてはならない事柄(追記)
こちらも何卒よろしくお願い致します。
Webアプリエンジニア養成読本[しくみ、開発、環境構築・運用…全体像を最新知識で最初から! ] (Software Design plus)
- 作者: 和田裕介,石田絢一(uzulla),すがわらまさのり,斎藤祐一郎
- 出版社/メーカー: 技術評論社
- 発売日: 2014/03/11
- メディア: 大型本
- この商品を含むブログ (3件) を見る