Override default form builder for a controller

This commit is contained in:
Kevin McPhillips 2015-04-06 22:20:57 -04:00
parent efaec3dd63
commit 2b8acdcd21
10 changed files with 129 additions and 1 deletions

@ -1,3 +1,11 @@
* Add ability to override default form builder for a controller.
class AdminController < ApplicationController
default_form_builder AdminFormBuilder
end
*Kevin McPhillips*
* For actions with no corresponding templates, render `head :no_content`
instead of raising an error. This allows for slimmer API controller
methods that simply work, without needing further instructions.

@ -12,6 +12,7 @@ module ActionController
autoload :Metal
autoload :Middleware
autoload :Renderer
autoload :FormBuilder
autoload_under "metal" do
autoload :Compatibility

@ -221,6 +221,7 @@ def self.without_modules(*modules)
Cookies,
Flash,
FormBuilder,
RequestForgeryProtection,
ForceSSL,
Streaming,

@ -0,0 +1,48 @@
module ActionController
# Override the default form builder for all views rendered by this
# controller and any of its descendents. Accepts a sublcass of
# +ActionView::Helpers::FormBuilder+.
#
# For example, given a form builder:
#
# class AdminFormBuilder < ActionView::Helpers::FormBuilder
# def special_field(name)
# end
# end
#
# The controller specifies a form builder as its default:
#
# class AdminAreaController < ApplicationController
# default_form_builder AdminFormBuilder
# end
#
# Then in the view any form using +form_for+ will be an instance of the
# specified form builder:
#
# <%= form_for(@instance) do |builder| %>
# <%= builder.special_field(:name) %>
# <%= end %>
module FormBuilder
extend ActiveSupport::Concern
included do
class_attribute :_default_form_builder, instance_accessor: false
end
module ClassMethods
# Set the form builder to be used as the default for all forms
# in the views rendered by this controller and its subclasses.
#
# ==== Parameters
# * <tt>builder</tt> - Default form builder, an instance of +ActionView::Helpers::FormBuilder+
def default_form_builder(builder)
self._default_form_builder = builder
end
end
# Default form builder for the controller
def default_form_builder
self.class._default_form_builder
end
end
end

@ -0,0 +1,17 @@
require 'abstract_unit'
class FormBuilderController < ActionController::Base
class SpecializedFormBuilder < ActionView::Helpers::FormBuilder ; end
default_form_builder SpecializedFormBuilder
end
class ControllerFormBuilderTest < ActiveSupport::TestCase
setup do
@controller = FormBuilderController.new
end
def test_default_form_builder_assigned
assert_equal FormBuilderController::SpecializedFormBuilder, @controller.default_form_builder
end
end

@ -1,3 +1,8 @@
* Load the `default_form_builder` from the controller on initialization, which overrides
the global config if it is present.
*Kevin McPhillips*
* Accept lambda as `child_index` option in `fields_for` method.
*Karol Galanciak*

@ -14,6 +14,7 @@ def assign_controller(controller)
if @_controller = controller
@_request = controller.request if controller.respond_to?(:request)
@_config = controller.config.inheritable_copy if controller.respond_to?(:config)
@_default_form_builder = controller.default_form_builder if controller.respond_to?(:default_form_builder)
end
end

@ -114,6 +114,8 @@ module FormHelper
include ModelNaming
include RecordIdentifier
attr_internal :default_form_builder
# Creates a form that allows the user to create or update the attributes
# of a specific model object.
#
@ -1233,7 +1235,7 @@ def instantiate_builder(record_name, record_object, options)
end
def default_form_builder_class
builder = ActionView::Base.default_form_builder
builder = default_form_builder || ActionView::Base.default_form_builder
builder.respond_to?(:constantize) ? builder.constantize : builder
end
end

@ -0,0 +1,21 @@
require 'abstract_unit'
class ControllerHelperTest < ActionView::TestCase
tests ActionView::Helpers::ControllerHelper
class SpecializedFormBuilder < ActionView::Helpers::FormBuilder ; end
def test_assign_controller_sets_default_form_builder
@controller = OpenStruct.new(default_form_builder: SpecializedFormBuilder)
assign_controller(@controller)
assert_equal SpecializedFormBuilder, self.default_form_builder
end
def test_assign_controller_skips_default_form_builder
@controller = OpenStruct.new
assign_controller(@controller)
assert_nil self.default_form_builder
end
end

@ -3269,6 +3269,30 @@ def test_lazy_loading_default_form_builder
ActionView::Base.default_form_builder = old_default_form_builder
end
def test_form_builder_override
self.default_form_builder = LabelledFormBuilder
output_buffer = fields_for(:post, @post) do |f|
concat f.text_field(:title)
end
expected = "<label for='title'>Title:</label> <input name='post[title]' type='text' id='post_title' value='Hello World' /><br/>"
assert_dom_equal expected, output_buffer
end
def test_lazy_loading_form_builder_override
self.default_form_builder = "FormHelperTest::LabelledFormBuilder"
output_buffer = fields_for(:post, @post) do |f|
concat f.text_field(:title)
end
expected = "<label for='title'>Title:</label> <input name='post[title]' type='text' id='post_title' value='Hello World' /><br/>"
assert_dom_equal expected, output_buffer
end
def test_fields_for_with_labelled_builder
output_buffer = fields_for(:post, @post, builder: LabelledFormBuilder) do |f|
concat f.text_field(:title)