public
Last active

Twitter Bootstrap Form Builder

  • Download Gist
bootstrap_form_builder.rb
Ruby
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
class BootstrapFormBuilder < ActionView::Helpers::FormBuilder
 
delegate :capture, :content_tag, :tag, to: :@template
%w[text_field text_area password_field collection_select].each do |method_name|
define_method(method_name) do |name, *args|
errors = object.errors[name].any?? " error" : ""
error_msg = object.errors[name].any?? content_tag(:span, object.errors[name].join(","), class: "help-inline") : ""
content_tag :div, class: "clearfix#{errors}" do
field_label(name, *args) + content_tag(:div, class: "input#{errors}") do
super(name, *args) + " " + error_msg
end
end
end
end
 
def check_box(name, *args)
content_tag :div, class: "clearfix" do
content_tag(:div, class:"input") do
content_tag(:ul, class:"inputs-list") do
content_tag(:li) do
content_tag(:label) do
super(name, *args) + content_tag(:span) do
field_label(name, *args)
end
end
end
end
end
end
end
def div(*args, &block)
options = args.extract_options!
data = block_given? ? capture(&block) : ''
content_tag(:div, data, class: options[:class])
end
def submit(*args)
super(*args, class: "btn primary")
end
private
 
def field_label(name, *args)
options = args.extract_options!
required = object.class.validators_on(name).any? { |v| v.kind_of? ActiveModel::Validations::PresenceValidator}
label(name, options[:label], class: ("required" if required))
end
def objectify_options(options)
super.except(:label)
end
end

Ternary operations are easier to read when you isolate the "?".

Ex:

errors = object.errors[name].any? ? " error" : ""

Thanks for sharing. This is exactly what I was going to do after I watched that Railscast.

Yeah, that's true. For some reason, I was thinking of ?? as a real question. lol

Glad I helped you out.

Modified your method to add the help text also:

 %w[text_field text_area password_field collection_select].each do |method_name|
    define_method(method_name) do |name, *args|
      errors = object.errors[name].any? ? " error" : ""
      error_msg = object.errors[name].any? ? content_tag(:span, object.errors[name].join(","), class: "help-inline") : ""
      options = args.extract_options!
      help_text =  !options[:help_text].blank? ? content_tag(:span,options[:help_text], class: "help-block") : "" 
      content_tag :div, class: "clearfix#{errors}" do
        field_label(name, *args) + content_tag(:div, class: "input#{errors}") do
          super(name, *args) + " " + error_msg 
        end   +  help_text 
        
      end
      
    end
  end

Then you can pass help text as follows:

 f.text_area :tags, rows: 8, class: "span7", help_text: 'Please enter meaningful tags'

small correction, after extracting the options, you have to push it back again. Otherwise the options will not be passed .

 %w[text_field text_area password_field collection_select].each do |method_name|
    define_method(method_name) do |name, *args|
      errors = object.errors[name].any? ? " error" : ""
      error_msg = object.errors[name].any? ? content_tag(:span, object.errors[name].join(","), class: "help-inline") : ""
      options = args.extract_options!
      help_text =  !options[:help_text].blank? ? content_tag(:span,options[:help_text], class: "help-block") : ""
      args.push(options)
      content_tag :div, class: "clearfix#{errors}" do
        field_label(name, *args) + content_tag(:div, class: "input#{errors}") do
          super(name, *args) + " " + error_msg 
        end  +  help_text
        
      end
      
    end
  end

heh, is there an extract_options without the destructive !?

I don't think so. That's why I had to push the options again.

May be some ruby experts can help.

Sent from my iPhone

On Jan 7, 2012, at 3:26 PM, Dan Neumannreply@reply.github.com wrote:

heh, is there an extract_options without the destructive !?


Reply to this email directly or view it on GitHub:
https://gist.github.com/1526162

I tried your changes but it totally screwed up the forms. All of the styling went away. Then I changed the *args to options like so and it works. However, the help_text is left justified and not in alignment with the forms.

class BootstrapFormBuilder < ActionView::Helpers::FormBuilder

  delegate :capture, :content_tag, :tag, to: :@template

  %w[text_field text_area password_field collection_select].each do |method_name|
    define_method(method_name) do |name, *args|
      errors = object.errors[name].any?? " error" : ""
      error_msg = object.errors[name].any?? content_tag(:span, object.errors[name].join(","), class: "help-inline") : ""
      options = args.extract_options!
      help_text =  !options[:help_text].blank? ? content_tag(:span,options[:help_text], class: "help-block") : "" 
      content_tag :div, class: "clearfix#{errors}" do
        field_label(name, options) + content_tag(:div, class: "input#{errors}") do
          super(name, options) + " " + error_msg
        end + help_text
      end
    end
  end

  def check_box(name, *args)
    content_tag :div, class: "clearfix" do
      content_tag(:div, class:"input") do
        content_tag(:ul, class:"inputs-list") do
          content_tag(:li) do
            content_tag(:label) do
              super(name, *args) + content_tag(:span) do
                field_label(name, *args)
              end
            end
          end
        end
      end
    end
  end

  def submit(*args)
    super(*args, class: "btn primary")
  end

private

  def field_label(name, *args)
    options = args.extract_options!
    required = object.class.validators_on(name).any? { |v| v.kind_of? ActiveModel::Validations::PresenceValidator}
    label(name, options[:label], class: ("required" if required))
  end

  def objectify_options(options)
    super.except(:label)
  end

end

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.