🧪 ☣️ This gem is an experiment. Please do not use it for anything other than to explore the new concepts it brings into Rails.
New!
Visit the AttributeBuilders playground https://attributebuilders.julianpinzon.com to see all of this in action!
Install the gem in your Rails application. Use:
$ bundle add actionview_attribute_builders
Or add it directly in your Gemfile
gem 'actionview_attribute_builders', '~> 0.1.0'
And then execute:
$ bundle
1. Create a custom form builder
# app/form_builders/example_form_builder.rb
class ExampleFormBuilder < ActionView::Helpers::FormBuilder
end
2. Add a text_field
method, overriding the one inherited from its parent (Rails' default)
# app/form_builders/example_form_builder.rb
class ExampleFormBuilder < ActionView::Helpers::FormBuilder
def text_field(method, options = {})
# ...
end
end
3. Use the appropriate <helper>_attribute_builder
method for the type of field you're creating
In this case text_field_attribute_builder
# app/form_builders/example_form_builder.rb
class ExampleFormBuilder < ActionView::Helpers::FormBuilder
def text_field(method, options = {})
# 1. Retreive an instance of the `AttributeBuilders::TextField` class via the helper method
attribute_builder = text_field_attribute_builder(method, options)
# 2. Use the `html_attributes` method to retrieve the computed attributes. Commonly, `id`, `name`, `value` etc.
html_attributes = attribute_builder.html_attributes
# => { id: "user_name", name: "user[name]", value: "Julian" }
end
end
4. Render the HTML form element
# app/form_builders/example_form_builder.rb
class ExampleFormBuilder < ActionView::Helpers::FormBuilder
def text_field(method, options = {})
# ...
# 3. Use the attributes to create the markup.
# 3.1 For example, use a web component
@template.content_tag("example-text-field", nil, html_attributes.merge!(options))
# 3.1 Or a ViewComponent
@template.render(ExampleFieldComponent.new(html_attributes, options))
end
end
5. Use the new form builder in a template
<%= form_with model: @user, builder: ExampleFormBuilder do |form| %>
<%= form.text_field :name, required: true, label: "Name" %>
<% end %>
6. Check the output in your browser's inspector to verify the new markup
Note how, just like in a plain Rails application, the field includes the conventional name
, type
and id
attributes based on the model used.
<form action="/users" accept-charset="UTF-8" method="post"><input type="hidden" name="authenticity_token" value="3EgNNhL-HUI-2gxV_-9T_cEaT8p6b4CWtVbQMCeHlaKlfgd_p9sFuuLVKaDkUt3gEQKhc_d7YdR-TFzp-LiAuA" autocomplete="off">
<example-text-field required="" type="text" name="user[name]" id="user_name"></example-text-field>
</form>
6. Do this for *every form helper
number_field
, password_field
, checkbox
etc.
* every helper that's currently supported. Not all of them are done
Visit the Attribute Builders playground https://attributebuilders.julianpinzon.com for an interactive preview of this gem in action.
👀 Images inside!
Visit the examples folder and follow the guides on how to use this with real components using Shoelace and Material Design Web Components.
This library exposes helpers that use the exact same mechanics to create form input element attributes that Rails uses internally to create input elements that are compliant with ActiveModel
and ActiveRecord
conventions.
Check out the lib/actionview_attribute_builders/attribute_builders_helper for a list of all currently supported builders.
This library is not finished. There are several things missing. For example:
- Not all attribute builders have been extracted from Rails. There are currently 4 missing input fields and some extra missing helpers (like buttons and input submit fields)
- Some helpers are far more complex than others and probably can't be used yet in a real scenario. For example,
<select>
tags (and similar elements) are harder because they are composed of not one but multiple html elements (<select>
and<option>
). This problem is yet to be solved. - The way the gem is loaded is a bit hacky and has a lot of garbage comments.
Attributer Builder | Available? |
---|---|
check_box | ✅ |
collection_check_boxes | ◻️ |
collection_radio_buttons | ◻️ |
collection_select | ✅ |
color_field | ✅ |
date_field | ✅ |
date_select | ◻️ |
datetime_field | ✅ |
datetime_select | ◻️ |
email_field | ✅ |
file_field | ✅ |
grouped_collection_select | ✅ |
hidden_field | ✅ |
label | ✅ |
month_field | ✅ |
number_field | ✅ |
password_field | ✅ |
radio_button | ✅ |
range_field | ✅ |
search_field | ✅ |
select | ✅ |
tel_field | ✅ |
text_area | ✅ |
text_field | ✅ |
time_field | ✅ |
time_select | ◻️ |
time_zone_select | ✅ |
url_field | ✅ |
week_field | ✅ |
weekday_select | ✅ |
submit | ❌ |
button | ❌ |
The short version is that Rails has a lot of conventions for form fields to work seamlessly with ActiveModel
and ActiveRecord
. However, these are not exposed to developers; they are deeply nested and coupled to the rendering of the actual markup. This makes creating new FormBuilders
notoriously hard or even impossible in some cases. This forces developers to abandon Rails' conventions which is not desirable.
This gem's objective is to separate those responsibilities so developers can leverage Rails' conventions to build custom form elements and keep enjoying the advantages of convention over configuraiton.
I have written extensively about this problem. If you're interested, please read the following:
- https://dev.julianpinzon.com/series/exploring-rails-forms
- ViewComponent/view_component#420 (comment)
The best way to contribute to this gem in its current state is:
- to experiment with it and build custom
FormBuilder
classes. - start a discussion or issue on this repo
The gem is available as open source under the terms of the MIT License.