-
Notifications
You must be signed in to change notification settings - Fork 21.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Set default form builder for a controller #19736
Conversation
@@ -14,7 +14,9 @@ def protect_against_forgery?() false end | |||
class BlockTestCase < ActiveSupport::TestCase | |||
def render_content(start, inside) | |||
template = block_helper(start, inside) | |||
ActionView::Template::Handlers::Erubis.new(template).evaluate(ViewContext.new) | |||
context = ViewContext.new | |||
context.controller = BasicController.new |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The context in this test was missing a controller
and was raising on nil
.
@kmcphillips what about defining a method like |
@senny it’s not that writing a wrapper like The background to this patch is that we’re starting to use more custom form builders in Shopify (a rather large Rails project) and are hitting a complexity wall with the workarounds mentioned above. |
Overriding a custom Rails allows you to scope nearly everything cleanly to split an app into sections, with this notable exception. Especially since you have the ability to override the form builder globally. Shopify isn't the first project where I have wanted this feature either, FWIW. |
About the feature, I can see as it can be useful. This would be similar to when we define which helper module is loaded by controller (if we disable the global require). About the implementation, this is coupling Action View with Action Controller. How about instead making Action View asking Action Controller what is the form builder, we do not set it when creating the |
Also I can see how Simple Form can benefits of this feature. |
@rafaelfranca Agree. Don't like the coupling. I'll look at refactoring it to Action View. |
Given we will have a default form builder per action view instance and it Another thing, maybe we should call the singleton method On Mon, Apr 13, 2015, 12:51 Kevin McPhillips notifications@github.com
|
@rafaelfranca Great feedback. I think it's a great idea to deprecate the global I'll rename the method to be About the implementation. I can delegate That makes the implementation in the def default_form_builder_class
builder = default_form_builder || ActionView::Base.default_form_builder And that works. But when the view is not an instance of I'm not sure if that means this test is broken, or if this is a valid case. I can do What do you think? |
I think instead of delegating we should do the same we do with And we define: def default_form_builder_class
builder = @_default_form_builder || ActionView::Base.default_form_builder Or use a I think this would fix the problem with the custom view context. |
Ok, updated. I also added tests to both the |
Set default form builder for a controller
Awesome! |
@@ -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 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Typo of subclass
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@rafaelfranca Fixed in b4a9c59
Just to add to the discussion, deprecating the AV config might not be an option if we want people to actually use it decoupled (which means there will be no controller default to inherit from). |
@carlosantoniodasilva yeah, I thought that when I was merging it and forget to comment here. |
👍 On Tue, Apr 14, 2015 at 1:56 PM, Rafael Mendonça França <
At. |
Super great. Thanks! 🚀 🌙 |
Nice job everybody. |
Any chance this will end up in a 4.2.x release? |
No. New features are not added to stable releases |
I looked around for a Rails release roadmap, but I didn't find one. Should I expect this in a 4.3.x release or something else? |
It will be in the Rails 5 release |
Problem
Form builders can only be overridden per call of
form_for
, or globally for the entire application. Often form builders will be specialized for all forms in a particular section or area. There is currently no way of defining a default form builder scoped to a particular area or context. This leads to repetition with having to pass in the form builder explicitly into every form.Solution
Define a
form_builder
singleton method on the controller which allows a from builder to be specified per controller. DRY in the views.This is modeled after how a layout is defined per controller.
This override has a higher prescidence than the
ActionView
globaldefault_form_builder
option, but lower prescidence than the explicitbuilder:
option when callingform_for
.Example
Given a section specific form builder:
And an abstract controller superclass for an admin area:
Any calls to
form_for
for that controller or its subclasses will default to the form builder declared in that controller.Tested in this example app:
https://github.com/kmcphillips/rails-test-app
Workarounds
The existing but insufficient workarounds I have been able to identify are:
form_for
method to injectbuilder:
into the options hash.builder:
option into everyform_for
call.config.action_view.default_form_builder
which contains specializations that may not apply to all areas.cc @arthurnn @edward