I call this... The Fake Checkbox! :)
See, the problem is a normal HTML checkbox only submits to the server when it's checked. If it's unchecked, nothing gets sent to the server. Sometimes I want a value (like, umm, false?) sent to the server whether it's checked or unchecked.
So how do we go about making a checkbox that does this? The idea is simple -- make a normal checkbox with Javascript attached to it that updates a hidden input field when checked or unchecked.
Making a Rails helper to do this is simple -- put this in application_helper.rb.
1 def fake_check_box_tag(name, checked_values, is_checked, html_options = {})
2 onchange = html_options[:onchange] || ""
3 checked_value = checked_values[:checked] || 'true'
4 unchecked_value = checked_values[:unchecked] || 'false'
5 unique_id = rand.to_s[-5, 5]
6 poser_id = "fake_check_box_poser_#{unique_id}"
7 value_id = "fake_check_box_value_#{unique_id}"
8 onchange = onchange + "; doFakeCheckBoxClick(this, #{unique_id}, '#{checked_value}', '#{unchecked_value}')"
9
10 html_options.delete(:object_id)
11 html_options[:onchange] = onchange
12 html_options[:id] = poser_id
13
14 html = ''
15 html += hidden_field_tag name, is_checked ? checked_value : unchecked_value, :id => value_id
16 html += check_box_tag nil, 'true', is_checked, html_options
17 html
18 end
Then you need to define this Javascript function.
1 function doFakeCheckBoxClick(me, unique_id, checked_value, unchecked_value) {
2 unique_id = 'fake_check_box_value_' + unique_id
3 if (me.checked)
4 $(unique_id).value = checked_value;
5 else
6 $(unique_id).value = unchecked_value;
7 }
Now you can call it just like almost like the Rail's built in check_box_tag method.
1 fake_check_box_tag "person[is_female]",
2 { :checked => 'yes',
3 :unchecked => 'no' },
4 true,
5 { :onchange => "alert('checkbox clicked!')" }
In this example, if the checkbox is checked, the following will be true in your action:
params[:person][:is_female] == 'yes'
If it isn't checked, then this will be true:
params[:person[:is_female] == 'no'
The 3rd parameter (true) says that the checkbox will initially be checked.