reform 2.0.0.rc1 → 2.0.0.rc2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 981ddfe5d276177430c4441c81e38f8d1bc89166
4
- data.tar.gz: 269eeca94c1c7636e4ff8fd73df5e2c6bccc459c
3
+ metadata.gz: a87860e43b6e321c13ae641903aa1a6b098c2ec1
4
+ data.tar.gz: 50d863fbf7d3e5ba9ea7eb0ea2d46a073e7cf458
5
5
  SHA512:
6
- metadata.gz: 165337839adaf02e97f805f05974a2ce9b8b1950f848493a1feabbb5ce708c3877e7bb6f59c7d0f5ab088f36ddfc10c3b4069cbed2ada2ba95909a360c0d705d
7
- data.tar.gz: c7cf74f86eebc98c0810299fbaa179715b2bf92ba02d666f8658a116323d8b3b637fb9cf36361612f673abe1e5aa9541d04b1606d674f758fcc264d165d0f23c
6
+ metadata.gz: 6a3171c4d74d852e77a88d817b886515fbe2c0f469e9f54abb3e53efd7b237013010d4b1c404b382c5e068294bd5747c9bd61061fdc511c18db8507bfff5630c
7
+ data.tar.gz: 12f688ec7d485fafd29924d91c5dd59862ff3fb6f23c463a3b4e6be2aaddaa6d7381e706f318029841509bfd52571d4b462d6eead389c976a3437085b6053f84
data/.travis.yml CHANGED
@@ -1,15 +1,17 @@
1
1
  language: ruby
2
2
  rvm:
3
3
  - 2.2.0
4
- - 2.1.5
5
- - 2.0.0
6
4
  - 1.9.3
5
+ services:
6
+ - mongodb
7
7
  gemfile:
8
+ - gemfiles/Gemfile.rails-4.2
9
+ - gemfiles/Gemfile.rails-4.1
8
10
  - gemfiles/Gemfile.rails-4.0
9
11
  - gemfiles/Gemfile.rails-3.2
10
12
  - gemfiles/Gemfile.rails-3.1
11
- - gemfiles/Gemfile.rails-3.0
13
+ # - gemfiles/Gemfile.rails-3.0
12
14
  matrix:
13
15
  fast_finish: true
14
16
  allow_failures:
15
- - rvm: ruby-head
17
+ - rvm: 1.9.3
data/CHANGES.md CHANGED
@@ -14,6 +14,9 @@ you don't need to know about forms anymore, the twin handles that using #insert.
14
14
  * With `Composition` included, `Form#model` would give you a composition object. You can grab that using `Form#mapper` now.
15
15
  * `Form#update!` is deprecated. It still works but will remind you to override `#present!` or use pre-populators as [described here](http://trailblazerb.org/gems/reform/prepopulator.html) and in the Trailblazer book, chapter "Nested Forms".
16
16
 
17
+ * Forms do not `include ActiveModel::Validations` anymore. This has polluted the entire gem and is not encapsulated in `Validator`. Consider using Lotus Validations instead.
18
+ * Validation inheritance with `ActiveModel::Validations` is broken with Rails 3.2 and 4.0. Update Rails or use the `Lotus` validations.
19
+
17
20
  ## 1.2.6
18
21
 
19
22
  * Added `:prepopulate` to fill out form properties for presentation. Note that you need to call `Form#prepopulate!` to trigger the prepopulation.
data/Gemfile CHANGED
@@ -3,5 +3,5 @@ source 'https://rubygems.org'
3
3
  gemspec
4
4
 
5
5
  #gem 'representable', path: "../representable"
6
- # gem "disposable", path: "../disposable"
6
+ # gem "disposable", path: "../disposable"
7
7
  # gem "disposable", github: "apotonick/disposable"
data/README.md CHANGED
@@ -40,7 +40,7 @@ Forms have a ridiculously simple API with only a handful of public methods.
40
40
  3. `#errors` returns validation messages in a classic ActiveModel style.
41
41
  4. `#sync` writes form data back to the model. This will only use setter methods on the model(s).
42
42
  5. `#save` (optional) will call `#save` on the model and nested models. Note that this implies a `#sync` call.
43
- 6. `#present!` (optional) will run pre-population hooks to "fill out" your form before rendering.
43
+ 6. `#prepopulate!` (optional) will run pre-population hooks to "fill out" your form before rendering.
44
44
 
45
45
  In addition to the main API, forms expose accessors to the defined properties. This is used for rendering or manual operations.
46
46
 
@@ -77,7 +77,7 @@ Your `@form` is now ready to be rendered, either do it yourself or use something
77
77
 
78
78
  Nested forms and collections can be easily rendered with `fields_for`, etc. Note that you no longer pass the model to the form builder, but the Reform instance.
79
79
 
80
- Optionally, you might want to use the [#present!](#present) method to pre-populate fields and prepare the form for rendering.
80
+ Optionally, you might want to use the `#prepopulate!` method to pre-populate fields and prepare the form for rendering.
81
81
 
82
82
 
83
83
  ## Validation
@@ -283,6 +283,30 @@ Add this line to your Gemfile:
283
283
  gem 'reform'
284
284
  ```
285
285
 
286
+ 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.
287
+
288
+ 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).
289
+
290
+ To use ActiveModel (not recommended as it doesn't support removing validations).
291
+
292
+ ```ruby
293
+ require "reform/form/active_model/validations"
294
+ Reform::Form.class_eval do
295
+ include Reform::Form::ActiveModel::Validations
296
+ end
297
+ ```
298
+
299
+ To use Lotus validations (recommended).
300
+
301
+ ```ruby
302
+ require "reform/form/lotus"
303
+ Reform::Form.class_eval do
304
+ include Reform::Form::Lotus
305
+ end
306
+ ```
307
+
308
+ Put this in an initializer or on top of your script.
309
+
286
310
 
287
311
  ## Compositions
288
312
 
@@ -723,8 +747,10 @@ Rails and Reform work together out-of-the-box.
723
747
 
724
748
  However, you should know about two things.
725
749
 
726
- 1. In case you explicitely _don't_ want to have automatic support for `ActiveRecord` and form builder: `require reform/form`, only.
750
+ 1. In case you explicitely _don't_ want to have automatic support for `ActiveRecord` or `Mongoid` and form builder: `require reform/form`, only.
727
751
  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`.
752
+ 3. Mongoid form gets loaded with the gem if `Mongoid` constant is defined.
753
+
728
754
 
729
755
  ## ActiveRecord Compatibility
730
756
 
@@ -741,6 +767,24 @@ class SongForm < Reform::Form
741
767
  include Reform::Form::ActiveRecord
742
768
  ```
743
769
 
770
+ ## Mongoid Compatibility
771
+
772
+ Reform provides the following `Mongoid` specific features. They're mixed in automatically in a Rails/Mongoid setup.
773
+
774
+ * Uniqueness validations. Use `validates_uniqueness_of` in your form.
775
+
776
+ You may want to include the module manually then.
777
+
778
+ ```ruby
779
+ class SongForm < Reform::Form
780
+ include Reform::Form::Mongoid
781
+ ```
782
+
783
+ ## Uniqueness Validation
784
+
785
+ 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.
786
+
787
+ You're encouraged to use Reform's non-writing `unique: true` validation, though. [Learn more](http://trailblazerb.org/gems/reform/validation.html)
744
788
 
745
789
  ## ActiveModel Compliance
746
790
 
data/database.sqlite3 CHANGED
Binary file
@@ -0,0 +1,8 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in reform.gemspec
4
+ gemspec :path => '../'
5
+
6
+ gem 'railties', '~> 4.1.0'
7
+ gem 'activerecord', '~> 4.1.0'
8
+ gem 'minitest'
@@ -0,0 +1,8 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in reform.gemspec
4
+ gemspec :path => '../'
5
+
6
+ gem 'railties', '~> 4.2.0'
7
+ gem 'activerecord', '~> 4.2.0'
8
+ gem 'minitest'
@@ -1,3 +1,4 @@
1
1
  require 'reform/form/active_model'
2
+ require 'reform/form/orm'
2
3
  require 'reform/form/active_record'
3
4
  require 'reform/form/model_reflections' # only load this in AR context as simple_form currently is bound to AR.
@@ -27,7 +27,7 @@ module Reform
27
27
  end
28
28
 
29
29
  if validates_options = options[:validates]
30
- validates name, validates_options.dup # .dup for RAils 3.x because it's retarded.
30
+ validates name, validates_options.dup # .dup for RAils 3.x.
31
31
  end
32
32
 
33
33
  super
@@ -39,20 +39,18 @@ module Reform
39
39
  args.each { |name| property(name, options) }
40
40
  end
41
41
 
42
- # FIXME: make AM optional.
43
- require 'active_model'
44
- include ActiveModel::Validations
45
-
46
42
  require 'reform/contract/validate'
47
43
  include Reform::Contract::Validate
48
44
 
49
- def errors # FIXME: this is needed for Rails 3.0 compatibility.
50
- @errors ||= Errors.new(self)
45
+
46
+ module ValidatesWarning
47
+ def validates(*)
48
+ raise "[Reform] Please include either Reform::Form::ActiveModel::Validations or Reform::Form::Lotus in your form class."
49
+ end
51
50
  end
51
+ extend ValidatesWarning
52
52
 
53
53
  private
54
- attr_writer :errors # only used in top form. (is that true?)
55
-
56
54
  # DISCUSS: can we achieve that somehow via features in build_inline?
57
55
  # TODO: check out if that is needed with Lotus::Validations and make it a AM feature.
58
56
  def self.process_inline!(mod, definition)
@@ -92,5 +90,3 @@ module Reform
92
90
  extend Reform::Schema
93
91
  end
94
92
  end
95
-
96
- require 'reform/contract/errors'
@@ -1,25 +1,11 @@
1
1
  # The Errors class is planned to replace AM::Errors. It provides proper nested error messages.
2
2
  class Reform::Contract::Errors < ActiveModel::Errors
3
- def messages
4
- return super unless Reform.rails3_0?
5
- self
6
- end
7
-
8
- # def each
9
- # messages.each_key do |attribute|
10
- # self[attribute].each { |error| yield attribute, Array.wrap(error) }
11
- # end
12
- # end
13
-
14
3
  def merge!(errors, prefix)
15
- # TODO: merge into AM.
16
4
  errors.messages.each do |field, msgs|
17
5
  unless field.to_sym == :base
18
6
  field = (prefix+[field]).join(".").to_sym # TODO: why is that a symbol in Rails?
19
7
  end
20
8
 
21
- msgs = [msgs] if Reform.rails3_0? # DISCUSS: fix in #each?
22
-
23
9
  msgs.each do |msg|
24
10
  next if messages[field] and messages[field].include?(msg)
25
11
  add(field, msg)
@@ -28,7 +14,7 @@ class Reform::Contract::Errors < ActiveModel::Errors
28
14
  end
29
15
 
30
16
  def valid? # TODO: test me in unit test.
31
- blank?
17
+ empty?
32
18
  end
33
19
 
34
20
  def to_s
@@ -1,36 +1,31 @@
1
1
  module Reform::Contract::Validate
2
2
  def validate
3
- options = {:errors => errs = Reform::Contract::Errors.new(self), :prefix => []}
3
+ validate!(errs=build_errors, [])
4
4
 
5
- validate!(options)
6
-
7
- self.errors = errs # if the AM valid? API wouldn't use a "global" variable this would be better.
8
-
9
- errors.valid?
5
+ @errors = errs
6
+ errors.empty?
10
7
  end
11
8
 
12
- def validate!(options)
13
- prefix = options[:prefix]
9
+ def validate!(errors, prefix)
10
+ validate_nested!(nested_errors = build_errors, prefix) # call valid? recursively and collect nested errors.
14
11
 
15
- validate_nested!(options) # call valid? recursively and collect nested errors.
12
+ valid? # calls AM/Lotus validators and invokes self.errors=.
16
13
 
17
- valid? # this validates on <Fields> using AM::Validations, currently.
14
+ errors.merge!(self.errors, prefix) # local errors.
15
+ errors.merge!(nested_errors, []) #
16
+ end
18
17
 
19
- options[:errors].merge!(self.errors, prefix)
18
+ def errors
19
+ @errors ||= build_errors
20
20
  end
21
21
 
22
22
  private
23
23
 
24
24
  # runs form.validate! on all nested forms
25
- def validate_nested!(options)
25
+ def validate_nested!(errors, prefixes)
26
26
  schema.each(twin: true) do |dfn|
27
- property_options = options.dup
28
-
29
- property_options[:prefix] = options[:prefix].dup # TODO: implement Options#dup.
30
- property_options[:prefix] << dfn.name
31
-
32
27
  # recursively call valid? on nested form.
33
- Disposable::Twin::PropertyProcessor.new(dfn, self).() { |form| form.validate!(property_options) }
28
+ Disposable::Twin::PropertyProcessor.new(dfn, self).() { |form| form.validate!(errors, prefixes+[dfn.name]) }
34
29
  end
35
30
  end
36
31
  end
@@ -99,5 +99,10 @@ module Reform::Form::ActiveModel
99
99
  return ::ActiveModel::Name.new(OpenStruct.new(:name => string)) if Reform.rails3_0?
100
100
  ::ActiveModel::Name.new(self, namespace, string)
101
101
  end
102
+ end # ClassMethods
103
+
104
+
105
+ def model_name(*args)
106
+ self.class.model_name(*args)
102
107
  end
103
108
  end
@@ -0,0 +1,66 @@
1
+ require "active_model"
2
+ require "reform/contract/errors"
3
+
4
+ module Reform::Form::ActiveModel
5
+ # AM::Validations for your form.
6
+ #
7
+ # Note: The preferred way for validations should be Lotus::Validations, as ActiveModel::Validation's implementation is
8
+ # old, very complex given that it needs to do a simple thing, and it's using globals like @errors.
9
+ #
10
+ # Implements ::validates and friends, and #valid?.
11
+ module Validations
12
+ def self.included(includer)
13
+ includer.instance_eval do
14
+ extend Uber::InheritableAttr
15
+ inheritable_attr :validator
16
+ self.validator = Class.new(Validator)
17
+
18
+ class << self
19
+ extend Uber::Delegates
20
+ delegates :validator, :validates, :validate, :validates_with, :validate_with
21
+ end
22
+ end
23
+ end
24
+
25
+ def build_errors
26
+ Reform::Contract::Errors.new(self)
27
+ end
28
+
29
+
30
+ # Validators is the validatable object. On the class level, we define validations,
31
+ # on instance, it exposes #valid?.
32
+ class Validator
33
+ include ActiveModel::Validations
34
+
35
+ def initialize(form)
36
+ @form = form
37
+ end
38
+
39
+ def method_missing(method_name, *args, &block)
40
+ @form.send(method_name, *args, &block)
41
+ end
42
+
43
+ def self.name # FIXME: this is only needed for i18n, it seems.
44
+ "ba"
45
+ end
46
+
47
+ def self.clone
48
+ Class.new(self)
49
+ end
50
+ end
51
+
52
+
53
+ def valid?
54
+ validator = self.class.validator.new(self)
55
+ validator.valid? # run the Validations object's validator with the form as context. this won't pollute anything in the form.
56
+
57
+
58
+ #errors.merge!(validator.errors, "")
59
+ validator.errors.each do |name, error| # TODO: handle with proper merge, or something. validator.errors is ALWAYS AM::Errors.
60
+ errors.add(name, error)
61
+ end
62
+
63
+ errors.empty?
64
+ end
65
+ end
66
+ end
@@ -3,6 +3,7 @@ module Reform::Form::ActiveRecord
3
3
  base.class_eval do
4
4
  register_feature Reform::Form::ActiveRecord
5
5
  include Reform::Form::ActiveModel
6
+ include Reform::Form::ORM
6
7
  extend ClassMethods
7
8
  end
8
9
  end
@@ -18,28 +19,6 @@ module Reform::Form::ActiveRecord
18
19
  end
19
20
 
20
21
  class UniquenessValidator < ::ActiveRecord::Validations::UniquenessValidator
21
- # when calling validates it should create the Vali instance already and set @klass there! # TODO: fix this in AM.
22
- def validate(form)
23
- property = attributes.first
24
-
25
- # here is the thing: why does AM::UniquenessValidator require a filled-out record to work properly? also, why do we need to set
26
- # the class? it would be way easier to pass #validate a hash of attributes and get back an errors hash.
27
- # the class for the finder could either be infered from the record or set in the validator instance itself in the call to ::validates.
28
- record = form.model_for_property(property)
29
- record.send("#{property}=", form.send(property))
30
-
31
- @klass = record.class # this is usually done in the super-sucky #setup method.
32
- super(record).tap do |res|
33
- form.errors.add(property, record.errors.first.last) if record.errors.present?
34
- end
35
- end
36
- end
37
-
38
- # TODO: this is no AR thing.
39
- def model_for_property(name)
40
- return model unless is_a?(Reform::Form::Composition) # i am too lazy for proper inheritance. there should be a ActiveRecord::Composition that handles this.
41
-
42
- model_name = schema.representable_attrs.get(name)[:on]
43
- model[model_name]
22
+ include Reform::Form::ORM::UniquenessValidator
44
23
  end
45
24
  end
@@ -0,0 +1,55 @@
1
+ require "lotus/validations"
2
+
3
+ # Implements ::validates and friends, and #valid?.
4
+ module Reform::Form::Lotus
5
+ class Errors < Lotus::Validations::Errors
6
+ def merge!(errors, prefix)
7
+ errors.instance_variable_get(:@errors).each do |name, err|
8
+ field = (prefix+[name]).join(".")
9
+ add(field, *err) # TODO: use namespace feature in Lotus here!
10
+ end
11
+ # next if messages[field] and messages[field].include?(msg)
12
+ end
13
+
14
+ def inspect
15
+ @errors.to_s
16
+ end
17
+
18
+ def messages
19
+ self
20
+ end
21
+ end
22
+
23
+
24
+ def self.included(base)
25
+ # base.send(:include, Lotus::Validations)
26
+ base.extend(ClassMethods)
27
+ end
28
+
29
+
30
+ module ClassMethods
31
+ def validates(name, options)
32
+ validations.add(name, options)
33
+ end
34
+
35
+ def validate(name, *)
36
+ # DISCUSS: lotus does not support that?
37
+ # validations.add(name, options)
38
+ end
39
+
40
+ def validations
41
+ @validations ||= Lotus::Validations::ValidationSet.new
42
+ end
43
+ end
44
+
45
+
46
+ def valid?
47
+ # DISCUSS: by using @fields here, we avoid setters being called. win!
48
+ validator = Lotus::Validations::Validator.new(self.class.validations, @fields, errors)
49
+ validator.validate
50
+ end
51
+
52
+ def build_errors
53
+ Errors.new
54
+ end
55
+ end