how to correctly extend form_for / ActionView::Helpers::FormBuilder?
This is similiar to Trying to extend ActionView::Helpers::For开发者_如何转开发mBuilder but I don't want to use :builder => MyThing.
I want to extend form builder to add custom methods. This is the current situation:
module ActsAsTreeHelpers
def acts_as_tree_block(method, &block)
yield if block_given?
end
end
ActionView::Helpers::FormBuilder.send :include, ::ActsAsTreeHelpers
Console:
ruby-1.9.2-p180 :004 > ActionView::Helpers::FormBuilder.included_modules
=> [ActsAsTreeHelpers, ...]
But the following gives me: undefined method acts_as_tree_block for #<ActionView::Helpers::FormBuilder:0xae114dc>
<%= form_for thing do |form| %>
<%= form.acts_as_tree_block :parent_id, {"test"} %>
<% end %>
What am I missing here?
I also had the same problem. I tried to add a new file named form_builder.rb in folder config/initializers of my project and it works well now.
Below are some contents of my solution. base_helper.rb
def field_container(model, method, options = {}, &block)
css_classes = options[:class].to_a
if error_message_on(model, method).present?
css_classes << 'withError'
end
content_tag('p', capture(&block), :class => css_classes.join(' '), :id => "#{model}_#{method}_field")
end
form_builder.rb
class ActionView::Helpers::FormBuilder
def field_container(method, options = {}, &block)
@template.field_container(@object_name,method,options,&block)
end
def error_message_on(method, options = {})
@template.error_message_on(@object_name, method, objectify_options(options))
end
end
ActionView::Base.field_error_proc = Proc.new{ |html_tag, instance| "<span class=\"field_with_errors\">#{html_tag}</span>".html_safe }
_form.html.erb
<%= f.field_container :name do %>
<%= f.label :name, t("name") %> <span class="required">*</span><br />
<%= f.text_field :name %>
<%= f.error_message_on :name %>
<% end %>
The accepted answer no longer worked for me (Rails 5+)
Here is the changes I made to get it to work (Rails 5.2.3) :
# config/initializers/custom_form_builder.rb
class ActionView::Helpers::FormBuilder
def my_custom_text_field_with_only_letters(method, options = {})
options[:pattern] = "^[A-Za-z]+$"
options[:title] = "Only letters please"
text_field(method, options)
end
field_helpers << :my_custom_text_field_with_only_letters
end
field_helpers << :my_custom_text_field_with_only_letters
makes sure your new method is available natively in all your application forms.
According to the doc, another possibility is to extend FormBuilder , add your custom method, and then specify in each of your wanted forms which FormBuilder to use :
class MyFormBuilder < ActionView::Helpers::FormBuilder
def div_radio_button(method, tag_value, options = {})
...
<%= form_for @person, :builder => MyFormBuilder do |f| %>
<%= f.div_radio_button(:admin, "child") %>
精彩评论