Well, I just stumbled upon something that I think is not really a bug, but rather a lack of consistency between some ActionView tag helper API methods.
For instance, let’s say you want to create a form with a radio button:
<%= radio_button_tag "webserver", "apache2.2" %>
|
And then, in order to create the label for it, you read the documentation:
Creates a radio button; use groups of radio buttons named the same to allow users to
select from a group of options.
Hmmm… Nice! Those rails folks are really awesome, they even bothered throwing in some examples:
radio_button_tag 'gender', 'male'
=> <input id="gender_male" name="gender"
type="radio" value="male" />
|
“Got it!”, you think. “It’s just add the name and the value, separated by underscore and we’re good to go!”. Clickety, clickety:
<%= label_tag "webserver\_apache2.2",
"Yes, I want this Native American server dude!" %>
|
Then, really proud of your self you go and pay localhost, port 3000 a visit. Without further delay you go blindly clicking the label.
After a brief pause, you look at your mouse, and wonder: “What the fsck?”.
You just realized clicking on the label didn’t select the radio button as you’d expect. “Okay, that was way too easy indeed, I must have typed something wrong… Yeah, for sure…”.
You go back to your code, check everything’s right, touch absolutely nothing – and you RELOAD!
<philosophical_moment>
Yeah, even though you changed nothing on your code, reloading sometimes works as a demonstration of faith on the force up above. I don’t know about you, but sometimes I just reload as if that was a sign I have faith and I deserved working code for that :).
</philosophical_moment>
So, after loosing faith on Saint Reload, you start forensics: left click > show me the money code. You chase after that nasty little radio button tag, and stuck inside some unaligned divs, with more classes than a MIT student, you find it:
<input id="webserver_apache22" name="webserver"
type="radio" value="apache2.2" />
|
“Nah, c’mon!”, you think, “How come that motherf little pretty radio button ate my dot?”. It turns out that the radio_button_tag handles the id generation differently from label_tag. Here’s how label_tag sanitizes the id:
def label_tag(name, text = nil, options = {})
content_tag :label, text || name.to_s.humanize,
{ "for" => sanitize_to_id(name) }
.update(options.stringify_keys)
end
|
And here’s sanitize_to_id:
def sanitize_to_id(name)
name.to_s.gsub(']','').gsub(/[^-a-zA-Z0-9:.]/, "_")
end
|
Finally, if you check how radio_button_tag comes up with its id:
def radio_button_tag(name, value, checked = false, options = {})
pretty_tag_value =
value.to_s.gsub(/\s/, "_").gsub(/(?!-)\W/, "")
.downcase
pretty_name =
name.to_s.gsub(/\[/, "_").gsub(/\]/, "")
html_options = {
"type" => "radio",
"name" => name,
"id" => "#{pretty_name}_#{pretty_tag_value}",
"value" => value }.update(options.stringify_keys)
html_options["checked"] = "checked" if checked
tag :input, html_options
end
|
You’ll realize that the rules are slightly different. As I said: for me it’s more a lack of coherence among those methods than really a bug.
Here’s a live manifestation of the bug I created for helping out:
http://labelbug.felipecoury.com
And the project on GitHub:
http://github.com/fcoury/labelbug/tree/master
So, I was good to point what’s wrong, but unfortunately I am still not that comfortable as to point a solution, so I will leave this one to the experts for now. I’ll just go back to praying that someday Saint Reload guides me through the miracle of self-healing code.