reform 2.0.0 → 2.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGES.md +4 -0
- data/README.md +6 -2
- data/database.sqlite3 +0 -0
- data/lib/reform/form/active_model/validations.rb +16 -6
- data/lib/reform/mongoid.rb +1 -1
- data/lib/reform/version.rb +1 -1
- data/test/active_model_custom_validation_translations_test.rb +47 -0
- data/test/dummy/config/locales/en.yml +204 -4
- data/test/mongoid_test.rb +261 -259
- metadata +4 -3
- data/gemfiles/Gemfile.rails-3.0 +0 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 037b79d11746474c6c396824536f8bd567e59879
|
4
|
+
data.tar.gz: 4d448833f2cde88977600d0e9cc85686550eeda8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a40d0cde85b16d5b4f4fbfa06cde1549e961044986abda2a95cb0abc2a22224a8b0b7dd88a7e80706b9b78b1932056d0091d4c858f7d3e67b523ced40bdd1285
|
7
|
+
data.tar.gz: bc964b5838dabcaac8b47db139a6a6b86c624b133297af97489d6dd1f465bb375cb47c9186c52832ad4ebea03227095f0947629edfc3678090fd471e2e06ff66
|
data/CHANGES.md
CHANGED
data/README.md
CHANGED
@@ -113,8 +113,12 @@ It's then up to you what to do with the updated models - they're still unsaved.
|
|
113
113
|
The easiest way to save the data is to call `#save` on the form.
|
114
114
|
|
115
115
|
```ruby
|
116
|
-
|
117
|
-
|
116
|
+
if @form.validate(params[:song])
|
117
|
+
@form.save #=> populates album with incoming data
|
118
|
+
# by calling @form.album.title=.
|
119
|
+
else
|
120
|
+
# handle validation errors.
|
121
|
+
end
|
118
122
|
```
|
119
123
|
|
120
124
|
This will sync the data to the model and then call `album.save`.
|
data/database.sqlite3
CHANGED
Binary file
|
@@ -5,13 +5,16 @@ require "uber/delegates"
|
|
5
5
|
module Reform::Form::ActiveModel
|
6
6
|
# AM::Validations for your form.
|
7
7
|
#
|
8
|
-
# Note: The preferred way for validations should be Lotus::Validations, as ActiveModel::Validation's
|
9
|
-
# old, very complex given that it needs to do a simple thing,
|
8
|
+
# Note: The preferred way for validations should be Lotus::Validations, as ActiveModel::Validation's
|
9
|
+
# implementation is old, very complex given that it needs to do a simple thing, is using
|
10
|
+
# globals like @errors, and relies and more than 100 methods to be mixed into your form.
|
10
11
|
#
|
11
12
|
# Implements ::validates and friends, and #valid?.
|
13
|
+
#
|
12
14
|
module Validations
|
13
15
|
def self.included(includer)
|
14
16
|
includer.instance_eval do
|
17
|
+
include Reform::Form::ActiveModel
|
15
18
|
extend Uber::InheritableAttr
|
16
19
|
inheritable_attr :validator
|
17
20
|
self.validator = Class.new(Validator)
|
@@ -19,6 +22,9 @@ module Reform::Form::ActiveModel
|
|
19
22
|
class << self
|
20
23
|
extend Uber::Delegates
|
21
24
|
delegates :validator, :validates, :validate, :validates_with, :validate_with
|
25
|
+
|
26
|
+
# Hooray! Delegate translation back to Reform's Validator class which contains AM::Validations.
|
27
|
+
delegates :validator, :human_attribute_name, :lookup_ancestors, :i18n_scope # Rails 3.1.
|
22
28
|
end
|
23
29
|
end
|
24
30
|
end
|
@@ -27,6 +33,12 @@ module Reform::Form::ActiveModel
|
|
27
33
|
Reform::Contract::Errors.new(self)
|
28
34
|
end
|
29
35
|
|
36
|
+
# The concept of "composition" has still not arrived in Rails core and they rely on 400 methods being
|
37
|
+
# available in one object. This is why we need to provide parts of the I18N API in the form.
|
38
|
+
def read_attribute_for_validation(name)
|
39
|
+
send(name)
|
40
|
+
end
|
41
|
+
|
30
42
|
|
31
43
|
# Validators is the validatable object. On the class level, we define validations,
|
32
44
|
# on instance, it exposes #valid?.
|
@@ -44,9 +56,6 @@ module Reform::Form::ActiveModel
|
|
44
56
|
@form.send(method_name, *args, &block)
|
45
57
|
end
|
46
58
|
|
47
|
-
# def self.model_name # FIXME: this is only needed for i18n, it seems.
|
48
|
-
# "Reform::Form"
|
49
|
-
# end
|
50
59
|
def self.model_name
|
51
60
|
ActiveModel::Name.new(Reform::Form)
|
52
61
|
end
|
@@ -57,7 +66,8 @@ module Reform::Form::ActiveModel
|
|
57
66
|
end
|
58
67
|
end
|
59
68
|
|
60
|
-
|
69
|
+
# Needs to be implemented by every validation backend and implements the
|
70
|
+
# actual validation. See Reform::Form::Lotus, too!
|
61
71
|
def valid?
|
62
72
|
validator = self.class.validator.new(self)
|
63
73
|
validator.valid? # run the Validations object's validator with the form as context. this won't pollute anything in the form.
|
data/lib/reform/mongoid.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
1
|
require 'reform/form/active_model'
|
2
2
|
require 'reform/form/orm'
|
3
3
|
require 'reform/form/mongoid'
|
4
|
-
require 'reform/form/model_reflections' # only load this in AR context as simple_form currently is bound to AR.
|
4
|
+
require 'reform/form/active_model/model_reflections' # only load this in AR context as simple_form currently is bound to AR.
|
data/lib/reform/version.rb
CHANGED
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class ActiveModelCustomValidationTranslationsTest < MiniTest::Spec
|
4
|
+
module SongForm
|
5
|
+
class WithBlock < Reform::Form
|
6
|
+
property :title
|
7
|
+
|
8
|
+
validate do
|
9
|
+
errors.add :title, :blank
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
class WithLambda < Reform::Form
|
14
|
+
property :title
|
15
|
+
|
16
|
+
validate ->{ errors.add :title, :blank }
|
17
|
+
end
|
18
|
+
|
19
|
+
class WithMethod < Reform::Form
|
20
|
+
property :title
|
21
|
+
|
22
|
+
validate :custom_validation_method
|
23
|
+
def custom_validation_method
|
24
|
+
errors.add :title, :blank
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
|
30
|
+
it 'translates the error message when custom validation is used with block' do
|
31
|
+
form = SongForm::WithBlock.new(Song.new)
|
32
|
+
form.validate({})
|
33
|
+
form.errors[:title].must_include "can't be blank"
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'translates the error message when custom validation is used with lambda' do
|
37
|
+
form = SongForm::WithLambda.new(Song.new)
|
38
|
+
form.validate({})
|
39
|
+
form.errors[:title].must_include "can't be blank"
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'translates the error message when custom validation is used with method' do
|
43
|
+
form = SongForm::WithMethod.new(Song.new)
|
44
|
+
form.validate({})
|
45
|
+
form.errors[:title].must_include "can't be blank"
|
46
|
+
end
|
47
|
+
end
|
@@ -1,5 +1,205 @@
|
|
1
|
-
|
2
|
-
# See http://github.com/svenfuchs/rails-i18n/tree/master/rails%2Flocale for starting points.
|
3
|
-
|
1
|
+
---
|
4
2
|
en:
|
5
|
-
|
3
|
+
date:
|
4
|
+
abbr_day_names:
|
5
|
+
- Sun
|
6
|
+
- Mon
|
7
|
+
- Tue
|
8
|
+
- Wed
|
9
|
+
- Thu
|
10
|
+
- Fri
|
11
|
+
- Sat
|
12
|
+
abbr_month_names:
|
13
|
+
-
|
14
|
+
- Jan
|
15
|
+
- Feb
|
16
|
+
- Mar
|
17
|
+
- Apr
|
18
|
+
- May
|
19
|
+
- Jun
|
20
|
+
- Jul
|
21
|
+
- Aug
|
22
|
+
- Sep
|
23
|
+
- Oct
|
24
|
+
- Nov
|
25
|
+
- Dec
|
26
|
+
day_names:
|
27
|
+
- Sunday
|
28
|
+
- Monday
|
29
|
+
- Tuesday
|
30
|
+
- Wednesday
|
31
|
+
- Thursday
|
32
|
+
- Friday
|
33
|
+
- Saturday
|
34
|
+
formats:
|
35
|
+
default: "%Y-%m-%d"
|
36
|
+
long: "%B %d, %Y"
|
37
|
+
short: "%b %d"
|
38
|
+
month_names:
|
39
|
+
-
|
40
|
+
- January
|
41
|
+
- February
|
42
|
+
- March
|
43
|
+
- April
|
44
|
+
- May
|
45
|
+
- June
|
46
|
+
- July
|
47
|
+
- August
|
48
|
+
- September
|
49
|
+
- October
|
50
|
+
- November
|
51
|
+
- December
|
52
|
+
order:
|
53
|
+
- :year
|
54
|
+
- :month
|
55
|
+
- :day
|
56
|
+
datetime:
|
57
|
+
distance_in_words:
|
58
|
+
about_x_hours:
|
59
|
+
one: about 1 hour
|
60
|
+
other: about %{count} hours
|
61
|
+
about_x_months:
|
62
|
+
one: about 1 month
|
63
|
+
other: about %{count} months
|
64
|
+
about_x_years:
|
65
|
+
one: about 1 year
|
66
|
+
other: about %{count} years
|
67
|
+
almost_x_years:
|
68
|
+
one: almost 1 year
|
69
|
+
other: almost %{count} years
|
70
|
+
half_a_minute: half a minute
|
71
|
+
less_than_x_minutes:
|
72
|
+
one: less than a minute
|
73
|
+
other: less than %{count} minutes
|
74
|
+
less_than_x_seconds:
|
75
|
+
one: less than 1 second
|
76
|
+
other: less than %{count} seconds
|
77
|
+
over_x_years:
|
78
|
+
one: over 1 year
|
79
|
+
other: over %{count} years
|
80
|
+
x_days:
|
81
|
+
one: 1 day
|
82
|
+
other: "%{count} days"
|
83
|
+
x_minutes:
|
84
|
+
one: 1 minute
|
85
|
+
other: "%{count} minutes"
|
86
|
+
x_months:
|
87
|
+
one: 1 month
|
88
|
+
other: "%{count} months"
|
89
|
+
x_seconds:
|
90
|
+
one: 1 second
|
91
|
+
other: "%{count} seconds"
|
92
|
+
prompts:
|
93
|
+
day: Day
|
94
|
+
hour: Hour
|
95
|
+
minute: Minute
|
96
|
+
month: Month
|
97
|
+
second: Seconds
|
98
|
+
year: Year
|
99
|
+
errors:
|
100
|
+
format: "%{attribute} %{message}"
|
101
|
+
messages:
|
102
|
+
accepted: must be accepted
|
103
|
+
blank: can't be blank
|
104
|
+
present: must be blank
|
105
|
+
confirmation: doesn't match %{attribute}
|
106
|
+
empty: can't be empty
|
107
|
+
equal_to: must be equal to %{count}
|
108
|
+
even: must be even
|
109
|
+
exclusion: is reserved
|
110
|
+
greater_than: must be greater than %{count}
|
111
|
+
greater_than_or_equal_to: must be greater than or equal to %{count}
|
112
|
+
inclusion: is not included in the list
|
113
|
+
invalid: is invalid
|
114
|
+
less_than: must be less than %{count}
|
115
|
+
less_than_or_equal_to: must be less than or equal to %{count}
|
116
|
+
not_a_number: is not a number
|
117
|
+
not_an_integer: must be an integer
|
118
|
+
odd: must be odd
|
119
|
+
record_invalid: 'Validation failed: %{errors}'
|
120
|
+
restrict_dependent_destroy:
|
121
|
+
one: Cannot delete record because a dependent %{record} exists
|
122
|
+
many: Cannot delete record because dependent %{record} exist
|
123
|
+
taken: has already been taken
|
124
|
+
too_long:
|
125
|
+
one: is too long (maximum is 1 character)
|
126
|
+
other: is too long (maximum is %{count} characters)
|
127
|
+
too_short:
|
128
|
+
one: is too short (minimum is 1 character)
|
129
|
+
other: is too short (minimum is %{count} characters)
|
130
|
+
wrong_length:
|
131
|
+
one: is the wrong length (should be 1 character)
|
132
|
+
other: is the wrong length (should be %{count} characters)
|
133
|
+
other_than: must be other than %{count}
|
134
|
+
template:
|
135
|
+
body: 'There were problems with the following fields:'
|
136
|
+
header:
|
137
|
+
one: 1 error prohibited this %{model} from being saved
|
138
|
+
other: "%{count} errors prohibited this %{model} from being saved"
|
139
|
+
helpers:
|
140
|
+
select:
|
141
|
+
prompt: Please select
|
142
|
+
submit:
|
143
|
+
create: Create %{model}
|
144
|
+
submit: Save %{model}
|
145
|
+
update: Update %{model}
|
146
|
+
number:
|
147
|
+
currency:
|
148
|
+
format:
|
149
|
+
delimiter: ","
|
150
|
+
format: "%u%n"
|
151
|
+
precision: 2
|
152
|
+
separator: "."
|
153
|
+
significant: false
|
154
|
+
strip_insignificant_zeros: false
|
155
|
+
unit: "$"
|
156
|
+
format:
|
157
|
+
delimiter: ","
|
158
|
+
precision: 3
|
159
|
+
separator: "."
|
160
|
+
significant: false
|
161
|
+
strip_insignificant_zeros: false
|
162
|
+
human:
|
163
|
+
decimal_units:
|
164
|
+
format: "%n %u"
|
165
|
+
units:
|
166
|
+
billion: Billion
|
167
|
+
million: Million
|
168
|
+
quadrillion: Quadrillion
|
169
|
+
thousand: Thousand
|
170
|
+
trillion: Trillion
|
171
|
+
unit: ''
|
172
|
+
format:
|
173
|
+
delimiter: ''
|
174
|
+
precision: 3
|
175
|
+
significant: true
|
176
|
+
strip_insignificant_zeros: true
|
177
|
+
storage_units:
|
178
|
+
format: "%n %u"
|
179
|
+
units:
|
180
|
+
byte:
|
181
|
+
one: Byte
|
182
|
+
other: Bytes
|
183
|
+
gb: GB
|
184
|
+
kb: KB
|
185
|
+
mb: MB
|
186
|
+
tb: TB
|
187
|
+
percentage:
|
188
|
+
format:
|
189
|
+
delimiter: ''
|
190
|
+
format: "%n%"
|
191
|
+
precision:
|
192
|
+
format:
|
193
|
+
delimiter: ''
|
194
|
+
support:
|
195
|
+
array:
|
196
|
+
last_word_connector: ", and "
|
197
|
+
two_words_connector: " and "
|
198
|
+
words_connector: ", "
|
199
|
+
time:
|
200
|
+
am: am
|
201
|
+
formats:
|
202
|
+
default: "%a, %d %b %Y %H:%M:%S %z"
|
203
|
+
long: "%B %d, %Y %H:%M"
|
204
|
+
short: "%d %b %H:%M"
|
205
|
+
pm: pm
|
data/test/mongoid_test.rb
CHANGED
@@ -1,311 +1,313 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
#
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
#
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
#
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
1
|
+
require 'test_helper'
|
2
|
+
def mongoid_present?
|
3
|
+
require 'mongoid'
|
4
|
+
Mongoid.configure do |config|
|
5
|
+
config.connect_to("reform-mongoid-test")
|
6
|
+
end
|
7
|
+
true
|
8
|
+
rescue
|
9
|
+
false
|
10
|
+
end
|
11
|
+
|
12
|
+
if mongoid_present?
|
13
|
+
require 'reform/mongoid'
|
14
|
+
|
15
|
+
class Disc
|
16
|
+
include Mongoid::Document
|
17
|
+
field :title, type: String
|
18
|
+
has_many :tunes
|
19
|
+
has_and_belongs_to_many :musicians
|
20
|
+
end
|
21
|
+
|
22
|
+
class Musician
|
23
|
+
include Mongoid::Document
|
24
|
+
field :name, type: String
|
25
|
+
end
|
26
|
+
|
27
|
+
class Tune
|
28
|
+
include Mongoid::Document
|
29
|
+
include Mongoid::Timestamps
|
30
|
+
field :title, type: String
|
31
|
+
belongs_to :disc
|
32
|
+
belongs_to :musician
|
33
|
+
end
|
34
|
+
|
35
|
+
class MongoidTest < MiniTest::Spec
|
36
|
+
class TuneForm < Reform::Form
|
37
|
+
include Reform::Form::Mongoid
|
38
|
+
model :tune
|
39
|
+
|
40
|
+
property :title
|
41
|
+
property :created_at
|
42
|
+
|
43
|
+
validates_uniqueness_of :title, scope: [:disc_id, :musician_id]
|
44
|
+
validates :created_at, :presence => true # have another property to test if we mix up.
|
45
|
+
|
46
|
+
property :musician do
|
47
|
+
property :name
|
48
|
+
validates_uniqueness_of :name # this currently also tests if Form::AR is included as a feature.
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
let(:disc) { Disc.create(:title => "Damnation") }
|
53
|
+
let(:musician) { Musician.create(:name => "Opeth") }
|
54
|
+
let(:form) { TuneForm.new(Tune.new(:musician => Musician.new)) }
|
55
|
+
|
56
|
+
it { form.class.i18n_scope.must_equal :mongoid }
|
57
|
+
|
58
|
+
it "allows accessing the database" do
|
59
|
+
end
|
60
|
+
|
61
|
+
# uniqueness
|
62
|
+
it "has no errors on title when title is unique for the same musician and disc" do
|
63
|
+
form.validate("title" => "The Gargoyle", "musician_id" => musician.id, "disc" => disc.id, "created_at" => "November 6, 1966")
|
64
|
+
assert_empty form.errors[:title]
|
65
|
+
end
|
66
|
+
|
67
|
+
it "has errors on title when title is taken for the same musician and disc" do
|
68
|
+
skip "replace ActiveModel::Validations with our own, working and reusable gem."
|
69
|
+
Tune.create(title: "Windowpane", musician_id: musician.id, disc_id: disc.id)
|
70
|
+
form.validate("title" => "Windowpane", "musician_id" => musician.id, "disc" => disc)
|
71
|
+
refute_empty form.errors[:title]
|
72
|
+
end
|
73
|
+
|
74
|
+
# nested object taken.
|
75
|
+
it "is valid when musician name is unique" do
|
76
|
+
form.validate("musician" => {"name" => "Paul Gilbert"}, "title" => "The Gargoyle", "created_at" => "November 6, 1966").must_equal true
|
77
|
+
end
|
78
|
+
|
79
|
+
it "is invalid and shows error when taken" do
|
80
|
+
Tune.delete_all
|
81
|
+
Musician.create(:name => "Racer X")
|
82
|
+
|
83
|
+
form.validate("musician" => {"name" => "Racer X"}, "title" => "Ghost Inside My Skin").must_equal false
|
84
|
+
form.errors.messages.must_equal({:"musician.name"=>["is already taken"], :created_at => ["can't be blank"]})
|
85
|
+
end
|
86
|
+
|
87
|
+
it "works with Composition" do
|
88
|
+
form = Class.new(Reform::Form) do
|
89
|
+
include Reform::Form::Mongoid
|
90
|
+
include Reform::Form::Composition
|
91
|
+
|
92
|
+
property :name, :on => :musician
|
93
|
+
validates_uniqueness_of :name
|
94
|
+
end.new(:musician => Musician.new)
|
95
|
+
|
96
|
+
Musician.create(:name => "Bad Religion")
|
97
|
+
form.validate("name" => "Bad Religion").must_equal false
|
98
|
+
end
|
99
|
+
|
100
|
+
describe "#save" do
|
101
|
+
# TODO: test 1-n?
|
102
|
+
it "calls model.save" do
|
103
|
+
Musician.delete_all
|
104
|
+
form.validate("musician" => {"name" => "Bad Religion"}, "title" => "Ghost Inside My Skin")
|
105
|
+
form.save
|
106
|
+
Musician.where(:name => "Bad Religion").size.must_equal 1
|
107
|
+
end
|
108
|
+
|
109
|
+
it "doesn't call model.save when block is given" do
|
110
|
+
Musician.delete_all
|
111
|
+
form.validate("name" => "Bad Religion")
|
112
|
+
form.save {}
|
113
|
+
Musician.where(:name => "Bad Religion").size.must_equal 0
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
117
118
|
|
119
|
+
class PopulateWithActiveRecordTest < MiniTest::Spec
|
120
|
+
class DiscForm < Reform::Form
|
118
121
|
|
119
|
-
|
120
|
-
# class DiscForm < Reform::Form
|
122
|
+
property :title
|
121
123
|
|
122
|
-
|
124
|
+
collection :tunes, :populate_if_empty => Tune do
|
125
|
+
property :title
|
126
|
+
end
|
127
|
+
end
|
123
128
|
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
# end
|
129
|
+
let (:disc) { Disc.new(:tunes => []) }
|
130
|
+
it do
|
131
|
+
form = DiscForm.new(disc)
|
128
132
|
|
129
|
-
|
130
|
-
# it do
|
131
|
-
# form = DiscForm.new(disc)
|
133
|
+
form.validate("tunes" => [{"title" => "Straight From The Jacket"}])
|
132
134
|
|
133
|
-
#
|
135
|
+
# form populated.
|
136
|
+
form.tunes.size.must_equal 1
|
137
|
+
form.tunes[0].model.must_be_kind_of Tune
|
134
138
|
|
135
|
-
#
|
136
|
-
|
137
|
-
# form.tunes[0].model.must_be_kind_of Tune
|
139
|
+
# model NOT populated.
|
140
|
+
disc.tunes.must_equal []
|
138
141
|
|
139
|
-
# # model NOT populated.
|
140
|
-
# disc.tunes.must_equal []
|
141
142
|
|
143
|
+
form.sync
|
142
144
|
|
143
|
-
#
|
145
|
+
# form populated.
|
146
|
+
form.tunes.size.must_equal 1
|
147
|
+
form.tunes[0].model.must_be_kind_of Tune
|
144
148
|
|
145
|
-
#
|
146
|
-
|
147
|
-
|
149
|
+
# model also populated.
|
150
|
+
tune = disc.tunes[0]
|
151
|
+
disc.tunes.must_equal [tune]
|
152
|
+
tune.title.must_equal "Straight From The Jacket"
|
148
153
|
|
149
|
-
# # model also populated.
|
150
|
-
# tune = disc.tunes[0]
|
151
|
-
# disc.tunes.must_equal [tune]
|
152
|
-
# tune.title.must_equal "Straight From The Jacket"
|
153
154
|
|
155
|
+
# if ActiveRecord::VERSION::STRING !~ /^3.0/
|
156
|
+
# # saving saves association.
|
157
|
+
# form.save
|
158
|
+
#
|
159
|
+
# disc.reload
|
160
|
+
# tune = disc.tunes[0]
|
161
|
+
# disc.tunes.must_equal [tune]
|
162
|
+
# tune.title.must_equal "Straight From The Jacket"
|
163
|
+
# end
|
164
|
+
end
|
154
165
|
|
155
|
-
# # if ActiveRecord::VERSION::STRING !~ /^3.0/
|
156
|
-
# # # saving saves association.
|
157
|
-
# # form.save
|
158
|
-
# #
|
159
|
-
# # disc.reload
|
160
|
-
# # tune = disc.tunes[0]
|
161
|
-
# # disc.tunes.must_equal [tune]
|
162
|
-
# # tune.title.must_equal "Straight From The Jacket"
|
163
|
-
# # end
|
164
|
-
# end
|
165
166
|
|
167
|
+
describe "modifying 1., adding 2." do
|
168
|
+
let (:tune) { Tune.new(:title => "Part 2") }
|
169
|
+
let (:disc) { Disc.create.tap { |a| a.tunes << tune } }
|
166
170
|
|
167
|
-
|
168
|
-
|
169
|
-
# let (:disc) { Disc.create.tap { |a| a.tunes << tune } }
|
171
|
+
it do
|
172
|
+
form = DiscForm.new(disc)
|
170
173
|
|
171
|
-
|
172
|
-
|
174
|
+
id = disc.tunes[0].id
|
175
|
+
disc.tunes[0].persisted?.must_equal true
|
176
|
+
assert id.to_s.size > 0
|
173
177
|
|
174
|
-
|
175
|
-
# assert id > 0
|
178
|
+
form.validate("tunes" => [{"title" => "Part Two"}, {"title" => "Check For A Pulse"}])
|
176
179
|
|
177
|
-
#
|
180
|
+
# form populated.
|
181
|
+
form.tunes.size.must_equal 2
|
182
|
+
form.tunes[0].model.must_be_kind_of Tune
|
183
|
+
form.tunes[1].model.must_be_kind_of Tune
|
178
184
|
|
179
|
-
#
|
180
|
-
|
181
|
-
# form.tunes[0].model.must_be_kind_of Tune
|
182
|
-
# form.tunes[1].model.must_be_kind_of Tune
|
185
|
+
# model NOT populated.
|
186
|
+
disc.tunes.must_equal [tune]
|
183
187
|
|
184
|
-
# # model NOT populated.
|
185
|
-
# disc.tunes.must_equal [tune]
|
186
188
|
|
189
|
+
form.sync
|
187
190
|
|
188
|
-
#
|
191
|
+
# form populated.
|
192
|
+
form.tunes.size.must_equal 2
|
189
193
|
|
190
|
-
#
|
191
|
-
|
194
|
+
# model also populated.
|
195
|
+
disc.tunes.size.must_equal 2
|
192
196
|
|
193
|
-
#
|
194
|
-
|
197
|
+
# corrected title
|
198
|
+
disc.tunes[0].title.must_equal "Part Two"
|
199
|
+
# ..but same tune.
|
200
|
+
disc.tunes[0].id.must_equal id
|
195
201
|
|
196
|
-
#
|
197
|
-
|
198
|
-
#
|
199
|
-
|
202
|
+
# and a new tune.
|
203
|
+
disc.tunes[1].title.must_equal "Check For A Pulse"
|
204
|
+
disc.tunes[1].persisted?.must_equal true # TODO: with << strategy, this shouldn't be saved.
|
205
|
+
end
|
200
206
|
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
207
|
+
describe 'using nested_models_attributes to modify nested collection' do
|
208
|
+
class ActiveModelDiscForm < Reform::Form
|
209
|
+
include Reform::Form::ActiveModel
|
210
|
+
include Reform::Form::ActiveModel::FormBuilderMethods
|
205
211
|
|
206
|
-
|
207
|
-
# class ActiveModelDiscForm < Reform::Form
|
208
|
-
# include Reform::Form::ActiveModel
|
209
|
-
# include Reform::Form::ActiveModel::FormBuilderMethods
|
212
|
+
property :title
|
210
213
|
|
211
|
-
|
214
|
+
collection :tunes, :populate_if_empty => Tune do
|
215
|
+
property :title
|
216
|
+
end
|
217
|
+
end
|
212
218
|
|
213
|
-
|
214
|
-
|
215
|
-
# end
|
216
|
-
# end
|
219
|
+
let (:disc) { Disc.create(:title => 'Greatest Hits') }
|
220
|
+
let (:form) { ActiveModelDiscForm.new(disc) }
|
217
221
|
|
218
|
-
|
219
|
-
|
222
|
+
it do
|
223
|
+
form.validate('tunes_attributes' => {'0' => {'title' => 'Tango'}})
|
220
224
|
|
221
|
-
#
|
222
|
-
|
225
|
+
# form populated.
|
226
|
+
form.tunes.size.must_equal 1
|
227
|
+
form.tunes[0].model.must_be_kind_of Tune
|
228
|
+
form.tunes[0].title.must_equal 'Tango'
|
223
229
|
|
224
|
-
#
|
225
|
-
|
226
|
-
# form.tunes[0].model.must_be_kind_of Tune
|
227
|
-
# form.tunes[0].title.must_equal 'Tango'
|
230
|
+
# model NOT populated.
|
231
|
+
disc.tunes.must_equal []
|
228
232
|
|
229
|
-
|
230
|
-
# disc.tunes.must_equal []
|
233
|
+
form.save
|
231
234
|
|
232
|
-
#
|
235
|
+
# nested model persisted.
|
236
|
+
first_tune = disc.tunes[0]
|
237
|
+
first_tune.persisted?.must_equal true
|
238
|
+
assert first_tune.id.to_s.size > 0
|
233
239
|
|
234
|
-
#
|
235
|
-
|
236
|
-
# assert first_tune.id > 0
|
240
|
+
# form populated.
|
241
|
+
form.tunes.size.must_equal 1
|
237
242
|
|
238
|
-
#
|
239
|
-
|
243
|
+
# model also populated.
|
244
|
+
disc.tunes.size.must_equal 1
|
245
|
+
disc.tunes[0].title.must_equal 'Tango'
|
240
246
|
|
241
|
-
|
242
|
-
|
243
|
-
# disc.tunes[0].title.must_equal 'Tango'
|
247
|
+
form = ActiveModelDiscForm.new(disc)
|
248
|
+
form.validate('tunes_attributes' => {'0' => {'id' => first_tune.id, 'title' => 'Tango nuevo'}, '1' => {'title' => 'Waltz'}})
|
244
249
|
|
245
|
-
#
|
246
|
-
|
250
|
+
# form populated.
|
251
|
+
form.tunes.size.must_equal 2
|
252
|
+
form.tunes[0].model.must_be_kind_of Tune
|
253
|
+
form.tunes[1].model.must_be_kind_of Tune
|
254
|
+
form.tunes[0].title.must_equal 'Tango nuevo'
|
255
|
+
form.tunes[1].title.must_equal 'Waltz'
|
247
256
|
|
248
|
-
#
|
249
|
-
|
250
|
-
|
251
|
-
# form.tunes[1].model.must_be_kind_of Tune
|
252
|
-
# form.tunes[0].title.must_equal 'Tango nuevo'
|
253
|
-
# form.tunes[1].title.must_equal 'Waltz'
|
257
|
+
# model NOT populated.
|
258
|
+
disc.tunes.size.must_equal 1
|
259
|
+
disc.tunes[0].title.must_equal 'Tango'
|
254
260
|
|
255
|
-
|
256
|
-
# disc.tunes.size.must_equal 1
|
257
|
-
# disc.tunes[0].title.must_equal 'Tango'
|
261
|
+
form.save
|
258
262
|
|
259
|
-
#
|
263
|
+
# form populated.
|
264
|
+
form.tunes.size.must_equal 2
|
260
265
|
|
261
|
-
#
|
262
|
-
|
266
|
+
# model also populated.
|
267
|
+
disc.tunes.size.must_equal 2
|
268
|
+
disc.tunes[0].id.must_equal first_tune.id
|
269
|
+
disc.tunes[0].persisted?.must_equal true
|
270
|
+
disc.tunes[1].persisted?.must_equal true
|
271
|
+
disc.tunes[0].title.must_equal 'Tango nuevo'
|
272
|
+
disc.tunes[1].title.must_equal 'Waltz'
|
273
|
+
end
|
274
|
+
end
|
275
|
+
end
|
263
276
|
|
264
|
-
#
|
265
|
-
#
|
266
|
-
#
|
267
|
-
# disc.tunes[0].persisted?.must_equal true
|
268
|
-
# disc.tunes[1].persisted?.must_equal true
|
269
|
-
# disc.tunes[0].title.must_equal 'Tango nuevo'
|
270
|
-
# disc.tunes[1].title.must_equal 'Waltz'
|
271
|
-
# end
|
272
|
-
# end
|
273
|
-
# end
|
277
|
+
# it do
|
278
|
+
# a=Disc.new
|
279
|
+
# a.tunes << Tune.new(title: "Old What's His Name") # Tune does not get persisted.
|
274
280
|
|
275
|
-
#
|
276
|
-
# # a=Disc.new
|
277
|
-
# # a.tunes << Tune.new(title: "Old What's His Name") # Tune does not get persisted.
|
281
|
+
# a.tunes[1] = Tune.new(title: "Permanent Rust")
|
278
282
|
|
279
|
-
#
|
283
|
+
# puts "@@@"
|
284
|
+
# puts a.tunes.inspect
|
280
285
|
|
281
|
-
#
|
282
|
-
#
|
286
|
+
# puts "---"
|
287
|
+
# a.save
|
288
|
+
# puts a.tunes.inspect
|
283
289
|
|
284
|
-
#
|
285
|
-
# # a.save
|
286
|
-
# # puts a.tunes.inspect
|
290
|
+
# b = a.tunes.first
|
287
291
|
|
288
|
-
#
|
292
|
+
# a.tunes = [Tune.new(title:"Biomag")]
|
293
|
+
# puts "\\\\"
|
294
|
+
# a.save
|
295
|
+
# a.reload
|
296
|
+
# puts a.tunes.inspect
|
297
|
+
|
298
|
+
# b.reload
|
299
|
+
# puts "#{b.inspect}, #{b.persisted?}"
|
289
300
|
|
290
|
-
# # a.tunes = [Tune.new(title:"Biomag")]
|
291
|
-
# # puts "\\\\"
|
292
|
-
# # a.save
|
293
|
-
# # a.reload
|
294
|
-
# # puts a.tunes.inspect
|
295
301
|
|
296
|
-
#
|
297
|
-
#
|
302
|
+
# a.tunes = [a.tunes.first, Tune.new(title: "Count Down")]
|
303
|
+
# b = a.tunes.first
|
304
|
+
# puts ":::::"
|
305
|
+
# a.save
|
306
|
+
# a.reload
|
307
|
+
# puts a.tunes.inspect
|
298
308
|
|
299
|
-
|
300
|
-
#
|
301
|
-
#
|
302
|
-
|
303
|
-
|
304
|
-
# # a.reload
|
305
|
-
# # puts a.tunes.inspect
|
306
|
-
|
307
|
-
# # b.reload
|
308
|
-
# # puts "#{b.inspect}, #{b.persisted?}"
|
309
|
-
# # end
|
310
|
-
# end
|
311
|
-
# end
|
309
|
+
# b.reload
|
310
|
+
# puts "#{b.inspect}, #{b.persisted?}"
|
311
|
+
# end
|
312
|
+
end
|
313
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: reform
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.0.
|
4
|
+
version: 2.0.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Nick Sutterer
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2015-07-
|
12
|
+
date: 2015-07-13 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: disposable
|
@@ -196,7 +196,6 @@ files:
|
|
196
196
|
- Rakefile
|
197
197
|
- TODO.md
|
198
198
|
- database.sqlite3
|
199
|
-
- gemfiles/Gemfile.rails-3.0
|
200
199
|
- gemfiles/Gemfile.rails-3.1
|
201
200
|
- gemfiles/Gemfile.rails-3.2
|
202
201
|
- gemfiles/Gemfile.rails-4.0
|
@@ -230,6 +229,7 @@ files:
|
|
230
229
|
- lib/reform/schema.rb
|
231
230
|
- lib/reform/version.rb
|
232
231
|
- reform.gemspec
|
232
|
+
- test/active_model_custom_validation_translations_test.rb
|
233
233
|
- test/active_model_test.rb
|
234
234
|
- test/active_record_test.rb
|
235
235
|
- test/benchmarking.rb
|
@@ -319,6 +319,7 @@ signing_key:
|
|
319
319
|
specification_version: 4
|
320
320
|
summary: Form object decoupled from models with validation, population and presentation.
|
321
321
|
test_files:
|
322
|
+
- test/active_model_custom_validation_translations_test.rb
|
322
323
|
- test/active_model_test.rb
|
323
324
|
- test/active_record_test.rb
|
324
325
|
- test/benchmarking.rb
|