rails の validation error message の i18n 対応

rails で Custom validatior や Custom validation method を定義して、その中で errors.add する際に、 message として使われる I18n のパスをどう書くのが良いのかっていうのが気になった。
結論としては、下記のように書くのがスッキリして良さそう。

Custom Validators

特定のモデルによらないエラーメッセージの場合は、下記のように locales/en.yml を書くことで、record.errors.add(attribute, :something_invalid)と書ける。

en:
  errors:
    messages:
      something_invalid: Invalid something.
class MyCheckValidator < ActiveModel::EachValidator
  def validate_each(record, attribute, value)
    unless check_something(value)
      record.errors.add(attribute, :something_invalid)
      #=> record.errors.add(attribute, I18n.t('errors.messages.something_invalid')) と同じ
    end
  end

  def check_something(value)
   # Something
  end
end

class MyModel < ActiveRecord::Base
  validates :name, my_check: true
end

Custom Methods

特定のモデルの特定の項目のエラーメッセージの場合は、下記のようにymlを書くことで、適切にメッセージを参照してくれる。

en:
  activerecord:
    errors:
      models:
        my_model:
          attributes:
            start_date:
              cannot_be_after_end_date: It cannot be after the end date.
            end_date:
              cannot_be_before_start_date: It cannot be before the start date.
class MyModel < ActiveRecord::Base
  validate :start_date_cannot_be_after_end_date, if: -> { start_date.present? && end_date.present? }

  private

  def start_date_cannot_be_after_end_date
    return if start_date <= end_date

    errors.add(:start_date, :cannot_be_after_end_date)
    #=> errors.add(:start_date, I18n.t('activerecord.errors.models.my_model.attributes.start_date.cannot_be_after_end_date')) と同じ
    errors.add(:end_date, :cannot_be_before_start_date)
    #=> errors.add(:end_date, I18n.t('activerecord.errors.models.my_model.attributes.end_date.cannot_be_before_start_date')) と同じ
  end
end

参考