- Loosen
representable
dependency to< 4
.
- Loosen
disposable
dependency to>= 0.5.0
.
- Support ruby-3 by using
Representable::Option
to handlekeyword_arguments
forwarding 🎉 - Upgrade
representable
anddisposable
dependencies which usestrailblazer-option
overdeclarative-option
. - Deprecate populator's callable signature which accepts
form
as a separate positional argument. Make all callable (proc, method,Uber::Callable
) signatures identical.
- fix memory leak with Dry validation (#525)
- [BREAKING] Dropping compatibility of dry-validation < 1.x
[* Removed
Reform::Contract
?] [* Move Form#deserializer to Form::deserializer]
- Rename validation option for dry-v 1+ to
contract
instead ofschema
- Fix Validation block option :form incorrectly memoized between tests
- With dry-validation 1.5 the form is always injected. Just add option :form to access it in the schema.
- Removed global monkey patching of Dry::Schema::DSL
- Tests in ruby 2.7
You can upgrade from 2.2.0 without worries.
- Require Representable 3.0.0 and removed Representable 2.4 deprecation code.
- Require Disposable 0.4.0 which fixes issues with
nil
field values,sync {}
and dry-validation. - Fix boolean coercion.
- Allow using
:populator
classes marked withUber::Callable
. - Introduce
parse: false
as a shortcut fordeserialzer: { writeable: false}
. Thanks to @pabloh for insisting on this handy change. - Memoize the deserializer instance on the class level via
::deserializer
. This saves the inferal of a deserializing representer and speeds up following calls by 130%. - Deprecated positional arguments for
validation :default, options: {}
. New API:validation name: :default, **
. - Reform now maintains a generic
Dry::Schema
class for global schema configuration. Can be overridden via::validation
. - When validating with dry-validation, we now pass a symbolized hash. We also replaced
Dry::Validation::Form
withSchema
which won't coerce values where it shouldn't. - [private]
Group#call
API now is:call(form, errors)
. - Modify
Form#valid?
- simply callsvalidate({})
. - In
:if
for validation groups, you now get a hash of result objects, not just true/false. - Allow adding a custom error AFTER validate has been already called
Compatibility with dry-validation
with 1.x:
- [CHANGE] seems like "custom" predicate are not supported by
dry-schema
anymore or better the same result is reached using therule
method: Something like this:will be something like:validation do def a_song?(value) value == :really_cool_song end required(:songs).filled(:a_song?) end
validation do required(:songs).filled rule(:songs) do key.failure(:a_song?) unless value == :really_cool_song end end
- [BREAKING] inheriting/merging/overriding schema/rules is not supported by
dry-v
so theinherit:
option is NOT SUPPORTED for now. Also extend aschema:
option using a block is NOT SUPPORTED for now. Possible workaround is to use reform module to compose different validations but this won't override existing validations but just merge them
- You can now use any object with
call
as a populator, no need toinclude Uber::Callable
anymore. This is because we have only three types and don't need ais_a?
orrespond_to?
check. - Use
declarative-option
and loosenuber
dependency.
- Add
Form#call
as an alias forvalidate
and theResult
object.
- Loosen
uber
dependency.
- Fix
Contract::Properties
. Thanks @simonc. <3
- Remove
reform/rails
. This is now handled via thereform-rails
gem which you have to bundle. - For coercion, we now use dry-types as a replacement for the deprecated virtus. You have to change to dry-types' constants, e.g.
type: Types::Form::Bool
. - Use disposable 0.3.0. This gives us the long-awaited
nilify: true
option.
####### TODO: fix Module and coercion Types::*
You should be able to upgrade from 2.0 without any code changes.
- You can now have
:populator
for scalar properties, too. This allows "parsing code" per property which is super helpful to structure your deserialization. :populator
can be a method name, as inpopulator: :populate_authors!
.- Populators can now skip deserialization of a nested fragment using
skip!
. Learn more here. - Added support for dry-validation as a future replacement for ActiveModel::Validation. Note that this is still experimental, but works great.
- Added validation groups.
- All lambda APIs change (with deprecation):
populator: ->(options)
or->(fragment:, model:, **o)
where we only receive one hash instead of a varying number or arguments. This is pretty cool and should be listed under Awesomeness. ActiveModel::Validator
prevents Rails from adding methods to it. This makesacceptance
andconfirmation
validations work properly.
- Please be warned that we will drop support for
ActiveModel::Validations
from 2.2 onwards. Don't worry, it will still work, but we don't want to work with it anymore.
ActiveModel::Validator
now delegates all methods properly to the form. It used to crashed with properties calledformat
or other privateObject
methods.- Simpleform will now properly display fields as required, or not (by introducion
ModelReflections::validators_on
). - The
:default
option is not copied into the deserializer anymore from the schema. This requires disposable 0.1.11.
#sync
and#save
with block now provideHashWithIndifferentAccess
in Rails.
-
Form#valid?
is private now. Sorry for the inconvenience, but this has never been documented as public. Reason is that the only entry point for validation is#validate
to give the form as less public API as possible and minimize misunderstandings.The idea is that you set up the object graph before/while
#validate
and then invoke the validators once. -
Fixed AM to find proper i18n for error messages. This happens by injecting the form's
model_name
into theValidator
object in ActiveModel.
- Fix
unique: true
validation in combination withComposition
. - Use newest Disposable 0.1.9 which does not set
:pass_options
anymore.
- Fix
ActiveModel::Validations
where translations in custom validations would error. This is now handled by delegating back to theValidator
object in Reform.
-
The
::reform_2_0!
is no longer there. Guess why. -
Again:
:empty
doesn't exist anymore. You can choose from:readable
,:writeable
and:virtual
. -
When using
:populator
the API to work against the form has changed.populator: lambda { |fragment, index, args| songs[index] or songs[index] = args.binding[:form].new(Song.new) }
is now
populator: lambda { |fragment, index, args| songs[index] or songs.insert(index) = Song.new }
You don't need to know about forms anymore, the twin handles that using the Twin API..
-
:as
option removed. Use:from
. -
With
Composition
included,Form#model
would give you a composition object. You can grab that usingForm#mapper
now. -
Form#update!
is deprecated. It still works but will remind you to override#present!
or use pre-populators as described here and in the Trailblazer book, chapter "Nested Forms". -
Forms do not
include ActiveModel::Validations
anymore. This has polluted the entire gem and is not encapsulated inValidator
. Consider using Lotus Validations instead. -
Validation inheritance with
ActiveModel::Validations
is broken with Rails 3.2 and 4.0. Update Rails or use theLotus
validations.
- Fix an annoying bug coming from Rails autoloader with validations and
model_name
.
- Added
:prepopulate
to fill out form properties for presentation. Note that you need to callForm#prepopulate!
to trigger the prepopulation. - Added support for DateTime properties in forms. Until now, we were ignoring the time part. Thanks to @gdott9 for fixing this.
- Added
Form#options_for
to have access to all property options.
-
Added
Form#readonly?
to find out whether a field is set to writeable. This is helpful for simple_form to display a disabled input field.property :title, writeable: false
In the view, you can then use something along the following code.
f.input :title, readonly: @form.readonly?(:title)
-
Make
ModelReflections
work with simple_form 3.1.0. (#176). It also providesdefined_enums
and::reflect_on_association
now. -
nil
values passed into#validate
will now be written to the model in#sync
(#175). Formerly, only blank strings and values evaluating to true were considered when syncing. This allows blanking fields of the model as follows.form.validate(title: nil)
-
Calling
Form::reform_2_0!
will now properly inherit to nested forms.
- Use new
uber
to allow subclassingreform_2_0!
forms. - Raise a better understandable deserialization error when the form is not populated properly. This error is so common that I overcame myself to add a dreaded
rescue
block inForm#validate
.
- Fixed a nasty bug where
ActiveModel
forms with form builder support wouldn't deserialize properly. A million Thanks to @karolsarnacki for finding this and providing an exemplary failing test. <3
-
Due to countless bugs we no longer include support for simple_form's type interrogation automatically. This allows using forms with non-AM objects. If you want full support for simple_form do as follows.
class SongForm < Reform::Form include ModelReflections
Including this module will add
#column_for_attribute
and other methods need by form builders to automatically guess the type of a property. -
Form#save
no longer passedself
to the block. You've been warned long enough. ;)
- Renamed
:as
to:from
to be in line with Representable/Roar, Disposable and Cells. Thanks to @bethesque for pushing this. :empty
is now:virtual
and:virtual
iswriteable: false
. It was too confusing and sucked. Thanks to @bethesque, again, for her moral assistance.Form#save
withComposition
now returns true only if all composite models saved.Form::copy_validations_from
allows copying custom validators now.- New call style for
::properties
. Instead of an array, it's nowproperties :title, :genre
. - All options are evaluated with
pass_options: true
. - All transforming representers are now created and stored on class level, resulting in simpler code and a 85% speed-up.
-
In
#validate
, you can ignore properties now using:skip_if
.property :hit, skip_if: lambda { |fragment, *| fragment["title"].blank? }
This works for both properties and 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. -
You can now specify validations right in the
::property
call.property :title, validates: {presence: true}
Thanks to @zubin for this brillant idea!
-
Reform now tracks which attributes have changed after
#validate
. You can check that usingform.changed?(:title)
. -
When including
Sync::SkipUnchanged
, the form won't try to assign unchanged values anymore in#sync
. This is extremely helpful when handling file uploads and the like. -
Both
#sync
and#save
can be configured dynamically now.When syncing, you can run a lambda per property.
property :title, sync: lambda { |value, options| model.set_title(value) }
This won't run Reform's built-in sync for this property.
You can also provide the sync lambda at run-time.
form.sync(title: lambda { |value, options| form.model.title = "HOT: #{value}" })
This block is run in the caller's context allowing you to access environment variables.
Note that the dynamic sync happens before save, so the model id may unavailable.
You can do the same for saving.
form.save(title: lambda { |value, options| form.model.title = "#{form.model.id} --> #{value}" })
Again, this block is run in the caller's context.
The two features are an excellent way to handle file uploads without ActiveRecord's horrible callbacks.
-
Adding generic
:base
errors now works. Thanks to @bethesque.errors.add(:base, "You are too awesome!")
This will prefix the error with
:base
. -
Need your form to parse JSON? Include
Reform::Form::JSON
, the#validate
method now expects a JSON string and will deserialize and populate the form from the JSON document. -
Added
Form::schema
to generate a pure representer from the form's representer. -
Added
:readable
and:writeable
option which allow to skip reading or writing to the model whenfalse
.
- Fix a bug where including a form module would mess up the options has of the validations (under older Rails).
- Fix
::properties
which modified the options hash while iterating properties. Form#save
now returns the result of themodel.save
invocation.- Fix: When overriding a reader method for a nested form for presentation (e.g. to provide an initial new record), this reader was used in
#update!
. The deserialize/update run now grabs the actual nested form instances directly fromfields
. Errors#to_s
is now delegated tomessages.to_s
. This is used inTrailblazer::Operation
.
- Deprecate first block argument in save. It's new signature is
save { |hash| }
. You already got the form instance when callingform.save
so there's no need to pass it into the block. #validate
does not touch any model anymore. Both single values and collections are written to the model after#sync
or#save
.- Coercion now happens in
#validate
, only. - You can now define forms in modules including
Reform::Form::Module
to improve reusability. - Inheriting from forms and then overriding/extending properties with
:inherit
now works properly. - You can now define methods in inline forms.
- Added
Form::ActiveModel::ModelValidations
to copy validations from model classes. Thanks to @cameron-martin for this fine addition. - Forms can now also deserialize other formats, e.g. JSON. This allows them to be used as a contract for API endpoints and in Operations in Trailblazer.
- Composition forms no longer expose readers to the composition members. The composition is available via
Form#model
, members viaForm#model[:member_name]
. - ActiveRecord support is now included correctly and passed on to nested forms.
- Undocumented/Experimental: Scalar forms. This is still WIP.
Reverting what I did in 1.0.3. Leave your code as it is. You may override a writers like #title=
to sanitize or filter incoming data, as in
def title=(v)
super(v.strip)
end
This setter will only be called in #validate
.
Readers still work the same, meaning that
def title
super.downcase
end
will result in lowercased title when rendering the form (and only then).
The reason for this confusion is that you don't blog enough about Reform. Only after introducing all those deprecation warnings, people started to contact me to ask what's going on. This gave me the feedback I needed to decide what's the best way for filtering incoming data.
- Systematically use
fields
when saving the form. This avoids calling presentational readers that might have been defined by the user.
-
The following property names are reserved and will raise an exception:
[:model, :aliased_model, :fields, :mapper]
-
You get warned now when overriding accessors for your properties:
property :title def title super.upcase end
This is because in Reform 1.1, those accessors will only be used when rendering the form, e.g. when doing
= @form.title
. If you override the accessors for presentation, only, you're fine. Addpresentation_accessors: true
to any property, the warnings will be suppressed and everything's gonna work. You may removepresentation_accessors: true
in 1.1, but it won't affect the form.However, if you used to override
#title
or#title=
to manipulate incoming data, this is no longer working in 1.1. The reason for this is to make Reform cleaner. You will get two options:validate_processor
and:sync_processor
in order to filter data when calling#validate
and when syncing data back to the model with#sync
or#save
.
-
Deprecated model readers for
Composition
andActiveModel
. Consider the following setup.class RecordingForm < Reform::Form include Composition property :title, on: :song end
Before, Reform would allow you to do
form.song
which returned the song model. You can still do this (but you shouldn't) withform.model[:song]
.This allows having composed models and properties with the same name. Until 1.1, you have to use
skip_accessors: true
to advise Reform not to create the deprecated accessor.Also deprecated is the alias accessor as found with
ActiveModel
.class RecordingForm < Reform::Form include Composition include ActiveModel model :hit, on: :song end
Here, an automatic reader
Form#hit
was created. This is deprecated asThis is gonna be removed in 1.1.
- Removed
Form::DSL
in favour ofForm::Composition
. - Simplified nested forms. You can now do
validates :songs, :length => {:minimum => 1} validates :hit, :presence => true
- Allow passing symbol hash keys into
#validate
. - Unlimited nesting of forms, if you really want that.
save
gets called on all nested forms automatically, disable withsave: false
.- Renaming with
as:
now works everywhere. - Fixes to make
Composition
work everywhere. - Extract setup and validate into
Contract
. - Automatic population with
:populate_if_empty
in#validate
. - Remove
#from_hash
and#to_hash
. - Introduce
#sync
and make#save
less smart.
- Last release supporting Representable 1.7.
- In ActiveModel/ActiveRecord: The model name is now correctly infered even if the name is something like
Song::Form
.
- Maintenance release cause I'm stupid.
- Allow proper form inheritance. When having
HitForm < SongForm < Reform::Form
theHitForm
class will containSongForm
's properties in addition to its own fields. ::model
is now inherited properly.- Allow instantiation of nested form with emtpy nested properties.
- Accessors for properties (e.g.
title
andtitle=
) can now be overridden in the form and callsuper
. This is extremely helpful if you wanna do "manual coercion" since the accessors are invoked in#validate
. Thanks to @cj for requesting this. - Inline forms now know their class name from the property that defines them. This is needed for I18N where
ActiveModel
queries the class name to compute translation keys. If you're not happy with it, use::model
.
#form_for
now properly recognizes a nested form when declared using:form
(instead of an inline form).- Multiparameter dates as they're constructed from the Rails date helper are now processed automatically. As soon as an incoming attribute name is
property_name(1i)
or the like, it's compiled into a Date. That happens inMultiParameterAttributes
. If a component (year/month/day) is missing, the date is considerednil
.
- Fix a bug where
form.save do .. end
would callmodel.save
even though a block was given. This no longer happens, if there's a block to#save
, you have to manually save data (ActiveRecord environment, only). #validate
doesn't blow up anymore when input data is missing for a nested property or collection.- Allow
form: SongForm
to specify an explicit form class instead of using an inline form for nested properties.
ActiveRecord::i18n_scope
now returnsactiverecord
.Form#save
now calls save on the model inActiveRecord
context.Form#model
is public now.- Introduce
:empty
to have empty fields that are accessible for validation and processing, only. - Introduce
:virtual
for read-only fields the are like:empty
but initially read from the decorated model. - Fix uniqueness validation with
Composition
form. - Move
setup
andsave
logic into respective representer classes. This might break your code in case you overwrite private reform classes.
- Added nested property and collection for
has_one
andhas_many
relationships. . Note that this currently works only 1-level deep. - Renamed
Reform::Form::DSL
toReform::Form::Composition
and deprecatedDSL
. require 'reform'
now automatically requires Rails stuff in a Rails environment. Mainly, this is the FormBuilder compatibility layer that is injected intoForm
. If you don't want that, only require 'reform/form'.- Composition now totally optional
Form.new
now accepts one argument, only: the model/composition. If you want to create your own representer, inject it by overridingForm#mapper
. Note that this won't create property accessors for you.Form::ActiveModel
no longer creates accessors to your represented models, e.g. havingproperty :title, on: :song
doesn't allowform.song
anymore. This is because the actual model and the form's state might differ, so please useform.title
directly.
- Altered
reform/rails
to conditionally loadActiveRecord
code and createdreform/active_record
.
Form#to_model
is now delegated to model.- Coercion with virtus works.
- Added
reform/rails
that requires everything you need (even in other frameworks :). - Added
Form::ActiveRecord
that gives youvalidates_uniqueness_with
. Note that this is strongly coupled to your database, thou. - Merged a lot of cleanups from sweet @parndt <3.
- Oh yeah.