Today I’ll be finishing up my code reading session of formtastic by looking at how it creates the input fields.
The Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
module Formtastic #:nodoc: class SemanticFormBuilder < ActionView::Helpers::FormBuilder def basic_input_helper(form_helper_method, type, method, options) #:nodoc: html_options = options.delete(:input_html) || {} html_options = default_string_options(method, type).merge(html_options) if [:numeric, :string, :password, :text].include?(type) self.label(method, options_for_label(options)) << self.send(form_helper_method, method, html_options) end # Outputs a label and standard Rails text field inside the wrapper. def string_input(method, options) basic_input_helper(:text_field, :string, method, options) end # Outputs a label and standard Rails password field inside the wrapper. def password_input(method, options) basic_input_helper(:password_field, :password, method, options) end # Outputs a label and standard Rails text field inside the wrapper. def numeric_input(method, options) basic_input_helper(:text_field, :numeric, method, options) end # Ouputs a label and standard Rails text area inside the wrapper. def text_input(method, options) basic_input_helper(:text_area, :text, method, options) end # Outputs a label and a standard Rails file field inside the wrapper. def file_input(method, options) basic_input_helper(:file_field, :file, method, options) end end end |
Review
The first thing I noticed is that many of the common inputs all use the same method to create the input just with different parameters, #basic_input_helper
. So lets dig into #basic_input_helper
deeper.
HTML Options
1 2 |
html_options = options.delete(:input_html) || {} html_options = default_string_options(method, type).merge(html_options) if [:numeric, :string, :password, :text].include?(type) |
First #basic_input_helper
sets up the input_html
options. If you remember, this option was used to control the html attributes of the input element in more detail.
Then :numeric
, :string
, :password
, and :text
fields will get some extra options from #default_string_options
. This includes sizing information that is be pulled directly from the database (e.g. 4 characters max size).
Input generation
1 2 |
self.label(method, options_for_label(options)) << self.send(form_helper_method, method, html_options) |
Finally, #basic_input_helper
generates a label for the input and then runs the ActionView method to create the input. If you remember, the form_helper_method
was passed in from the inputs earlier (:text_field
, :password_field
, etc).
So that completes my code reading of formtastic. I started with the form generation, figured out how it automatically gets all of the fields on a model, walked though how all of the field options are created, saw how it uses reflection to find the type of input for each field, and how those inputs are passed to ActionView to be rendered into HTML. There is still a lot of other code in formtastic, including some generators for more advanced fields if you’re interested in reading further.