6
Help us understand the problem. What are the problem?

More than 5 years have passed since last update.

Organization

ラジオボタンが非選択のときにブラウザが値を送信してくれない事象をsimple_formで何とかする方法

困ったこと

ラジオボタンが非選択状態のとき、ブラウザはラジオボタン項目の値を送信してくれないのです(値がないから当然ですよねー)。

「非選択状態」という状態を保存したいとき、これだと保存されなくて困る。詰む。

解決方法

前提

rails4 + simple_form + twitter bootstrap3のマークアップです。

simple_form側の実装

こちらの記事で紹介されている方法をsimple_formで実装します。
radioボタンが非選択時、値を送信しないのに対応する

/app/inputs/collection_radio_buttons_input.rb
class CollectionRadioButtonsInput < SimpleForm::Inputs::CollectionRadioButtonsInput
  # @override
  def collection
    if translate(:options).present?
      translate(:options)
        .to_a
        .map { |elem| [elem.last, elem.first] }
        .push(['未回答', '']) # <= 空の項目を常に追加するようにする
    else
      super
    end
  end

  # @override
  def apply_nested_boolean_collection_options!(options)
    options[:item_wrapper_tag] = nil
  end

  # @override
  def build_nested_boolean_style_item_tag(collection_builder)
    hidden_class = collection_builder.value.blank? ? ' hidden' : ''
    collection_builder.label(class: item_wrapper_class + hidden_class) {
      collection_builder.radio_button + collection_builder.text
    }
  end

  # @override
  def item_wrapper_class
    'radio-inline'
  end
end

simple_formは基本的にオーバーライドして振る舞いを変えられるのが便利です。

collectionメソッドはラジオボタンの項目数が多すぎてもsimple_formでそこそこすっきり書く方法で紹介した、選択項目の値をconfig/locals/以下のファイルに書いてしまう方法を取り入れつつ、翻訳が存在する場合のみ空の項目を常に追加するようにしています(booleanのラジオボタンのときに誤判定する可能性もあるので、その辺考慮した方が良いです)。

こうやって空の項目を追加することで、「空白の値を持つラジオボタン」を作り出しているのです。

空白の値を持つラジオボタンは表示されないで欲しいので、build_nested_boolean_style_item_tagメソッドをオーバーライドして、空白の値の場合はhiddenクラスを追加するようにしています。hiddenにはdisplay: noneやらそんな感じのスタイルが定義されているので、表示上見えなくなるという寸法です。

ビュー側の実装

非選択状態のときは、内部的には空白の値を持つラジオボタンが選択されている状態でなければなりません。

そんな訳で、そういう風になるようにJavaScriptで制御してあげる必要があります。

今回は既に選択してあるラジオボタンをクリックすると、ラジオボタンが非選択状態になる、という振る舞いを実現します。

beforeRadioValue = null
$('input:radio').on 'mousedown', ->
  beforeRadioValue = $("input:radio[name='#{$(this).attr('name')}']:checked").val()
.on 'click', ->
  if $(this).val() == beforeRadioValue
    # 既に選択してあるラジオボタンをクリックしたときに、空白の値を持つラジオボタンが選択されるようにする
    $(this).closest('.form-group').find("input:radio[value='']").prop('checked', true)

これでサーバに空白の値が送信されるようになります。めでたしめでたし。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Sign upLogin
6
Help us understand the problem. What are the problem?