きっかけ
個人開発アプリ「えらぶノート」に、アイテム登録時の価格と容量について、全角数字だとエラーになるので半角数字で入力してもらうようメッセージがあるといいのではないか、という旨のフィードバックをいただきました。
(ありがとうございます!!)
フィードバックを受けて検討した結果、これを機に全角数字で入力されたものは半角に自動変換する機能を実装してみることにしました!!
半角変換の実装方法
全角→半角の変換にはString#trメソッドを使いました。
"120".tr("0-9", "0-9")
# => "120"
これで全角入力された数字を自動で半角に変換できます。
価格のように整数だけならこれで十分ですが、容量については、化粧品など極端に少ないもの(3.5gなど)の登録も想定しているため、小数点まで入力できるようになっています。
そのため、変換対象には全角の小数点も加える必要がありました。
"123.5".tr("0-9.", "0-9.")
# => "123.5"
全角の小数点もこのように指定しておくだけで、ちゃんと半角に変換されます。
ちなみに日本語(カタカナ⇆半角カタカナ、ひらがな⇆カタカナ変換など)を含む文字列の変換は、NKF(Network Kanji code conversion Filter)という標準ライブラリが使えそうです!
今回は数字と小数点のみを対象とするため、String#trメソッドの方が適していると判断しました。
いざ!実装
今回は価格(price)と容量(capacity)にコードを追加していきます。
最初はbefore_validationでまとめて変換しようと考えました。
before_validation :normalize_price
def normalize_price
self.price = self.price.to_s.tr("0-9.", "0-9.")
end
しかし、priceはinteger型、capacityはdecimal型のため、代入した瞬間にRailsがそれぞれの型に変換しようとします。
全角の「120」は数値として認識されず、0や0.0に変換されてしまいました。
item.price = "120"
item.capacity = "120"
item.price
# => 0
item.capacity
# => 0.0
そこで、値を代入する処理そのものであるprice=・capacity=セッターを上書きし、代入されるタイミングで先に変換の処理が走るようにしました。
class Item < ApplicationRecord
def price=(value)
super(zenkaku_to_hankaku(value))
end
def capacity=(value)
super(zenkaku_to_hankaku(value))
end
private
def zenkaku_to_hankaku(value)
return value unless value.is_a?(String)
value.tr("0-9.", "0-9.")
end
end
全角数字を代入してみると、ちゃんと半角に変換されました!
item.price = "120"
item.capacity = "123.5"
item.price
# => 120
item.capacity
# => 123.5
まとめ
- 数値のみの全角⇆半角変換には
.trメソッドが良さそう。 - 日本語を含む文字列の変換には
NKFが良さそう。 -
before_validationは保存直前に呼ばれるので、その前段階の代入時のセッターを上書きして対応した。
もっと良い書き方や、こうした方がいいよ!というご意見が
あれば、ぜひコメントで教えてください!
参考記事など