テキストを入力するフォームを作るとみなさんホントにいろんな文字を入れてくれます。
全角英数字やら各種記号、不要な空白・改行から、『-』(全角ハイフンマイナス)や『 』(EM SPACE)のようなややこしいものまで。
あまり無秩序だと見た目的にもよろしくないし、データ検索する時にパッと見つけられなくて困ります。
あとSJISに変換するときにも困ります。(EXCEL CSVもうイヤだー)
で、ある時カッとなって俺のDBに変なデータはいれさせねえ!
と、保存時に自動でノーマライズする処理を作りました。
実装
こういうConcernを作ってます。
module StringNormalizable extend ActiveSupport::Concern # validate前にかってに変換 included do before_validation :normalize_changed_attributes end private # string, textで変更のあったカラムを変換 def normalize_changed_attributes changed_attributes.each do |key, _| self[key] = normalize(self[key]) if self[key].is_a?(String) && self[key].present? end end def normalize(str) str.strip # 前後の空白除去 .tr("0-9a-zA-Z ()-−", "0-9a-zA-Z ()-") # 全角英数字を半角に .gsub("\t", ' ').gsub(/ +/, " ") # 空白を単一半角スペースに統一 .gsub("\r\n", "\n").gsub("\r", "\n") # 改行を\nに統一 .unicode_normalize(:nfkc) # ㌧㌦とか end end
使ってみる
例えばこういうモデルに対して、
bin/rails g model articles title:string body:text bin/rake db:migrate
includeしてやると、
class Article < ApplicationRecord include StringNormalizable end
レコード作成、更新時に自動でノーマライズしてくれます。
pry(main)> article = Article.create(title: " ㌧\t\t㌦ ", body: "(AB)\r\n123") pry(main)> article.title => "トン ドル" pry(main)> article.body => "(AB)\n" + "123" pry(main)> article.title = "㈱ Ⅲ" => "㈱ Ⅲ" pry(main)> article.save pry(main)> article.title => "(株) III"
実際に使ってみて
処理としては特に問題なく動いています。
ただユーザーが入力するところでは全角系などは意識的に使ってる人も多く、『勝手に変換しないでほしい』という声が多かったので、今はもっと限定的な処理にしています。