Skip to content

Commit

Permalink
Override default form builder for a controller
Browse files Browse the repository at this point in the history
  • Loading branch information
kmcphillips committed Apr 14, 2015
1 parent efaec3d commit dbfe67e
Show file tree
Hide file tree
Showing 9 changed files with 124 additions and 1 deletion.
8 changes: 8 additions & 0 deletions actionpack/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
* Add ability to override default form builder for a controller.

class AdminController < ApplicationController
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.
Expand Down
1 change: 1 addition & 0 deletions actionpack/lib/action_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ module ActionController
autoload :Metal
autoload :Middleware
autoload :Renderer
autoload :FormBuilder

autoload_under "metal" do
autoload :Compatibility
Expand Down
1 change: 1 addition & 0 deletions actionpack/lib/action_controller/base.rb
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,7 @@ def self.without_modules(*modules)

Cookies,
Flash,
FormBuilder,
RequestForgeryProtection,
ForceSSL,
Streaming,
Expand Down
48 changes: 48 additions & 0 deletions actionpack/lib/action_controller/form_builder.rb
Original file line number Diff line number Diff line change
@@ -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
17 changes: 17 additions & 0 deletions actionpack/test/controller/form_builder_test.rb
Original file line number Diff line number Diff line change
@@ -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 change: 1 addition & 0 deletions actionview/lib/action_view/helpers/controller_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
4 changes: 3 additions & 1 deletion actionview/lib/action_view/helpers/form_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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.
#
Expand Down Expand Up @@ -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
Expand Down
21 changes: 21 additions & 0 deletions actionview/test/template/controller_helper_test.rb
Original file line number Diff line number Diff line change
@@ -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
24 changes: 24 additions & 0 deletions actionview/test/template/form_helper_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down

0 comments on commit dbfe67e

Please sign in to comment.