1
0
Fork 0
mirror of https://github.com/rails/rails.git synced 2022-11-09 12:12:34 -05:00

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

View file

@ -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` * For actions with no corresponding templates, render `head :no_content`
instead of raising an error. This allows for slimmer API controller instead of raising an error. This allows for slimmer API controller
methods that simply work, without needing further instructions. methods that simply work, without needing further instructions.

View file

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

View file

@ -221,6 +221,7 @@ module ActionController
Cookies, Cookies,
Flash, Flash,
FormBuilder,
RequestForgeryProtection, RequestForgeryProtection,
ForceSSL, ForceSSL,
Streaming, Streaming,

View file

@ -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

View file

@ -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

View file

@ -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. * Accept lambda as `child_index` option in `fields_for` method.
*Karol Galanciak* *Karol Galanciak*

View file

@ -14,6 +14,7 @@ module ActionView
if @_controller = controller if @_controller = controller
@_request = controller.request if controller.respond_to?(:request) @_request = controller.request if controller.respond_to?(:request)
@_config = controller.config.inheritable_copy if controller.respond_to?(:config) @_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
end end

View file

@ -114,6 +114,8 @@ module ActionView
include ModelNaming include ModelNaming
include RecordIdentifier include RecordIdentifier
attr_internal :default_form_builder
# Creates a form that allows the user to create or update the attributes # Creates a form that allows the user to create or update the attributes
# of a specific model object. # of a specific model object.
# #
@ -1233,7 +1235,7 @@ module ActionView
end end
def default_form_builder_class 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 builder.respond_to?(:constantize) ? builder.constantize : builder
end end
end end

View file

@ -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

View file

@ -3269,6 +3269,30 @@ class FormHelperTest < ActionView::TestCase
ActionView::Base.default_form_builder = old_default_form_builder ActionView::Base.default_form_builder = old_default_form_builder
end 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 def test_fields_for_with_labelled_builder
output_buffer = fields_for(:post, @post, builder: LabelledFormBuilder) do |f| output_buffer = fields_for(:post, @post, builder: LabelledFormBuilder) do |f|
concat f.text_field(:title) concat f.text_field(:title)