Skip to content

Instantly share code, notes, and snippets.

@cbmeeks
Created December 28, 2011 03:59
Show Gist options
  • Star 16 You must be signed in to star a gist
  • Fork 5 You must be signed in to fork a gist
  • Save cbmeeks/1526162 to your computer and use it in GitHub Desktop.
Save cbmeeks/1526162 to your computer and use it in GitHub Desktop.
Twitter Bootstrap Form Builder
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
@danneu
Copy link

danneu commented Jan 1, 2012

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.

@cbmeeks
Copy link
Author

cbmeeks commented Jan 1, 2012

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

Glad I helped you out.

@SathishRaju
Copy link

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'

@SathishRaju
Copy link

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

@danneu
Copy link

danneu commented Jan 7, 2012

heh, is there an extract_options without the destructive !?

@SathishRaju
Copy link

SathishRaju commented Jan 7, 2012 via email

@cbmeeks
Copy link
Author

cbmeeks commented Jan 7, 2012

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.

@cbmeeks
Copy link
Author

cbmeeks commented Jan 7, 2012

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment