reform 2.1.0 → 2.2.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (89) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +0 -1
  3. data/.travis.yml +4 -12
  4. data/CHANGES.md +8 -0
  5. data/README.md +36 -743
  6. data/Rakefile +1 -31
  7. data/gemfiles/{Gemfile.rails-3.1 → Gemfile.disposable-0.3} +1 -2
  8. data/lib/reform.rb +0 -9
  9. data/lib/reform/contract.rb +5 -1
  10. data/lib/reform/form.rb +1 -4
  11. data/lib/reform/form/composition.rb +1 -2
  12. data/lib/reform/form/dry.rb +29 -16
  13. data/lib/reform/form/module.rb +15 -3
  14. data/lib/reform/form/validate.rb +1 -1
  15. data/lib/reform/validation.rb +3 -3
  16. data/lib/reform/version.rb +1 -1
  17. data/reform.gemspec +3 -10
  18. data/test/coercion_test.rb +7 -7
  19. data/test/composition_test.rb +5 -1
  20. data/test/contract_test.rb +10 -4
  21. data/test/deserialize_test.rb +3 -3
  22. data/test/errors_test.rb +48 -28
  23. data/test/form_option_test.rb +3 -1
  24. data/test/form_test.rb +19 -14
  25. data/test/module_test.rb +51 -11
  26. data/test/populate_test.rb +21 -7
  27. data/test/reform_test.rb +24 -20
  28. data/test/save_test.rb +10 -4
  29. data/test/skip_if_test.rb +5 -3
  30. data/test/test_helper.rb +3 -43
  31. data/test/validate_test.rb +34 -14
  32. data/test/validation/dry_test.rb +60 -0
  33. data/test/validation/dry_validation_test.rb +65 -43
  34. data/test/validation/errors.yml +4 -0
  35. metadata +16 -192
  36. data/database.sqlite3 +0 -0
  37. data/gemfiles/Gemfile.rails-3.2 +0 -7
  38. data/gemfiles/Gemfile.rails-4.0 +0 -8
  39. data/gemfiles/Gemfile.rails-4.1 +0 -8
  40. data/gemfiles/Gemfile.rails-4.2 +0 -8
  41. data/lib/reform/active_record.rb +0 -4
  42. data/lib/reform/form/active_model.rb +0 -87
  43. data/lib/reform/form/active_model/form_builder_methods.rb +0 -48
  44. data/lib/reform/form/active_model/model_reflections.rb +0 -46
  45. data/lib/reform/form/active_model/model_validations.rb +0 -110
  46. data/lib/reform/form/active_model/validations.rb +0 -107
  47. data/lib/reform/form/active_record.rb +0 -30
  48. data/lib/reform/form/lotus.rb +0 -59
  49. data/lib/reform/form/multi_parameter_attributes.rb +0 -48
  50. data/lib/reform/form/validation/unique_validator.rb +0 -54
  51. data/lib/reform/rails.rb +0 -13
  52. data/test/active_model_custom_validation_translations_test.rb +0 -75
  53. data/test/active_model_test.rb +0 -207
  54. data/test/active_model_validation_for_property_named_format_test.rb +0 -18
  55. data/test/active_record_test.rb +0 -273
  56. data/test/builder_test.rb +0 -32
  57. data/test/custom_validation_test.rb +0 -47
  58. data/test/dummy/Rakefile +0 -7
  59. data/test/dummy/app/controllers/albums_controller.rb +0 -18
  60. data/test/dummy/app/controllers/application_controller.rb +0 -4
  61. data/test/dummy/app/controllers/musician_controller.rb +0 -5
  62. data/test/dummy/app/forms/album_form.rb +0 -18
  63. data/test/dummy/app/helpers/application_helper.rb +0 -2
  64. data/test/dummy/app/models/album.rb +0 -4
  65. data/test/dummy/app/models/song.rb +0 -3
  66. data/test/dummy/app/views/albums/new.html.erb +0 -28
  67. data/test/dummy/app/views/layouts/application.html.erb +0 -14
  68. data/test/dummy/config.ru +0 -4
  69. data/test/dummy/config/application.rb +0 -20
  70. data/test/dummy/config/boot.rb +0 -10
  71. data/test/dummy/config/database.yml +0 -22
  72. data/test/dummy/config/environment.rb +0 -5
  73. data/test/dummy/config/environments/development.rb +0 -16
  74. data/test/dummy/config/environments/production.rb +0 -46
  75. data/test/dummy/config/environments/test.rb +0 -33
  76. data/test/dummy/config/locales/en.yml +0 -14
  77. data/test/dummy/config/routes.rb +0 -4
  78. data/test/dummy/db/test.sqlite3 +0 -0
  79. data/test/form_builder_test.rb +0 -138
  80. data/test/lotus/Gemfile +0 -5
  81. data/test/lotus/lotus_test.rb +0 -31
  82. data/test/lotus_test.rb +0 -150
  83. data/test/model_reflections_test.rb +0 -138
  84. data/test/model_validations_test.rb +0 -82
  85. data/test/mongoid_test.rb +0 -313
  86. data/test/multi_parameter_attributes_test.rb +0 -50
  87. data/test/rails/integration_test.rb +0 -54
  88. data/test/unique_test.rb +0 -135
  89. data/test/validation/activemodel_validation_test.rb +0 -252
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 22e0b3849f8a705c51f5e805dfaca960279b8d3d
4
- data.tar.gz: 1fa928b3309dcca60a1c5801a58acca34d7996ee
3
+ metadata.gz: 1b2a5be877cbaaa043ad0bfbcd2653da257699de
4
+ data.tar.gz: f1a4041fe62f7a7f5206953d587d7d4318464499
5
5
  SHA512:
6
- metadata.gz: 5daaf2a361ee1a200b7d300f926ff6e4acf7503d73b5b3dcde106201d9b6bcf8a015ba4472ba5496a67af48af7be7bd4879d6afa6ed2cee649ec776ec437afea
7
- data.tar.gz: 1adf91b4dfd4de9e14871b7f56953cd83ce765d6d1576858314ba4416f9c15c0d9eaad57b26b450345c8d4420ffd3ff524b67df210665d9f4268f4484a9b8894
6
+ metadata.gz: 97ef0aa8b71924a2500eebc80640621f0c54da292f438ded3ede85fd026f9f877008e99563253918157e221681e555c7144d65bf332c036c3a031bde526eaf07
7
+ data.tar.gz: 57b827c389e08eea790c146dfac6a1bc14f6e5f24e654d15aace5f7f07a674227ff5b9d4b1eb3051be15c99790e4937ffa05796aa4e56d223d7913087b8552e7
data/.gitignore CHANGED
@@ -16,4 +16,3 @@ spec/reports
16
16
  test/tmp
17
17
  test/version_tmp
18
18
  tmp
19
- test/dummy/log/*.log
@@ -1,19 +1,11 @@
1
1
  language: ruby
2
2
  rvm:
3
3
  - 2.2.3
4
- - 1.9.3
5
- services:
6
- - mongodb
4
+ - 2.0.0
7
5
  gemfile:
8
- - gemfiles/Gemfile.rails-4.2
9
- - gemfiles/Gemfile.rails-4.1
10
- - gemfiles/Gemfile.rails-4.0
11
- - gemfiles/Gemfile.rails-3.2
12
- - gemfiles/Gemfile.rails-3.1
13
- # - gemfiles/Gemfile.rails-3.0
6
+ - gemfiles/Gemfile.disposable-0.3
7
+
14
8
  matrix:
15
9
  fast_finish: true
16
- allow_failures:
17
- - rvm: 1.9.3
18
10
  before_install:
19
- - gem install bundler
11
+ - gem install bundler
data/CHANGES.md CHANGED
@@ -1,3 +1,11 @@
1
+ ## 2.2.0
2
+
3
+ * Remove `reform/rails`. This is now handled via the `reform-rails` gem which you have to bundle.
4
+ * For coercion, we now use [dry-types](https://github.com/dry-rb/dry-types) as a replacement for the deprecated virtus. You have to change to dry-types' constants, e.g. `type: Types::Form::Bool`.
5
+ * Use disposable 0.3.0. This gives us the long-awaited `nilify: true` option.
6
+
7
+ ####### TODO: fix Module and coercion Types::*
8
+
1
9
  ## 2.1.0
2
10
 
3
11
  You should be able to upgrade from 2.0 without any code changes.
data/README.md CHANGED
@@ -1,6 +1,7 @@
1
1
  # Reform
2
2
 
3
3
  [![Gitter Chat](https://badges.gitter.im/trailblazer/chat.svg)](https://gitter.im/trailblazer/chat)
4
+ [![TRB Newsletter](https://img.shields.io/badge/TRB-newsletter-lightgrey.svg)](http://trailblazer.to/newsletter/)
4
5
  [![Build
5
6
  Status](https://travis-ci.org/apotonick/reform.svg)](https://travis-ci.org/apotonick/reform)
6
7
  [![Gem Version](https://badge.fury.io/rb/reform.svg)](http://badge.fury.io/rb/reform)
@@ -11,17 +12,13 @@ Reform gives you a form object with validations and nested setup of models. It i
11
12
 
12
13
  Although reform can be used in any Ruby framework, it comes with [Rails support](#rails-integration), works with [simple_form and other form gems](#formbuilder-support), allows nesting forms to implement [has_one](#nesting-forms-1-1-relations) and [has_many](#nesting-forms-1-n-relations) relationships, can [compose a form](#compositions) from multiple objects and gives you [coercion](#coercion).
13
14
 
14
- ## This is not Reform 1.x!
15
+ ## Full Documentation
15
16
 
16
- Temporary note: This is the README and API for Reform 2. On the public API, only a few tiny things have changed. Here are the [Reform 1.2 docs](https://github.com/apotonick/reform/blob/v1.2.6/README.md).
17
+ Reform is part of the [Trailblazer](http://trailblazer.to) framework. [Full documentation](http://trailblazer.to/gems/reform) is available on the project site.
17
18
 
18
- Anyway, please upgrade and _report problems_ and do not simply assume that we will magically find out what needs to get fixed. When in trouble, join us on [Gitter](https://gitter.im/trailblazer/chat).
19
+ ## Reform 2.2
19
20
 
20
- [Full documentation for Reform](http://trailblazer.to/gems/reform) is available online, or support us and grab the [Trailblazer book](https://leanpub.com/trailblazer). There is an [Upgrading Guide](http://trailblazer.to/gems/reform/upgrading-guide.html) to help you migrate from Reform 1.x.
21
-
22
- ## Disposable
23
-
24
- Every form in Reform is a _twin_. Twins are non-persistent domain objects from the [Disposable gem](https://github.com/apotonick/disposable). All features of Disposable, like renaming fields, change tracking, etc. are available in Reform, too.
21
+ Temporary note: Reform 2.2 does **not automatically load Rails files** anymore (e.g. `ActiveModel::Validations`). You need the `reform-rails` gem, see [Installation](#installation).
25
22
 
26
23
  ## Defining Forms
27
24
 
@@ -131,6 +128,16 @@ This will sync the data to the model and then call `album.save`.
131
128
 
132
129
  Sometimes, you need to do saving manually.
133
130
 
131
+ ## Default values
132
+
133
+ Reform allows default values to be provided for properties.
134
+
135
+ ```ruby
136
+ class AlbumForm < Reform::Form
137
+ property :price_in_cents, default: 9_95
138
+ end
139
+ ```
140
+
134
141
  ## Saving Forms Manually
135
142
 
136
143
  Calling `#save` with a block will provide a nested hash of the form's properties and values. This does **not call `#save` on the models** and allows you to implement the saving yourself.
@@ -241,63 +248,29 @@ The block form of `#save` would give you the following data.
241
248
  The manual saving with block is not encouraged. You should rather check the Disposable docs to find out how to implement your manual tweak with the official API.
242
249
 
243
250
 
244
- ## Populating Forms for Validation
245
-
246
- This topic is thorougly covered in the [Trailblazer book](https://leanpub.com/trailblazer) in chapters _Nested Forms_ and _Mastering Forms_.
251
+ ## Populating Forms
247
252
 
248
- With a complex nested setup it can sometimes be painful to setup the model object graph.
249
-
250
- Let's assume you rendered the following form.
251
-
252
- ```ruby
253
- @form = AlbumForm.new(Album.new(songs: [Song.new, Song.new]))
254
- ```
255
-
256
- This will render two nested forms to create new songs.
257
-
258
- In `validate`, you're supposed to setup the very same object graph, again. Reform has no way of remembering what the object setup was like a request ago.
259
-
260
- So, the following code will fail.
261
-
262
- ```ruby
263
- @form = AlbumForm.new(Album.new).validate(params[:album])
264
- ```
265
-
266
- However, you can advise Reform to setup the correct objects for you.
267
-
268
- ```ruby
269
- class AlbumForm < Reform::Form
270
- collection :songs, populate_if_empty: Song do
271
- # ..
272
- end
273
- ```
253
+ Very often, you need to give Reform some information how to create or find nested objects when `validate`ing. This directive is called _populator_ and [documented here](http://trailblazer.to/gems/reform/populator.html).
274
254
 
275
- This works for both `property` and `collection` and instantiates `Song` objects where they're missing when calling `#validate`.
255
+ ## Installation
276
256
 
277
- If you want to create the objects yourself, because you're smarter than Reform, do it with a lambda.
257
+ Add this line to your Gemfile:
278
258
 
279
259
  ```ruby
280
- class AlbumForm < Reform::Form
281
- collection :songs, populate_if_empty: lambda { |fragment, args| Song.new } do
282
- # ..
283
- end
260
+ gem "reform"
284
261
  ```
285
262
 
286
- Reform also allows to completely override population using the `:populator` options. This is [documented here](http://trailblazer.to/gems/reform/populators.html), and also in the Trailblazer book.
287
-
288
- ## Installation
263
+ Reform works fine with Rails 3.1-5.0. However, inheritance of validations with `ActiveModel::Validations` is broken in Rails 3.2 and 4.0.
289
264
 
290
- Add this line to your Gemfile:
265
+ Since Reform 2.2, you have to add the `reform-rails` gem to your `Gemfile` to automatically load ActiveModel/Rails files.
291
266
 
292
267
  ```ruby
293
- gem 'reform'
268
+ gem "reform-rails"
294
269
  ```
295
270
 
296
- Reform works fine with Rails 3.1-4.2. However, inheritance of validations with `ActiveModel::Validations` is broken in Rails 3.2 and 4.0.
297
-
298
271
  Since Reform 2.0 you need to specify which **validation backend** you want to use (unless you're in a Rails environment where ActiveModel will be used).
299
272
 
300
- To use ActiveModel (not recommended as it doesn't support removing validations).
273
+ To use ActiveModel (not recommended because very out-dated).
301
274
 
302
275
  ```ruby
303
276
  require "reform/form/active_model/validations"
@@ -306,12 +279,12 @@ Reform::Form.class_eval do
306
279
  end
307
280
  ```
308
281
 
309
- To use Lotus validations (recommended).
282
+ To use dry-validation (recommended).
310
283
 
311
284
  ```ruby
312
- require "reform/form/lotus"
285
+ require "reform/form/dry"
313
286
  Reform::Form.class_eval do
314
- include Reform::Form::Lotus
287
+ feature Reform::Form::Dry
315
288
  end
316
289
  ```
317
290
 
@@ -338,708 +311,28 @@ When initializing a composition, you have to pass a hash that contains the compo
338
311
  AlbumForm.new(album: album, cd: CD.find(1))
339
312
  ```
340
313
 
341
- => rendering
342
- => sync with block
343
-
344
- ## Hash Fields
314
+ ## More
345
315
 
346
- Reform can also handle deeply nested hash fields from serialized hash columns. This is [documented here](https://github.com/apotonick/disposable#struct).
347
-
348
- => Example
316
+ Reform comes many more optional features, like hash fields, coercion, virtual fields, and so on. Check the [full documentation here](http://trailblazer.to/gems/reform).
349
317
 
350
318
  <a href="https://leanpub.com/trailblazer">
351
- ![](https://raw.githubusercontent.com/apotonick/trailblazer/master/doc/trb.jpg)
319
+ ![](http://trailblazer.to/images/3dbuch-freigestellt.png)
352
320
  </a>
353
321
 
354
- Reform is part of the [Trailblazer project](https://github.com/apotonick/trailblazer). Please [buy my book](https://leanpub.com/trailblazer) to support the development and learn everything about Reform. Currently the book discusses:
355
-
356
- * Form objects, the DSL and basic API (chapter 2 and 3)
357
- * Basic validations and rendering forms (chapter 3)
358
- * Nested forms, prepopulating and validation populating and pre-selecting values (chapter 5)
359
-
360
- More chapters are coming!
361
-
362
-
363
-
364
-
365
- ## Nomenclature
366
-
367
- Reform comes with two base classes.
368
-
369
- * `Form` is what made you come here - it gives you a form class to handle all validations, wrap models, allow rendering with Rails form helpers, simplifies saving of models, and more.
370
- * `Contract` gives you a sub-set of `Form`: [this class](#contracts) is meant for API validation where already populated models get validated without having to maintain validations in the model classes.
371
-
372
-
373
-
374
- Luckily, this can be shortened as follows.
375
-
376
- ```ruby
377
- class SongForm < Reform::Form
378
- property :title, validates: {presence: true}
379
- property :length, validates: {numericality: true}
380
- end
381
- ```
382
-
383
- Use `properties` to bulk-specify fields.
384
-
385
- ```ruby
386
- class SongForm < Reform::Form
387
- properties :title, :length, validates: {presence: true} # both required!
388
- validates :length, numericality: true
389
- end
390
- ```
391
-
392
-
393
-
394
- If the form wraps multiple models, via [composition](#compositions), you can access them like this:
395
-
396
- ```ruby
397
- @form.save do |nested|
398
- song = @form.model[:song]
399
- label = @form.model[:label]
400
- end
401
- ```
402
-
403
- Note that you can call `#sync` and _then_ call `#save { |hsh| }` to save models yourself.
404
-
405
-
406
- ## Contracts
407
-
408
- Contracts give you a sub-set of the `Form` API.
409
-
410
- 1. `#initialize` accepts an already populated model.
411
- 2. `#validate` will run defined validations (without accepting a params hash as in `Form`).
412
-
413
- Contracts can be used to completely remove validation logic from your model classes. Validation should happen in a separate layer - a `Contract`.
414
-
415
- ### Defining Contracts
416
-
417
- A contract looks like a form.
418
-
419
- ```ruby
420
- class AlbumContract < Reform::Contract
421
- property :title
422
- validates :title, length: {minimum: 9}
423
-
424
- collection :songs do
425
- property :title
426
- validates :title, presence: true
427
- end
428
- ```
429
-
430
- It defines the validations and the object graph to be inspected.
431
-
432
- In future versions and with the upcoming [Trailblazer framework](https://github.com/apotonick/trailblazer), contracts can be inherited from forms, representers, and cells, and vice-versa. Actually this already works with representer inheritance - let me know if you need help.
433
-
434
- ### Using Contracts
435
-
436
- Applying a contract is simple, all you need is a populated object (e.g. an album after `#assign_attributes`).
437
-
438
- ```ruby
439
- album.assign_attributes(..)
440
-
441
- contract = AlbumContract.new(album)
442
-
443
- if contract.validate
444
- album.save
445
- else
446
- raise contract.errors.messages.inspect
447
- end
448
- ```
449
-
450
- Contracts help you to make your data layer a dumb persistance tier. My [upcoming book discusses that in detail](http://nicksda.apotomo.de).
451
-
452
- ```
453
-
454
- This basically works like a nested `property` that iterates over a collection of songs.
455
-
456
-
457
-
458
- ### Turning Off Autosave
459
-
460
- You can assign Reform to _not_ call `save` on a particular nested model (per default, it is called automatically on all nested models).
461
-
462
- ```ruby
463
- class AlbumForm < Reform::Form
464
- # ...
465
-
466
- collection :songs, save: false do
467
- # ..
468
- end
469
- ```
470
-
471
- The `:save` options set to false won't save models.
472
-
473
-
474
-
475
-
476
-
477
- ## Compositions
478
-
479
- Sometimes you might want to embrace two (or more) unrelated objects with a single form. While you could write a simple delegating composition yourself, reform comes with it built-in.
480
-
481
- Say we were to edit a song and the label data the record was released from. Internally, this would imply working on the `songs` table and the `labels` table.
482
-
483
- ```ruby
484
- class SongWithLabelForm < Reform::Form
485
- include Composition
486
-
487
- property :title, on: :song
488
- property :city, on: :label
489
-
490
- model :song # only needed in ActiveModel context.
491
-
492
- validates :title, :city, presence: true
493
- end
494
- ```
495
-
496
- Note that reform needs to know about the owner objects of properties. You can do so by using the `on:` option.
497
-
498
- Also, the form needs to have a main object configured. This is where ActiveModel-methods like `#persisted?` or '#id' are delegated to. Use `::model` to define the main object.
499
-
500
-
501
- ### Composition: Setup
502
-
503
- The constructor slightly differs.
504
-
505
- ```ruby
506
- @form = SongWithLabelForm.new(song: Song.new, label: Label.new)
507
- ```
508
-
509
- ### Composition: Rendering
510
-
511
- After you configured your composition in the form, reform hides the fact that you're actually showing two different objects.
512
-
513
- ```haml
514
- = form_for @form do |f|
515
-
516
- Song: = f.input :title
517
-
518
- Label in: = f.input :city
519
- ```
520
-
521
- ### Composition: Processing
522
-
523
- When using `#save' without a block reform will use writer methods on the different objects to push validated data to the properties.
524
-
525
- Here's what the block parameters look like.
526
-
527
- ```ruby
528
- @form.save do |nested|
529
-
530
- nested #=> {
531
- # song: {title: "Rio"}
532
- # label: {city: "London"}
533
- # }
534
- end
535
- ```
536
-
537
-
538
- ## Forms In Modules
539
-
540
- To maximize reusability, you can also define forms in modules and include them in other modules or classes.
541
-
542
- ```ruby
543
- module SongsForm
544
- include Reform::Form::Module
545
-
546
- collection :songs do
547
- property :title
548
- validates :title, presence: true
549
- end
550
- end
551
- ```
552
-
553
- This can now be included into a real form.
554
-
555
- ```ruby
556
- class AlbumForm < Reform::Form
557
- property :title
558
-
559
- include SongsForm
560
- end
561
- ```
562
-
563
- Note that you can also override properties [using inheritance](#inheritance) in Reform.
564
-
565
- When using coercion, make sure the including form already contains the `Coercion` module.
566
-
567
-
568
- ## Inheritance
569
-
570
- Forms can be derived from other forms and will inherit all properties and validations.
571
-
572
- ```ruby
573
- class AlbumForm < Reform::Form
574
- property :title
575
-
576
- collection :songs do
577
- property :title
578
-
579
- validates :title, presence: true
580
- end
581
- end
582
- ```
583
-
584
- Now, a simple inheritance can add fields.
585
-
586
- ```ruby
587
- class CompilationForm < AlbumForm
588
- property :composers do
589
- property :name
590
- end
591
- end
592
- ```
593
-
594
- This will _add_ `composers` to the existing fields.
595
-
596
- You can also partially override fields using `:inherit`.
597
-
598
- ```ruby
599
- class CompilationForm < AlbumForm
600
- property :songs, inherit: true do
601
- property :band_id
602
- validates :band_id, presence: true
603
- end
604
- end
605
- ```
606
-
607
- Using `inherit:` here will extend the existing `songs` form with the `band_id` field. Note that this simply uses [representable's inheritance mechanism](https://github.com/apotonick/representable/#partly-overriding-properties).
608
-
609
- ## Coercion
610
-
611
- Often you want incoming form data to be converted to a type, like timestamps. Reform uses [virtus](https://github.com/solnic/virtus) for coercion, the DSL is seamlessly integrated into Reform with the `:type` option.
612
-
613
- ### Virtus Coercion
614
-
615
- Be sure to add `virtus` to your Gemfile.
616
-
617
- ```ruby
618
- require 'reform/form/coercion'
619
-
620
- class SongForm < Reform::Form
621
- include Coercion
622
-
623
- property :written_at, type: DateTime
624
- end
625
-
626
- form.validate("written_at" => "26 September")
627
- ```
628
-
629
- Coercion only happens in `#validate`.
630
-
631
- ```
632
- form.written_at #=> <DateTime "2014 September 26 00:00">
633
- ```
634
-
635
- ### Manual Coercing Values
636
-
637
- If you need to filter values manually, you can override the setter in the form.
638
-
639
- ```ruby
640
- class SongForm < Reform::Form
641
- property :title
642
-
643
- def title=(value)
644
- super sanitize(value) # value is raw form input.
645
- end
646
- end
647
- ```
648
-
649
- As with the built-in coercion, this setter is only called in `#validate`.
650
-
651
-
652
- ## Virtual Attributes
653
-
654
- 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.
655
-
656
-
657
- ### Virtual Fields
658
-
659
- 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.
660
-
661
- ```ruby
662
- class PasswordForm < Reform::Form
663
- property :password
664
- property :password_confirmation, virtual: true
665
- ```
666
-
667
- 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.
668
-
669
- ```ruby
670
- form.validate("password" => "123", "password_confirmation" => "321")
671
-
672
- form.password_confirmation #=> "321"
673
- ```
674
-
675
- The nested hash in the block-`#save` provides the same value.
676
-
677
- ```ruby
678
- form.save do |nested|
679
- nested[:password_confirmation] #=> "321"
680
- ```
681
-
682
- ### Read-Only Fields
683
-
684
- When you want to show a value but skip processing it after submission the `:writeable` option is your friend.
685
-
686
- ```ruby
687
- class ProfileForm < Reform::Form
688
- property :country, writeable: false
689
- ```
690
-
691
- This time reform will query the model for the value by calling `model.country`.
692
-
693
- You want to use this to display an initial value or to further process this field with JavaScript. However, after submission, the field is no longer considered: it won't be written to the model when saving.
694
-
695
- It is still readable in the nested hash and through the form itself.
696
-
697
- ```ruby
698
- form.save do |nested|
699
- nested[:country] #=> "Australia"
700
- ```
701
-
702
- ### Write-Only Fields
703
-
704
- A third alternative is to hide a field's value but write it to the database when syncing. This can be achieved using the `:readable` option.
705
-
706
- ```ruby
707
- property :credit_card_number, readable: false
708
- ```
709
-
710
- ## Validations From Models
711
-
712
- Sometimes when you still keep validations in your models (which you shouldn't) copying them to a form might not feel right. In that case, you can let Reform automatically copy them.
713
-
714
- ```ruby
715
- class SongForm < Reform::Form
716
- property :title
717
-
718
- extend ActiveModel::ModelValidations
719
- copy_validations_from Song
720
- end
721
- ```
722
-
723
- Note how `copy_validations_from` copies over the validations allowing you to stay DRY.
724
-
725
- This also works with Composition.
726
-
727
- ```ruby
728
- class SongForm < Reform::Form
729
- include Composition
730
- # ...
731
-
732
- extend ActiveModel::ModelValidations
733
- copy_validations_from song: Song, band: Band
734
- end
735
- ```
736
-
737
- Be warned that we _do not_ encourage copying validations. You should rather move validation code into forms and not work on your model directly anymore. Also, please note that the ```copy_validations_from``` line _must_ go below your property definitions for the validations to copy correctly.
738
-
739
- ## Agnosticism: Mapping Data
740
-
741
- Reform doesn't really know whether it's working with a PORO, an `ActiveRecord` instance or a `Sequel` row.
742
-
743
- When rendering the form, reform calls readers on the decorated model to retrieve the field data (`Song#title`, `Song#length`).
744
-
745
- When syncing a submitted form, the same happens using writers. Reform simply calls `Song#title=(value)`. No knowledge is required about the underlying database layer.
746
-
747
- The same applies to saving: Reform will call `#save` on the main model and nested models.
748
-
749
- Nesting forms only requires readers for the nested properties as `Album#songs`.
750
-
751
-
752
- ## Rails Integration
753
-
754
- Check out [@gogogarret](https://twitter.com/GoGoGarrett/)'s [sample Rails app](https://github.com/gogogarrett/reform_example) using Reform.
755
-
756
- Rails and Reform work together out-of-the-box.
757
-
758
- However, you should know about two things.
759
-
760
- 1. In case you explicitely _don't_ want to have automatic support for `ActiveRecord` or `Mongoid` and form builder: `require reform/form`, only.
761
- 2. In some setups around Rails 4 the `Form::ActiveRecord` module is not loaded properly, usually triggering a `NoMethodError` saying `undefined method 'model'`. If that happened to you, `require 'reform/rails'` manually at the bottom of your `config/application.rb`.
762
- 3. Mongoid form gets loaded with the gem if `Mongoid` constant is defined.
763
-
764
-
765
- ## ActiveRecord Compatibility
766
-
767
- Reform provides the following `ActiveRecord` specific features. They're mixed in automatically in a Rails/AR setup.
768
-
769
- * Uniqueness validations. Use `validates_uniqueness_of` in your form.
770
-
771
- As mentioned in the [Rails Integration](https://github.com/apotonick/reform#rails-integration) section some Rails 4 setups do not properly load.
772
-
773
- You may want to include the module manually then.
774
-
775
- ```ruby
776
- class SongForm < Reform::Form
777
- include Reform::Form::ActiveRecord
778
- ```
779
-
780
- ## Mongoid Compatibility
781
-
782
- Reform provides the following `Mongoid` specific features. They're mixed in automatically in a Rails/Mongoid setup.
783
-
784
- * Uniqueness validations. Use `validates_uniqueness_of` in your form.
785
-
786
- You may want to include the module manually then.
787
-
788
- ```ruby
789
- class SongForm < Reform::Form
790
- include Reform::Form::Mongoid
791
- ```
792
-
793
- ## Uniqueness Validation
794
-
795
- Both ActiveRecord and Mongoid modules will support "native" uniqueness support from the model class when you use `validates_uniqueness_of`. They will provide options like `:scope`, etc.
796
-
797
- You're encouraged to use Reform's non-writing `unique: true` validation, though. [Learn more](http://trailblazer.to/gems/reform/validation.html)
798
-
799
- ## ActiveModel Compliance
800
-
801
- Forms in Reform can easily be made ActiveModel-compliant.
802
-
803
- Note that this step is _not_ necessary in a Rails environment.
804
-
805
- ```ruby
806
- class SongForm < Reform::Form
807
- include Reform::Form::ActiveModel
808
- end
809
- ```
810
-
811
- If you're not happy with the `model_name` result, configure it manually via `::model`.
812
-
813
- ```ruby
814
- class CoverSongForm < Reform::Form
815
- include Reform::Form::ActiveModel
816
-
817
- model :song
818
- end
819
- ```
820
-
821
- `::model` will configure ActiveModel's naming logic. With `Composition`, this configures the main model of the form and should be called once.
822
-
823
- This is especially helpful when your framework tries to render `cover_song_path` although you want to go with `song_path`.
824
-
825
-
826
- ## FormBuilder Support
827
-
828
- To make your forms work with all the form gems like `simple_form` or Rails `form_for` you need to include another module.
829
-
830
- Again, this step is implicit in Rails and you don't need to do it manually.
831
-
832
- ```ruby
833
- class SongForm < Reform::Form
834
- include Reform::Form::ActiveModel
835
- include Reform::Form::ActiveModel::FormBuilderMethods
836
- end
837
- ```
838
-
839
- ### Simple Form
840
-
841
- If you want full support for `simple_form` do as follows.
842
-
843
- ```ruby
844
- class SongForm < Reform::Form
845
- include ActiveModel::ModelReflections
846
- ```
847
-
848
- Including this module will add `#column_for_attribute` and other methods need by form builders to automatically guess the type of a property.
849
-
850
- ## Validations For File Uploads
851
-
852
- In case you're processing uploaded files with your form using CarrierWave, Paperclip, Dragonfly or Paperdragon we recommend using the awesome [file_validators](https://github.com/musaffa/file_validators) gem for file type and size validations.
853
-
854
- ```ruby
855
- class SongForm < Reform::Form
856
- property :image
857
-
858
- validates :image, file_size: {less_than: 2.megabytes},
859
- file_content_type: {allow: ['image/jpeg', 'image/png', 'image/gif']}
860
- ```
861
-
862
- ## Multiparameter Dates
863
-
864
- 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.
865
-
866
- ```ruby
867
- class AlbumForm < Reform::Form
868
- feature Reform::Form::ActiveModel::FormBuilderMethods
869
- feature Reform::Form::MultiParameterAttributes
870
-
871
- collection :songs do
872
- feature Reform::Form::ActiveModel::FormBuilderMethods
873
- property :title
874
- property :release_date, :multi_params => true
875
- validates :title, :presence => true
876
- end
877
- end
878
- ```
879
-
880
- Note that the date will be `nil` when one of the components (year/month/day) is missing.
322
+ Reform is part of the [Trailblazer project](http://trailblazer.to). Please [buy my book](https://leanpub.com/trailblazer) to support the development and learn everything about Reform - there's two chapters dedicated to Reform!
881
323
 
882
324
 
883
- ## Security
325
+ ## Security And Strong_parameters
884
326
 
885
327
  By explicitely defining the form layout using `::property` there is no more need for protecting from unwanted input. `strong_parameter` or `attr_accessible` become obsolete. Reform will simply ignore undefined incoming parameters.
886
328
 
329
+ ## This is not Reform 1.x!
887
330
 
888
- ## Nesting Without Inline Representers
889
-
890
- When nesting form, you usually use a so-called inline form doing `property :song do .. end`.
891
-
892
- Sometimes you want to specify an explicit form rather than using an inline form. Use the `form:` option here.
893
-
894
- ```ruby
895
- property :song, form: SongForm
896
- ```
897
-
898
- The nested `SongForm` is a stand-alone form class you have to provide.
899
-
900
-
901
- ## Default Values For Presentation
902
-
903
- In case you want to change a value for presentation or provide a default value, override the reader. This is only considered when the form is rendered (e.g. in `form_for`).
904
-
905
- ```ruby
906
- class SongForm < Reform::Form
907
- property :genre
908
-
909
- def genre
910
- super || 'Punkrock'
911
- end
912
- end
913
- ```
914
-
915
- This will now be used when rendering the view.
916
-
917
- ```haml
918
- = f.input :genre # calls form.genre which provides default.
919
- ```
920
-
921
- ## Dirty Tracker
922
-
923
- Every form tracks changes in `#validate` and allows to check if a particular property value has changed using `#changed?`.
924
-
925
- ```ruby
926
- form.title => "Button Up"
927
-
928
- form.validate("title" => "Just Kiddin'")
929
- form.changed?(:title) #=> true
930
- ```
931
-
932
- When including `Sync::SkipUnchanged`, the form won't assign unchanged values anymore in `#sync`.
933
-
934
-
935
- ## Deserializing and Population
936
-
937
- 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.
938
-
939
- Representers can be inferred from the contract automatically using `Disposable::Schema`. You may then extend your representer with hypermedia, etc. in order to render documents. Check out the Trailblazer book (chapter Hypermedia APIs) for a full explanation.
940
-
941
- You can even write your own deserializer code in case you dislike Representable.
942
-
943
- ```ruby
944
- class AlbumForm < Reform::Form
945
- # ..
946
-
947
- def deserialize!(document)
948
- hash = YAML.parse(document)
949
-
950
- self.title = hash[:title]
951
- self.artist = Artist.new if hash[:artist]
952
- end
953
- end
954
- ```
955
-
956
- The decoupling of deserializer and form object is one of the main reasons I wrote Reform 2.
957
-
958
-
959
- ## Undocumented Features
960
-
961
- _(Please don't read this section!)_
962
-
963
- ### Skipping Properties when Validating
964
-
965
- In `#validate`, you can ignore properties now using `:skip_if` for deserialization.
966
-
967
- ```ruby
968
- property :hit, skip_if: lambda { |fragment, *| fragment["title"].blank? }
969
- ```
970
-
971
- 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.
972
-
973
- For nested properties you can use `:skip_if: :all_blank` as a macro to ignore a nested form if all values are blank.
974
-
975
- Note that this still runs validations for the property, though.
976
-
977
- ### Prepopulating Forms
978
-
979
- Docs: http://trailblazer.to/gems/reform/prepopulator.html
980
-
981
- When rendering a new form for an empty object, nested forms won't show up. The [Trailblazer book, chapter 5](https://leanpub.com/trailblazer), discusses this in detail.
982
-
983
- You can use the `:prepopulator` option to configure how to populate a nested form (this also works for scalar properties).
984
-
985
- ```ruby
986
- property :song, prepopulator: ->(options) { self.song = Song.new } do
987
- # ..
988
- end
989
- ```
990
-
991
- This option is only executed when being instructed to do so, using the `#prepopulate!` method.
992
-
993
- ```ruby
994
- form.prepopulate!
995
- ```
996
-
997
- You can also pass options to `#prepopulate`.
998
-
999
- Only do this for forms that are about to get rendered, though.
1000
-
1001
- Collections and partial collection population is covered in chapter 5.
1002
-
1003
-
1004
- ### Populator
1005
-
1006
- You can run your very own populator logic if you're keen (and you know what you're doing).
1007
-
1008
- ```ruby
1009
- class AlbumForm < Reform::Form
1010
- # ...
1011
-
1012
- collection :songs, populator: lambda { |fragment, args| args.binding[:form].new(Song.find fragment[:id]) } do
1013
- # ..
1014
- end
1015
- ```
1016
-
1017
- ### Property Inflections
1018
-
1019
- When rendering a form you might need to access the options you provided to `property`.
1020
-
1021
- ```ruby
1022
- property :title, type: String
1023
- ```
1024
-
1025
- You can do this using `#options_for`.
1026
-
1027
- ```ruby
1028
- form.options_for(:title) # => {:readable=>true, :coercion_type=>String}
1029
- ```
1030
-
1031
- Note that Reform renames some options (e.g. `:type` internally becomes `:coercion_type`). Those names are private API and might be changed without deprecation. You better test rendering logic in a unit test to make sure you're forward-compatible.
1032
-
1033
- ## Support
1034
-
1035
- If you run into any trouble chat with us on irc.freenode.org#trailblazer.
1036
-
1037
-
1038
- ## Maintainers
331
+ Temporary note: This is the README and API for Reform 2. On the public API, only a few tiny things have changed. Here are the [Reform 1.2 docs](https://github.com/apotonick/reform/blob/v1.2.6/README.md).
1039
332
 
1040
- [Nick Sutterer](https://github.com/apotonick)
1041
- [Garrett Heinlen](https://github.com/gogogarrett)
333
+ Anyway, please upgrade and _report problems_ and do not simply assume that we will magically find out what needs to get fixed. When in trouble, join us on [Gitter](https://gitter.im/trailblazer/chat).
1042
334
 
335
+ [Full documentation for Reform](http://trailblazer.to/gems/reform) is available online, or support us and grab the [Trailblazer book](https://leanpub.com/trailblazer). There is an [Upgrading Guide](http://trailblazer.to/gems/reform/upgrading-guide.html) to help you migrate from Reform 1.x.
1043
336
 
1044
337
  ### Attributions!!!
1045
338