Reform: Options API
Last updated 05 May 2017 reform v2.2This document describes available options for Reform’s declarative API.
Disposable API
Every Reform form object inherits from Disposable::Twin
, making every form a twin and giving each form the entire twin API such as.
- Defaults using
:default
. - Coercion using
:type
and:nilify
. - Nesting
- Composition
- Hash fields
If you’re looking for a specific feature, make sure to check the Disposable documentation
Virtual Attributes
Virtual fields come in handy when there’s no direct mapping to a model attribute or when you plan on displaying but not processing a value.
Virtual
Often, fields like password_confirmation
should neither be read from nor written back to the model. Reform comes with the :virtual
option to handle that case.
class PasswordForm < Reform::Form
property :password
property :password_confirmation, virtual: true
Here, the model won’t be queried for a password_confirmation
field when creating and rendering the form. When saving the form, the input value is not written to the decorated model. It is only readable in validations and when saving the form manually.
form.validate("password" => "123", "password_confirmation" => "321")
form.password_confirmation #=> "321"
The nested hash in the block-#save
provides the same value.
form.save do |nested|
nested[:password_confirmation] #=> "321"
Read-Only
Use writeable: false
to display a value but skip processing it in validate
.
property :country, writeable: false
- The form will invoke
model.country
to read the initial value. - It will invoke
form.country=
invalidate
. - The model’s setter
model.country
won’t be called insync
.
Non-writeable values are still readable in the nested hash and through the form itself.
form.save do |nested|
nested[:country] #=> "Australia"
Write-Only
Use readable: false
to hide a value but still write it to the model.
property :credit_card_number, readable: false
- The form won’t invoke
model.credit_card_number
and will display an empty field. - In
validate
, the form callsform.credit_card_number=
. - In
sync
, the settermodel.credit_card_number=
is called and the value written to the database.
Access Protection
Use parse: false
to protect the form setters from being called in validate
.
property :uuid, parse: false
- This will call
model.uuid
to display the field via the form. - In
validate
, the form’s setter won’t be called, leaving the value as it is. - In
sync
, the settermodel.uuid
is called and restored to the original value.
Note that the :parse
option works by leveraging :deserializer.
Coercion
Incoming form data often needs conversion to a specific type, like timestamps. Reform uses dry-types for coercion. The DSL is seamlessly integrated with the :type
option.
Be sure to add dry-types
to your Gemfile
when requiring coercion.
gem "dry-types"
To use coercion, you need to include the Coercion
module into your form class.
require "reform/form/coercion"
class SongForm < Reform::Form
feature Coercion
property :written_at, type: Types::Form::DateTime
end
form.validate("written_at" => "26 September")
Coercion only happens in #validate
, not during construction.
form.written_at #=> <DateTime "2014 September 26 00:00">
Available coercion types are documented here.
Manual Coercion
To filter values manually, you can override the setter in the form.
class SongForm < Reform::Form
property :title
def title=(value)
super sanitize(value) # value is raw form input.
end
end
Again, setters are only called in validate
, not during construction.
Deserializer
A form object is just a twin. In validate
, a representer is used to deserialize the incoming hash and populate the form twin graph. This means, you can use any representer you like and process data like JSON or XML, too.
Populator
When deserializing the incoming input in validate
, advanced logic might be necessary to find nested objects from the database, or populate the form with arbitrary nested objects.
The :populator
and its short-hand :populate_if_empty
options provide custom deserialization logic and are documented here.
Inheritance
Forms can be derived from other forms and will inherit all properties and validations.
class AlbumForm < Reform::Form
property :title
collection :songs do
property :title
validates :title, presence: true
end
end
Now, a simple inheritance can add fields.
class CompilationForm < AlbumForm
property :composers do
property :name
end
end
This will add composers
to the existing fields.
You can also partially override fields using :inherit
.
class CompilationForm < AlbumForm
property :songs, inherit: true do
property :band_id
validates :band_id, presence: true
end
end
Using inherit:
here will extend the existing songs
form with the band_id
field. Note that this simply uses representable’s inheritance mechanism.
Skip_if
Use :skip_if
to ignore properties in #validate
.
property :hit, skip_if: lambda { |fragment, *| fragment["title"].blank? }
This works for both properties and entire nested forms. The property will simply be ignored when deserializing, as if it had never been in the incoming hash/document.
For nested properties you can use :skip_if: :all_blank
as a macro to ignore a nested form if all values are blank.
Note that this still runs validations for the property.
Multiparameter Dates
Composed multi-parameter dates as created by the Rails date helper are processed automatically when multi_params: true
is set for the date property and the MultiParameterAttributes
feature is included. As soon as Reform detects an incoming release_date(i1)
or the like it is gonna be converted into a date.
class AlbumForm < Reform::Form
feature Reform::Form::ActiveModel::FormBuilderMethods
feature Reform::Form::MultiParameterAttributes
collection :songs do
feature Reform::Form::ActiveModel::FormBuilderMethods
property :title
property :release_date, :multi_params => true
validates :title, :presence => true
end
end
Note that the date will be nil
when one of the components (year/month/day) is missing.