- Loosen
representabledependency to< 4.
- Loosen
disposabledependency to>= 0.5.0.
- Support ruby-3 by using
Representable::Optionto handlekeyword_argumentsforwarding 🎉 - Upgrade
representableanddisposabledependencies which usestrailblazer-optionoverdeclarative-option. - Deprecate populator's callable signature which accepts
formas 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
contractinstead 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
nilfield values,sync {}and dry-validation. - Fix boolean coercion.
- Allow using
:populatorclasses marked withUber::Callable. - Introduce
parse: falseas 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::Schemaclass 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::FormwithSchemawhich won't coerce values where it shouldn't. - [private]
Group#callAPI now is:call(form, errors). - Modify
Form#valid?- simply callsvalidate({}). - In
:iffor 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-schemaanymore or better the same result is reached using therulemethod: 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-vso 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
callas a populator, no need toinclude Uber::Callableanymore. This is because we have only three types and don't need ais_a?orrespond_to?check. - Use
declarative-optionand loosenuberdependency.
- Add
Form#callas an alias forvalidateand theResultobject.
- Loosen
uberdependency.
- Fix
Contract::Properties. Thanks @simonc. <3
- Remove
reform/rails. This is now handled via thereform-railsgem 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: trueoption.
####### TODO: fix Module and coercion Types::*
You should be able to upgrade from 2.0 without any code changes.
- You can now have
:populatorfor scalar properties, too. This allows "parsing code" per property which is super helpful to structure your deserialization. :populatorcan 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::Validatorprevents Rails from adding methods to it. This makesacceptanceandconfirmationvalidations work properly.
- Please be warned that we will drop support for
ActiveModel::Validationsfrom 2.2 onwards. Don't worry, it will still work, but we don't want to work with it anymore.
ActiveModel::Validatornow delegates all methods properly to the form. It used to crashed with properties calledformator other privateObjectmethods.- Simpleform will now properly display fields as required, or not (by introducion
ModelReflections::validators_on). - The
:defaultoption is not copied into the deserializer anymore from the schema. This requires disposable 0.1.11.
#syncand#savewith block now provideHashWithIndifferentAccessin 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#validateto give the form as less public API as possible and minimize misunderstandings.The idea is that you set up the object graph before/while
#validateand then invoke the validators once. -
Fixed AM to find proper i18n for error messages. This happens by injecting the form's
model_nameinto theValidatorobject in ActiveModel.
- Fix
unique: truevalidation in combination withComposition. - Use newest Disposable 0.1.9 which does not set
:pass_optionsanymore.
- Fix
ActiveModel::Validationswhere translations in custom validations would error. This is now handled by delegating back to theValidatorobject in Reform.
-
The
::reform_2_0!is no longer there. Guess why. -
Again:
:emptydoesn't exist anymore. You can choose from:readable,:writeableand:virtual. -
When using
:populatorthe 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..
-
:asoption removed. Use:from. -
With
Compositionincluded,Form#modelwould give you a composition object. You can grab that usingForm#mappernow. -
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::Validationsanymore. This has polluted the entire gem and is not encapsulated inValidator. Consider using Lotus Validations instead. -
Validation inheritance with
ActiveModel::Validationsis broken with Rails 3.2 and 4.0. Update Rails or use theLotusvalidations.
- Fix an annoying bug coming from Rails autoloader with validations and
model_name.
- Added
:prepopulateto 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_forto 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
ModelReflectionswork with simple_form 3.1.0. (#176). It also providesdefined_enumsand::reflect_on_associationnow. -
nilvalues passed into#validatewill 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
uberto 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
rescueblock inForm#validate.
- Fixed a nasty bug where
ActiveModelforms 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_attributeand other methods need by form builders to automatically guess the type of a property. -
Form#saveno longer passedselfto the block. You've been warned long enough. ;)
- Renamed
:asto:fromto be in line with Representable/Roar, Disposable and Cells. Thanks to @bethesque for pushing this. :emptyis now:virtualand:virtualiswriteable: false. It was too confusing and sucked. Thanks to @bethesque, again, for her moral assistance.Form#savewithCompositionnow returns true only if all composite models saved.Form::copy_validations_fromallows 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_blankas a macro to ignore a nested form if all values are blank. -
You can now specify validations right in the
::propertycall.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
#syncand#savecan 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
:baseerrors 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#validatemethod now expects a JSON string and will deserialize and populate the form from the JSON document. -
Added
Form::schemato generate a pure representer from the form's representer. -
Added
:readableand:writeableoption 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
::propertieswhich modified the options hash while iterating properties. Form#savenow returns the result of themodel.saveinvocation.- 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_sis 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.saveso there's no need to pass it into the block. #validatedoes not touch any model anymore. Both single values and collections are written to the model after#syncor#save.- Coercion now happens in
#validate, only. - You can now define forms in modules including
Reform::Form::Moduleto improve reusability. - Inheriting from forms and then overriding/extending properties with
:inheritnow works properly. - You can now define methods in inline forms.
- Added
Form::ActiveModel::ModelValidationsto 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)
endThis setter will only be called in #validate.
Readers still work the same, meaning that
def title
super.downcase
endwill 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
fieldswhen 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: trueto any property, the warnings will be suppressed and everything's gonna work. You may removepresentation_accessors: truein 1.1, but it won't affect the form.However, if you used to override
#titleor#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_processorand:sync_processorin order to filter data when calling#validateand when syncing data back to the model with#syncor#save.
-
Deprecated model readers for
CompositionandActiveModel. Consider the following setup.class RecordingForm < Reform::Form include Composition property :title, on: :song end
Before, Reform would allow you to do
form.songwhich 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: trueto 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#hitwas created. This is deprecated asThis is gonna be removed in 1.1.
- Removed
Form::DSLin 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.
savegets called on all nested forms automatically, disable withsave: false.- Renaming with
as:now works everywhere. - Fixes to make
Compositionwork everywhere. - Extract setup and validate into
Contract. - Automatic population with
:populate_if_emptyin#validate. - Remove
#from_hashand#to_hash. - Introduce
#syncand make#saveless 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::FormtheHitFormclass will containSongForm's properties in addition to its own fields. ::modelis now inherited properly.- Allow instantiation of nested form with emtpy nested properties.
- Accessors for properties (e.g.
titleandtitle=) 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
ActiveModelqueries the class name to compute translation keys. If you're not happy with it, use::model.
#form_fornow 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 .. endwould callmodel.saveeven 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). #validatedoesn't blow up anymore when input data is missing for a nested property or collection.- Allow
form: SongFormto specify an explicit form class instead of using an inline form for nested properties.
ActiveRecord::i18n_scopenow returnsactiverecord.Form#savenow calls save on the model inActiveRecordcontext.Form#modelis public now.- Introduce
:emptyto have empty fields that are accessible for validation and processing, only. - Introduce
:virtualfor read-only fields the are like:emptybut initially read from the decorated model. - Fix uniqueness validation with
Compositionform. - Move
setupandsavelogic into respective representer classes. This might break your code in case you overwrite private reform classes.
- Added nested property and collection for
has_oneandhas_manyrelationships. . Note that this currently works only 1-level deep. - Renamed
Reform::Form::DSLtoReform::Form::Compositionand 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.newnow 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::ActiveModelno longer creates accessors to your represented models, e.g. havingproperty :title, on: :songdoesn't allowform.songanymore. This is because the actual model and the form's state might differ, so please useform.titledirectly.
- Altered
reform/railsto conditionally loadActiveRecordcode and createdreform/active_record.
Form#to_modelis now delegated to model.- Coercion with virtus works.
- Added
reform/railsthat requires everything you need (even in other frameworks :). - Added
Form::ActiveRecordthat 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.