A gem for Ruby on Rails which wraps up functionality of maintaining values for forms to factor cases where a POST fails model validation whilst also providing a means to succinctly produce relevant error messages.
Consider a simple form which is primarily defined by an HTML input element and its label:
Consider added functionality which presents a new label informing the user any errors discovered upon POST whilst also maintaining the value the user had previously submitted:
It's important to validate such fields on the server, even if JavaScript is doing this work on the front end. Within Ruby on Rails, (using HAML), the logic may look like the following:
%div.input-group
- value = {}
- if flash[:values] and flash[:values][:email:]
- value = {:value => flash[:values][:email]}
= label :user, :email, 'Email', {:class => "input-group-text"}
= text_field :user, :email, {:class => "form-control", :placeholder => "Your Email", :disabled => false}.merge(value)
- if (flash[:errors] and flash[:errors][:email])
= label :user, :email', flash[:errors][:email][0], {:class => "alert-danger input-group-text"}
This gem condenses the above into more a more concise set of method calls:
%div.input-group
= form_input_field :text_field, :user, :email, "Email", {:class => "form-control", :placeholder => "Your Email", :disabled => false}, {:class => "input-group-text"}
= form_error_field :user, :email, {:class => "alert-danger input-group-text"}
This makes a view much more clean and easier to digest at a glance.
Add this line to your application's Gemfile:
gem 'form_input_field'
And then execute:
$ bundle
Or install it yourself as:
$ gem install form_input_field
This gem places two helper methods into ActionView::Helpers::FormHelper. These methods are form_input_field
and form_error_field
.
To see some examples, go to the Examples Section of this document.
form_input_field
is an abstraction on the software pattern which encapsulates some input element and its label. Additionally, it has built in functionality which helps ensure the input element's value attribute is filled should the flash hash-map contain the presence of this value.
form_input_field(helper_sym, object_name, method, label_text = false, options = {}, label_options = {}, value_key = :values)
- Outputs two html tags - a label HTML element pointing to its corresponding input HTML element. The term "input HTML element" here is ambiguous; it's not meant to be taken literally. "Input" in this context is meant to be interpreted as any output produced by the following list of helper functions within
ActionView::Helpers::FormHelper
:- color_field, date_field, datetime_field, datetime_local_field, email_field, file_field, hidden_field, month_field, number_field, password_field, phone_field, range_field, search_field, telephone_field, text_area, text_field, time_field, url_field, week_field
- In addition to the above list of
FormHelper
method calls,form_input_field
captures two special cases - check_box and radio_button. These are described later.
- The
helper_sym
argument describes the relevant helper method to be called. It expects the method name as a symbol. I.e., if one needs a call to text_field, pass:text_field
; If one needs a call to password_field, supply a value of:password_field
, etc. - The
object_name
andmethod
arguments correspond to the equivalently named arguments as described inActionView::Helpers::FormHelper
. - The
label_text
argument expects a string for the associated label of the generated input HTML element described byhelper_sym
. Supplying a false will instead not produce a label HTML element; an empty string is produced for the label. - The
options
argument corresponds to a hash-map representing the set of options to be passed withhelper_sym
; these are the options to be given to a method call from the above set of helper methods. Esentially a hash-map of html properties and attributes. I.e.,{:style => "color:red;"}
- The
label_options
argument corresponds to a hash-map representing the set of options to be passed with the call to the label helper method fromActionView::Helpers::FormHelper
. Essentially a hash-map of html properties and attributes to be applied to the label. I.e.,{:style => "color:red;"}
- The
value_key
argument is a symbol that acts as a key for the flash hash-map that contains the relevant value filled by the controller. If the value associated with said key within flash is a string, then the string will occupy thevalue
attribute for the produced input HTML element. If it is a hash-map, it will then assume that the value given formethod
is the key to the string within this embedded hash-map. Consider the following example:- For a view that contains the following call:
form_input_field :person, :name, "Please input a name: "
, the controller contains eitherflash[:values] = params[:user][:name]
orflash[:values] = params[:user]
whenUser.new(params[:user][:name]).valid?
returns a false.
- For a view that contains the following call:
- Outputs two html tags - a label HTML element pointing to its corresponding input HTML element. The term "input HTML element" here is ambiguous; it's not meant to be taken literally. "Input" in this context is meant to be interpreted as any output produced by the following list of helper functions within
When using the value of :check_box
for helper_sym
, the argument set is as follows:
form_input_field(helper_sym, object_name, method, label_text = false, options = {}, label_options = {}, checked_value = "1", unchecked_value = "0", value_key = :values)
- The
checked_value
andunchecked_value
arguments correspond to the value sent to the server upon post, dependent whether or not the check box is checked. - The other arguments are unchanged from their descriptions above.
- The
When using the value of :radio_button
for helper_sym
, the argument set is as follows:
form_input_field(helper_sym, object_name, method, tag_value, label_text = false, options = {}, label_options = {}, value_key = :values)
- The
tag_value
argument corresponds to the value that will be sent to the server upon post, dependent whether or not the radio_button is selected. - The other arguments are unchanged from their descriptions above.
- The
form_error_field
is an abstraction on the software pattern which encapsulates the presentation of a validation error. This produces a label HTML element which points to the originating input field. The text of the label is the error message associated with the failed validation. These errors are typically captured from the model by the controller and then sent to the view where this method call is enacted.
form_error_field(object_name, method, label_options = {}, error_key = :errors)
- Outputs a label HTML tag whose textual value is located in the flash-hash map corresponding to
error_key
. If the value associated with said key is a string, then this string value will be used. If it is a hash-map, it will then assume that the value given formethod
is the key to the string within this embedded hash-map. Consider the following example:- For a view that contains the following call:
form_error_field :person, :name
, the controller contains eitherflash[:errors] = @user.errors[:name]
orflash[:errors] = @user.errors
, where@user
is defined byUser.new(params[:user][:name])
andUser.valid?
returns a false.
- For a view that contains the following call:
- The
label_options
argument corresponds to a hash-map representing the set of options to be passed with the call to the label helper function fromActionView::helpers::FormHelper
. Essentially a hash-map of html properties and attributes. I.e.,{:style => "color:red;"}
- Outputs a label HTML tag whose textual value is located in the flash-hash map corresponding to
form_input_field(:password_field, :user, :password, "Enter Password")
# => <label for="user_password">Enter Password</label><input type="password" name="user[password]" id="user_password" />
form_input_field(:password_field, :user, :password)
# => <input type="password" name="user[password]" id="user_password" />
form_input_field(:text_field, :login, :name, false, { :class => 'tag-class'})
# => <input class="tag-class" type="text" name="login[name]" id="login_name" />
form_input_field(:text_area, :applicant, :statement, label_text: "Tell us why you're interested:", options: { :class => 'form-input' }, label_options: { style: "font-weight:bold;color:grey;"})
# => <label style="font-weight:bold;color:grey;" for="applicant_statement">Tell us why you're interested:</label><textarea class="form-input" name="applicant[statement]" id="applicant_statement">n</textarea>
# The following three examples produce the same output:
form_input_field(:email_field, "user", "email", "Input Email", {:class => "form-control", :placeholder => "Your Email", :disabled => false}, {:class => "input-group-text"})
# => <label class="input-group-text" for="user_email">Input Email</label><input class="form-control" placeholder="Your Email" type="email" name="user[email]" id="user_email" />
form_input_field(:email_field, :user, :email, label_text: "Input Email", options: {:class => "form-control", :placeholder => "Your Email", :disabled => false}, label_options: {:class => "input-group-text"})
# => <label class="input-group-text" for="user_email">Input Email</label><input class="form-control" placeholder="Your Email" type="email" name="user[email]" id="user_email" />
form_input_field(:email_field, :user, :email, label_options: {:class => "input-group-text"}, options: {:class => "form-control", :placeholder => "Your Email", :disabled => false}, label_text: "Input Email")
# => <label class="input-group-text" for="user_email">Input Email</label><input class="form-control" placeholder="Your Email" type="email" name="user[email]" id="user_email" />"
#--- --- ---
form_input_field(:url_field, :user, :home_page)
# if flash[:values] contains {:home_page => "www.example.com"} OR if flash[:values] contains "www.example.com":
# => <input value="www.example.com" type="url" name="user[home_page]" id="user_home_page" />
form_input_field(:url_field, :user, :home_page, value_key: :info)
# if flash[:info] contains {:home_page => "www.example.com"} OR if flash[:info] contains "www.example.com":
# => <input value="www.example.com" type="url" name="user[home_page]" id="user_home_page" />
form_error_field(:user, :name)
# if flash[:errors] contains {:name => "Please input a valid name"} OR if flash[:errors] contains "Please input a valid name":
# => <label for="user_name">Please input a valid name</label>
form_error_field(:user, :name, { :class => "alert-danger"})
# if flash[:errors] contains {:name => "Please input a valid name"} OR if flash[:errors] contains "Please input a valid name":
# => <label class="alert-danger" for="user_name">Please input a valid name</label>
form_error_field(:user, :email, { style: "color:red;"}, :err_msg)
# if flash[:err_msg] contains {:email => "Please input a valid email"} OR if flash[:err_msg] contains "Please input a valid email":
# => <label style="color:red;" for="user_email">Please input a valid email</label>
After checking out the repo, run bin/setup
to install dependencies. Then, run rake spec
to run the tests. You can also run bin/console
for an interactive prompt that will allow you to experiment.
To install this gem onto your local machine, run bundle exec rake install
. To release a new version, update the version number in version.rb
, and then run bundle exec rake release
, which will create a git tag for the version, push git commits and tags, and push the .gem
file to rubygems.org.
- Base definition of
form_input_field
such that its optional keyword arguments can be supplied in any order. - Base definition of
form_error_field
such that its optional keyword arguments can be supplied in any order.
- A mechanism to set key defaults.
- Extend these helpers to be compatible with
ActionView::Helpers::FormBuilder
. - Create function wrappers specific to the required
ActionView::Helpers::FormHelper
method. I.e.,form_text_field(:model, :object_name)
which callsform_input_field(:text_field, :model, :object_name)
Other avenues of future work will be listed in the issues section of the repository.
Bug reports and pull requests are welcome on GitHub at https://github.com/alanmmckay/form_input_field.
Taken from rubygems.org pattern guide on semantic versioning. Semantic versioning boils down to:
- PATCH 0.0.x level changes for implementation level detail changes, such as small bug fixes
- MINOR 0.x.0 level changes for any backwards compatible API changes, such as new functionality/features
- MAJOR x.0.0 level changes for backwards incompatible API changes, such as changes that will break existing users code if they update
The gem is available as open source under the terms of the MIT License.