I’d like to be able to generate the following markup:
<label for="field">Something <span class="hint">Field hint</span></label>
from the following code:
form_for ... do |f|
f.label :field, :hint => "Field hint"
end
So far I’ve created an initializer to store the custom functionality which re-opens ActionView::Helpers::FormBuilder and changes the label method, however I’m not sure what the best way to actually get the span into the text for the label. If I try to put the text in directly then rails, rightly so, escapes the content.
I’d quite like to use the existing label infrastructure as it has all the validation error support. This rules out using content_tag and generating it all myself (which would work, but doesn’t seem… right).
Instead of changing the default builder, you should create a custom builder and pass it to the form with the :builder parameter.
The Hint builder inherits all FormBuilder features, including validation, error messages and so on. Now, you should change what you need to change in order to customize the behavior.
This is a really raw draft.
EDIT based on the first comment:
It’s always a good idea to not hack the Rails internals because you might need to use, now or in the future, plugins or features that rely on the original behavior. If you don’t want to manually append the builder in your forms, you can create an helper.
def search_form_for(record_or_name_or_array, *args, &proc)
options = { :builder => HintFormBuilder }
end
If you want to reopen the original class instead, I would suggest to create a new method. This solution also applies to the custom helper and has the benefit you can customize it without the need to gsub! the response. Yes, gsub! is the common way to do so because when extending the original methods you only have access to the method/options and the result, no the value (that is injected by the @object variable).
EDIT: I was mistaken, you can pass a custom text as a parameter so you don’t need to gsub! the returned string. I got confused by the text_field tag.
At this point, you can use either the first (subclassing with/without custom method), second (hacking internals) or third option (hacking internals with custom method) and intercept the text value before it is sent to @template.label.
Also note that text can be nil. If nil, the value is automatically generated from method. You should be aware of this.