Railsで金額の入力フォーム。Javascriptでカンマ区切りと漢数字変換、右寄せ。保存はGemで数値にする

Railsで金額を入力するフォームをリッチにするCoffeeScriptとGemを紹介します。

![success.gif](https://qiita-image-store.s3.amazonaws.com/0/108235/cdb6881d-6327-c60c-a69c-bf80bec5656d.gif)

 - ３桁ごとにカンマ
 - 漢数字変換
 - 右寄せ
 - データベースには数値で保存

# 使い方

テキストフィールドにして、moneyなどの適当なクラス名をつけます

```slim:slim
 = f.text_field :some_budget, {class: 'money'}
```


JSでmoneyクラスに対して、キーアップやチェンジのタイミングで`money_format`関数を適用します

```coffeescript:Javascript
$('.money').on 'change', -> $(@).val(money_format($(@).val()))
```

Gemを使ってPostされてきたカンマ区切りの文字列を数値に変換して保存する宣言をします

```rb:model
# ar_strip_commas
# gem install ar_strip_commas
strip_commas_from :some_budget
```

`strip_commas_from`は**ar_strip_commas**のメソッドです
このGemはカンマ区切りの金額を数値に変換してDBに保存してくれます

https://github.com/tilleryj/ar_strip_commas

# 数値と漢数字をカンマ区切りの金額に変換する実装

こちらをassets/javascripts/の適当な場所に置いておきます。
`money_format`というメソッドが使えるようになります。

```coffeescript:money_field.coffee
suuji = '〇一二三四五六七八九零壱弐参肆伍陸質捌玖零壹貳參'
keta1 = '十百千拾佰仟十陌阡'
keta2 = '万億兆京垓萬'
arb = '0123456789０１２３４５６７８９'

@money_format = (str) ->
  number_format(toArb(toHalfWidth(reject_format(str)).replace(/(\d)/g, num2ja)))

@reject_format = (val) ->
  str = ''
  i = 0
  while i < val.length
    c = val.charAt(i)
    if suuji.search(c) != -1 or keta1.search(c) != -1 or keta2.search(c) != -1 or arb.search(c) != -1
      str = str + c
    i++
  str

@number_format = (val) ->
  s = '' + val
  if s.length > 3
    r = if (r = s.length % 3) == 0 then 3 else r
    d = s.substring(r)
    s = s.substr(0, r) + d.replace(/(\d{3})/g, ',$1')
  s

@toArb = (kanji) ->
  b = 0
  t = 0
  f = false
  i = 0
  while i < kanji.length
    c = kanji.charAt(i)
    if (r = suuji.indexOf(c)) != -1
      if f == false
        b += r % 10
        f = true
      else
        b = b * 10 + r % 10
    else if (r = keta1.indexOf(c)) != -1
      t += b
      d = t % 10
      a = (if d == 0 then 1 else d) * 10 ** (r % keta2.length + 1)
      t += a - d
      b = 0
      f = false
    else if (r = keta2.indexOf(c)) != -1
      t += b
      d = t % 10000
      a = d * 10000 ** (r % keta2.length + 1)
      t += a - d
      b = 0
      f = false
    else
      return kanji
    i++
  t + b

@conv = ->
  reg = new RegExp('[' + suuji + keta1 + '][' + suuji + keta1 + keta2 + ']*', 'g')
  src = document.F1.S1.value
  document.F1.S2.value = src.replace(reg, ($0) ->
    r = toArb($0)
    if document.F1.C1.checked
      r = number_format(r)
    r
  )
  return

@num2ja = (num) ->
  `var i`
  `var suuji`
  sign =
    '+': ''
    '-': '−'
  zero = '零'
  point = '点'
  zero2nine = [
    '〇'
    '一'
    '二'
    '三'
    '四'
    '五'
    '六'
    '七'
    '八'
    '九'
  ]
  ten2thou = [
    ''
    '十'
    '百'
    '千'
  ]
  suffices = [
    ''
    '万'
    '億'
    '兆'
    '京'
    '垓'
    '禾予'
    '穣'
    '溝'
    '澗'
    '正'
    '載,'
    '極'
    '恒河沙'
    '阿僧祇'
    '那由他'
    '不可思議'
    '無量大数'
  ]
  num = num.replace(/,/g, '')
  num.match /([+-])?(\d+)(?:\.(\d+))?/i
  sig = RegExp.$1
  int = RegExp.$2
  fract = RegExp.$3
  seisuu = ''
  shousuu = ''
  shins = new Array
  counter = 0
  i = int.length
  while i > 0
    shins.push int.substring(i, i - 4)
    i -= 4
  if shins.length >= 18
    return suffices[17]
  suffix = 0
  i = 0
  while i < shins.length
    shin = shins[i]
    if shin == '0000'
      suffix++
      i++
      continue
    sens = ''
    keta = 0
    digits = shin.split('').reverse()
    j = 0
    while j < digits.length
      digit = digits[j]
      suuji = if digit == 1 and keta > 0 then '' else zero2nine[digit]
      if digit != 0
        sens = suuji + ten2thou[keta] + sens
      keta++
      j++
    seisuu = sens + suffices[suffix++] + seisuu
    i++
  result = seisuu
  result = result or zero
  if fract
    result = result + point + fract
  result

@toHalfWidth = (strVal) ->
  halfVal = strVal.replace(/[！-～]/g, (tmpStr) ->
    String.fromCharCode tmpStr.charCodeAt(0) - 0xFEE0
  )
  halfVal.replace(/”/g, '"').replace(/’/g, '\'').replace(/‘/g, '`').replace(/￥/g, '\\').replace(RegExp('　', 'g'), ' ').replace /〜/g, '~'
```