I've been building a new Rails 8 application recently. I'm all in on View Components, and have enjoyed building it out as pure and Rails-y as possible.
I came across a (documented) gotcha around using Rails Form Builders in View Components. Here's how I got the setup I want.
Setting default Form Builder in Rails View Components
class ApplicationComponent < ViewComponent::Base
alias_method :original_form_with, :form_with
def form_with(**args, &block)
original_form_with(**args, builder: MyFormBuilder, &block)
end
end
The above renames the form_with
method to
original_form_with
to get it out of our way. It then inserts an
extra builder: MyFormBuilder
, so you never have to
think about it again.
Using View Components in Form Builders
For posterity, here's the rest of my Rails View Component Form set up:
class MyFormBuilder < ActionView::Helpers::FormBuilder
def my_submit(**args, &block)
defaults = {
type: :submit
}
view_context.render MyButtonComponent.new(**defaults.merge(args))
end
private
def view_context
@view_context ||= ApplicationController.new.view_context
end
end
Allowing you to then use:
form_with ... do |form|
form.my_submit
end
Here we create a new Form Builder at config/initializers/my_form_builder.rb
inheriting from the default.
I've added a private method to get a controller ViewContext so we can render view components with no extra faffing about.
class ApplicationController < ActionController::Base
default_form_builder MyFormBuilder
...
end
Lastly we set the default builder using the handy Rails default_form_builder
, these folks thought of everything.
Extra Context + Sources
This was an intentional decision from the View Components team to prevent unexpected changes to rendering behavior.
Thanks to Lucas Mendelowski for the helpful article on how to easily slot VCs into Form Builders, shown above.