本当はこうしたほうがいい
Enumを使って定義したほうがスマートだしそっちに寄せられるなら寄せたほうが良さそうです。
参考:
-【Rails】Enum - EnumerizeとActiveRecord::Enum
-RubyでEnumを使いたかったらenumerize
-Enumerizeを数値型カラムで使う
でもI18nに定義してあるので
すでに下記のような感じに定義あったのでこれをどうしてもそのまま利用したかった。
ja.yml
ja:
master:
food_category:
1: 野菜
2: お肉
3: お魚
4: ご飯もの
5: 麺類
99: その他
ここに値のある数値しか保存できないようにvalidationしたい。
その場合は独自validationを定義することになる。
1. validatorをつくる
注:ファイル名がvalidator名になってないと怒られたりする。
lib/validates/food_category_validator.rb
# coding: utf-8
class FoodCategoryValidator < ActiveModel::EachValidator
def validate_each(record, attribute, value)
if !I18n.t("master.food_category").key?(value)
#エラー文も適当にI18nとしたほうが良さそう
record.errors[attribute] << '不正な値です'
end
end
end
2. validatorを読み込ませるように設定
config/application.rb
#色々省略
config.autoload_paths += %W(#{config.root}/lib/validates)
3. Modelで使う
app/models/food.rb
class Food < ActiveRecord::Base
validates :category, food_category: true
# 失敗1:下記のようにすると、translation missing 扱いになってしまう
# validates :category, inclusion: { in: I18n.t("master.food_category").keys }
# 失敗2:これで動くかと思ったけど気のせいだった
# if: は その条件に合致した場合にvalidationを実施するということ、これでは結局何もしない感じに...。
# validates :category, if: Proc.new { I18n.t("master.food_category").key?(self.category) }
end
こんな感じで動く
food = Food.new
# =><Food id: nil, category: nil, name: nil, created_at: nil, updated_at: nil>
food.valid?
# => false
food.errors
=> #<ActiveModel::Errors:0x007fbdc2959b88 @base=#<Food id: nil, category: nil, name: nil, created_at: nil, updated_at: nil>, @messages={:category=>["不正な値です"]}>
food.errors.full_messages
# => ["Category 不正な値です"]
# "Category は不正な値です" って I18n つかったらそれっぽくなると思う