valid_encoding? の validation 作成

validates_each だと allow_blank オプションのチェックの関係で String#blank? が呼ばれてその中で「ArgumentError: invalid byte sequence」になってしまうので使えなかった。
blank? で ArgumentError になるのは直る予定はなさそうなので、 validates_each は使えなさそうだった。 (参考: https://github.com/rails/rails/issues/1532 )

どうにか回避出来ないかいろいろがんばってみたところ validates_with なら大丈夫だった。

たとえば

  • rails new invalid-byte-sequence -T
  • cd invalid-byte-sequence
  • rails g scaffold post title
  • rake db:migrate

のように作成した rails 3.2.2 のアプリケーションで、以下のように validation を設定するとうまくいった。

  • rails runner 'Post.create!(title: "\x82\xA0")'

などで動作確認出来る。("\x82\xA0" は "\u3042".encode(Encoding::SJIS).force_encoding(Encoding::UTF_8)) で作成)
コメントアウトしている部分を有効にしたり、他の validates に「if: "title.valid_encoding?"」をつけていなかったりすると「invalid byte sequence in UTF-8」になる。

class EncodingValidator < ActiveModel::Validator
  def validate(record)
    unless record.title.valid_encoding?
      record.errors[:title] << "has invalid encoding"
    end
  end
end

class Post < ActiveRecord::Base
  validates :title, presence: true, if: "title.valid_encoding?"
  #validates_each :title do |record, attr, value|
  #end
  validates_with EncodingValidator
end