But instead of putting the logic into a Helpers method or Decorator class, moving it into a customized FormBuilder is worth a consideration.
Especially when it:
- is tied to a form
- is repeated
- generates tags (or even multi tag widgets)
<% form_for @recipe do |f| %> <% (1..10).each do |rating| %> <%= f.radio_button :rating, rating %> <%= f.label "rating_#{rating}", rating %> <% end %> <% end %>What if the view could be refactored to:
<% form_for @recipe, builder: Forms::CollectionFormBuilder do |f| %> <%= f.labeled_radio_button_group 1..10, :rating %> <% end %>Please note the defined option builder:, pointing to the customized FormBuilder.
The better readability is obvious, aside from the less coding. It can be achieved by creating a new class (collection_form_builder.rb) in lib/forms:
module Forms class CollectionFormBuilder < ActionView::Helpers::FormBuilder def labeled_radio_button_group collection, method, options={} collection.inject(''.html_safe) { |html, value| checked = object.send(method).eql? value options[:id] = "#{method}_#{value}" html += @template.radio_button_tag("#{@object_name}[#{method}]", value, checked, options) + @template.label_tag(options[:id], value) } end end endby inheriting from ActionView::Helpers::FormBuilder. Thus some instance variables stated by FormBuilder#form_for are available:
- @object (the object assigned to form_for itself, like @recipe)
- @object_name (the objects name, like "recipe")
- @template (the current view (an instance of ActionView::Base); this object provides all methods available in your view)
- @options (the options assigned to form_for)
- @proc (the block assigned to form_for)
@template.render partial: "fancy_widget", locals: { object: @object }Besides overwriting existing FormBuilder methods can make sense:
module Forms class LabeledFormBuilder < ActionView::Helpers::FormBuilder def check_box method, options={}, checked_value="1", unchecked_value="0" text = options.delete :text @template.content_tag(:label) { super(method, options, checked_value, unchecked_value) + (text or checked_value).to_s.html_safe } end end endwhich generates the typical check box tag embraced by a label tag:
<% form_for @recipe, builder: Forms::LabeledFormBuilder do |f| %> <%= f.check_box :published, text: 'Published', id: nil %> <% end %>resulting in HTML:
Further articles of interest:
Supported by Ruby 2.1.1 and Ruby on Rails 4.1.8
Keine Kommentare:
Kommentar veröffentlichen