freeform 1.0.11 → 2.0.0
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 +8 -8
- data/Gemfile.lock +3 -3
- data/README.md +16 -17
- data/lib/freeform/form/date_params_filter.rb +34 -0
- data/lib/freeform/form/model.rb +56 -0
- data/lib/freeform/form/nested.rb +64 -39
- data/lib/freeform/form/property.rb +31 -75
- data/lib/freeform/form/validation.rb +48 -34
- data/lib/freeform/form.rb +31 -42
- data/lib/freeform/version.rb +1 -1
- data/spec/acceptance_spec.rb +140 -260
- data/spec/builder/builder_spec.rb +23 -41
- data/spec/builder/view_helper_spec.rb +7 -16
- data/spec/dummy/app/forms/project_form.rb +16 -2
- data/spec/dummy/app/models/company.rb +2 -2
- data/spec/dummy/app/models/milestone.rb +3 -3
- data/spec/dummy/app/models/project.rb +3 -3
- data/spec/dummy/app/models/task.rb +2 -2
- data/spec/dummy/db/migrate/20110710143903_initial_tables.rb +5 -5
- data/spec/dummy/db/schema.rb +6 -4
- data/spec/dummy/db/test.sqlite3 +0 -0
- data/spec/form/date_params_filter_spec.rb +51 -0
- data/spec/form/form_input_key_spec.rb +9 -11
- data/spec/form/model_spec.rb +244 -0
- data/spec/form/nested_spec.rb +108 -138
- data/spec/form/persistence_spec.rb +304 -0
- data/spec/form/property_spec.rb +104 -256
- data/spec/form/validation_spec.rb +114 -127
- data/spec/spec_helper.rb +6 -0
- metadata +10 -10
- data/spec/dummy/app/forms/milestone_form.rb +0 -4
- data/spec/dummy/app/forms/task_form.rb +0 -11
- data/spec/dummy/log/test.log +0 -111133
- data/spec/persistence_spec.rb +0 -645
checksums.yaml
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
---
|
2
2
|
!binary "U0hBMQ==":
|
3
3
|
metadata.gz: !binary |-
|
4
|
-
|
4
|
+
ZmM3NmYwN2Q0MzBjODk2MTRlNzA3NjU0YWRjMWI1YTY3MjMxNjI1Yw==
|
5
5
|
data.tar.gz: !binary |-
|
6
|
-
|
6
|
+
YjVmOTEzMDZmNTNiNmQ2MGIwZTllMGRjMmI5NWU4ODFiYWFhMzhjMw==
|
7
7
|
SHA512:
|
8
8
|
metadata.gz: !binary |-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
YjU2ZDBlNTA2ZjNkZDdjZjgyMzY4NTg0NWRjZjM0ZTI0NjUwNWI5ZjZmZWMy
|
10
|
+
ZjUxNWFhZWQ2ZjZmODMyYzdmYjI4ZjJkNGIzNmEyYjhiNzNkMzMyY2E3NDMx
|
11
|
+
ZDgyOWI2M2ZlNjZiMTQxNDBkYzdjZWVmOTg0NzE3YzlhMDVlMWY=
|
12
12
|
data.tar.gz: !binary |-
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
NTZhNjZjYmEzZWQxOWI4YTZmMjlhMjg5MTQ4OGJiYWY1MzQyZmE3NDVlYjA0
|
14
|
+
M2I4MGM2NDhkZGRkODdiYjZjMTU0YWRhMzRhNGQ5OTEyNDU4OTZkNTI0ZDJm
|
15
|
+
OTNiMTc0ZmU1YzZhMTE2ODBiZTIxOTQ4NTk2NWY2ZTA5YjA2NGQ=
|
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
freeform (
|
4
|
+
freeform (2.0.0rc1)
|
5
5
|
activemodel
|
6
6
|
formtastic
|
7
7
|
rails (>= 3.2.0)
|
@@ -46,7 +46,7 @@ GEM
|
|
46
46
|
rack-test (>= 0.5.4)
|
47
47
|
selenium-webdriver (~> 2.0)
|
48
48
|
xpath (~> 0.1.4)
|
49
|
-
childprocess (0.5.
|
49
|
+
childprocess (0.5.3)
|
50
50
|
ffi (~> 1.0, >= 1.0.11)
|
51
51
|
diff-lcs (1.2.5)
|
52
52
|
erubis (2.7.0)
|
@@ -110,7 +110,7 @@ GEM
|
|
110
110
|
rspec-core (~> 2.14.0)
|
111
111
|
rspec-expectations (~> 2.14.0)
|
112
112
|
rspec-mocks (~> 2.14.0)
|
113
|
-
rubyzip (1.1.
|
113
|
+
rubyzip (1.1.3)
|
114
114
|
selenium-webdriver (2.41.0)
|
115
115
|
childprocess (>= 0.5.0)
|
116
116
|
multi_json (~> 1.0)
|
data/README.md
CHANGED
@@ -10,11 +10,13 @@ FreeForm is designed primarily with Rails in mind, but it should work on any Rub
|
|
10
10
|
|
11
11
|
**FreeForm will not work with Ryan Bate's nested_form gem, but provides its own identical behavior**
|
12
12
|
|
13
|
+
Please use/migrate to version 2.x of this gem. Version 1.x will no longer be supported, and version 2.x provides a better DSL, additional features, and cleaner source code.
|
14
|
+
|
13
15
|
## Installation
|
14
16
|
|
15
17
|
Add this line to your application's Gemfile:
|
16
18
|
|
17
|
-
gem 'freeform', '>=
|
19
|
+
gem 'freeform', '>= 2.0.0'
|
18
20
|
|
19
21
|
And then execute:
|
20
22
|
|
@@ -198,19 +200,18 @@ class UserForm < FreeForm::Form
|
|
198
200
|
property :username, :on => :user
|
199
201
|
property :email, :on => :user
|
200
202
|
|
201
|
-
has_many :phone_numbers
|
203
|
+
has_many :phone_numbers do
|
204
|
+
form_models :phone
|
205
|
+
|
206
|
+
property :area_code, :on => :phone
|
207
|
+
property :number, :on => :phone
|
208
|
+
end
|
202
209
|
|
203
210
|
def phone_initializer
|
204
211
|
{ :phone => user.phone_numbers.build }
|
205
212
|
end
|
206
213
|
end
|
207
214
|
|
208
|
-
class PhoneNumberForm < FreeForm::Form
|
209
|
-
form_models :phone
|
210
|
-
|
211
|
-
property :area_code, :on => :phone
|
212
|
-
property :number, :on => :phone
|
213
|
-
end
|
214
215
|
```
|
215
216
|
**Note:** The method `nested_form` is also aliased as `has_many` and `has_one`, if you prefer the expressiveness of that syntax. The functionality is the same in any case.
|
216
217
|
|
@@ -235,18 +236,16 @@ class UserForm < FreeForm::Form
|
|
235
236
|
property :username, :on => :user
|
236
237
|
property :email, :on => :user
|
237
238
|
|
238
|
-
has_many :phone_numbers
|
239
|
+
has_many :phone_numbers do
|
240
|
+
form_models :phone
|
239
241
|
|
240
|
-
|
241
|
-
|
242
|
+
property :area_code, :on => :phone
|
243
|
+
property :number, :on => :phone
|
242
244
|
end
|
243
|
-
end
|
244
|
-
|
245
|
-
class PhoneNumberForm < FreeForm::Form
|
246
|
-
form_models :phone
|
247
245
|
|
248
|
-
|
249
|
-
|
246
|
+
def phone_initializer
|
247
|
+
{ :phone => user.phone_numbers.build }
|
248
|
+
end
|
250
249
|
end
|
251
250
|
|
252
251
|
form = UserForm.new(:user => current_user)
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module FreeForm
|
2
|
+
class DateParamsFilter
|
3
|
+
def initialize(*args)
|
4
|
+
end
|
5
|
+
|
6
|
+
def call(params)
|
7
|
+
date_attributes = {}
|
8
|
+
|
9
|
+
params.each do |attribute, value|
|
10
|
+
if value.is_a?(Hash)
|
11
|
+
call(value) # TODO: #validate should only handle local form params.
|
12
|
+
elsif matches = attribute.match(/^(\w+)\(.i\)$/)
|
13
|
+
date_attribute = matches[1]
|
14
|
+
date_attributes[date_attribute] = params_to_date(
|
15
|
+
params.delete("#{date_attribute}(1i)"),
|
16
|
+
params.delete("#{date_attribute}(2i)"),
|
17
|
+
params.delete("#{date_attribute}(3i)")
|
18
|
+
)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
params.merge!(date_attributes)
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
def params_to_date(year, month, day)
|
26
|
+
day ||= 1 # FIXME: is that really what we want? test.
|
27
|
+
begin # TODO: test fails.
|
28
|
+
return Date.new(year.to_i, month.to_i, day.to_i)
|
29
|
+
rescue ArgumentError => e
|
30
|
+
return nil
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
require 'freeform/form/date_params_filter'
|
2
|
+
|
3
|
+
module FreeForm
|
4
|
+
module Model
|
5
|
+
def self.included(base)
|
6
|
+
base.extend(ClassMethods)
|
7
|
+
end
|
8
|
+
|
9
|
+
module ClassMethods
|
10
|
+
include Forwardable
|
11
|
+
|
12
|
+
def models
|
13
|
+
@models ||= []
|
14
|
+
end
|
15
|
+
|
16
|
+
def child_models
|
17
|
+
@child_models ||= []
|
18
|
+
end
|
19
|
+
|
20
|
+
def declared_models(*names)
|
21
|
+
names.each do |name|
|
22
|
+
declared_model(name)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
alias_method :form_models, :declared_models
|
26
|
+
|
27
|
+
def declared_model(name, opts={})
|
28
|
+
attr_accessor name
|
29
|
+
@models = (@models || []) << name
|
30
|
+
end
|
31
|
+
alias_method :form_model, :declared_model
|
32
|
+
|
33
|
+
def child_model(name, opts={}, &block)
|
34
|
+
declared_model(name)
|
35
|
+
@child_models = (@child_models || []) << name
|
36
|
+
|
37
|
+
# Defines an initializer method, such as 'initialize_address'
|
38
|
+
# that can be called on form initialization to build the model
|
39
|
+
define_method("initialize_#{name}") do
|
40
|
+
instance_variable_set("@#{name}", instance_eval(&block))
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def models
|
46
|
+
Array.new.tap do |a|
|
47
|
+
self.class.models.each do |form_model|
|
48
|
+
a << send(form_model)
|
49
|
+
end
|
50
|
+
a.flatten!
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
private
|
55
|
+
end
|
56
|
+
end
|
data/lib/freeform/form/nested.rb
CHANGED
@@ -9,64 +9,88 @@ module FreeForm
|
|
9
9
|
#------------------------------------------------------------------------
|
10
10
|
attr_accessor :nested_forms
|
11
11
|
|
12
|
-
def nested_form(attribute, options={})
|
13
|
-
|
14
|
-
|
15
|
-
@nested_forms.merge!({:"#{attribute}" => nested_form_class})
|
12
|
+
def nested_form(attribute, options={}, &block)
|
13
|
+
# Initialize the instance variables on the parent class
|
14
|
+
initialize_instance_variables(attribute)
|
16
15
|
|
17
|
-
# Define
|
18
|
-
|
16
|
+
# Define new nested class
|
17
|
+
klass = define_nested_class(attribute, options, &block)
|
19
18
|
|
20
|
-
#
|
21
|
-
define_nested_model_methods(attribute,
|
22
|
-
|
23
|
-
# Setup Handling for nested attributes
|
24
|
-
define_nested_attribute_methods(attribute, nested_form_class)
|
19
|
+
# Define methods for working with nested models
|
20
|
+
define_nested_model_methods(attribute, klass)
|
25
21
|
end
|
26
22
|
alias_method :has_many, :nested_form
|
27
23
|
alias_method :has_one, :nested_form
|
28
24
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
def define_nested_model_methods(attribute, form_class, options={})
|
33
|
-
singularized_attribute = attribute.to_s.singularize.to_s
|
25
|
+
protected
|
26
|
+
def initialize_instance_variables(attribute)
|
27
|
+
declared_model attribute
|
34
28
|
|
35
|
-
# Example: form.addresses will return all nested address forms
|
36
29
|
define_method(:"#{attribute}") do
|
37
30
|
value = instance_variable_get("@nested_#{attribute}")
|
38
31
|
value ||= []
|
39
32
|
instance_variable_set("@nested_#{attribute}", value)
|
40
33
|
end
|
34
|
+
end
|
41
35
|
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
36
|
+
def register_nested_form(klass)
|
37
|
+
@nested_forms ||= []
|
38
|
+
@nested_forms << klass
|
39
|
+
end
|
46
40
|
|
47
|
-
|
48
|
-
|
41
|
+
def parent_class
|
42
|
+
self
|
43
|
+
end
|
49
44
|
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
end
|
54
|
-
initializer ||= {}
|
45
|
+
def attribute_to_form_class(attribute)
|
46
|
+
singularized_attribute(attribute).camelize
|
47
|
+
end
|
55
48
|
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
value << form_model
|
61
|
-
instance_variable_set("@nested_#{attribute}", value)
|
49
|
+
def define_nested_class(attribute, options={}, &block)
|
50
|
+
# Define new nested class
|
51
|
+
klass = Class.new(FreeForm::Form) do
|
52
|
+
end
|
62
53
|
|
63
|
-
|
54
|
+
# Add whatever passed in methods, properties, etc. to the class
|
55
|
+
if block_given?
|
56
|
+
klass.class_eval(&block)
|
64
57
|
end
|
65
|
-
|
58
|
+
|
59
|
+
# Set the class name
|
60
|
+
form_class = attribute_to_form_class(attribute)
|
61
|
+
parent_class.const_set(form_class, klass)
|
62
|
+
|
63
|
+
# Register the class as being nested under the current class
|
64
|
+
register_nested_form(klass)
|
65
|
+
klass
|
66
66
|
end
|
67
67
|
|
68
|
-
|
69
|
-
|
68
|
+
def define_nested_model_methods(attribute, form_class, options={})
|
69
|
+
singular = singularized_attribute(attribute)
|
70
|
+
|
71
|
+
# Example: form.build_addresses (optional custom initializer)
|
72
|
+
define_method(:"build_#{attribute}") do |initializer=nil|
|
73
|
+
initializer ||= self.send("#{singular}_initializer")
|
74
|
+
|
75
|
+
form_class.new(initializer).tap do |obj|
|
76
|
+
# Add new object to parent model collection (e.g. the new address is in parent.addresses)
|
77
|
+
current_models = self.send(attribute)
|
78
|
+
current_models ||= []
|
79
|
+
current_models << obj
|
80
|
+
self.send("#{attribute}=", current_models)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
alias_method :"build_#{singular}", :"build_#{attribute}"
|
84
|
+
|
85
|
+
# Define methods for working with nested models
|
86
|
+
define_nested_attribute_methods(attribute, form_class)
|
87
|
+
end
|
88
|
+
|
89
|
+
def singularized_attribute(attribute)
|
90
|
+
attribute.to_s.singularize
|
91
|
+
end
|
92
|
+
|
93
|
+
#TODO: Clean up this method!
|
70
94
|
def define_nested_attribute_methods(attribute, nested_form_class)
|
71
95
|
# Equivalent of "address_attributes=" for "address" attribute
|
72
96
|
define_method(:"#{attribute}_attributes=") do |params|
|
@@ -79,12 +103,13 @@ module FreeForm
|
|
79
103
|
model.fill(attributes)
|
80
104
|
end
|
81
105
|
end
|
82
|
-
end
|
106
|
+
end
|
83
107
|
end
|
84
108
|
|
85
109
|
# Instance Methods
|
86
110
|
#--------------------------------------------------------------------------
|
87
111
|
protected
|
112
|
+
#TODO: Clean up this method!
|
88
113
|
def build_models_from_param_count(attribute, params)
|
89
114
|
# Get the difference between sets of params passed and current form objects
|
90
115
|
num_param_models = params.length
|
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'freeform/form/date_params_filter'
|
2
|
+
|
1
3
|
module FreeForm
|
2
4
|
module Property
|
3
5
|
def self.included(base)
|
@@ -7,43 +9,6 @@ module FreeForm
|
|
7
9
|
module ClassMethods
|
8
10
|
include Forwardable
|
9
11
|
|
10
|
-
# Models
|
11
|
-
#------------------------------------------------------------------------
|
12
|
-
def models
|
13
|
-
@models ||= []
|
14
|
-
end
|
15
|
-
|
16
|
-
def child_models
|
17
|
-
@child_models ||= []
|
18
|
-
end
|
19
|
-
|
20
|
-
def declared_model(name, opts={})
|
21
|
-
@models ||= []
|
22
|
-
@models << name
|
23
|
-
attr_accessor name
|
24
|
-
end
|
25
|
-
alias_method :form_model, :declared_model
|
26
|
-
|
27
|
-
def declared_models(*names)
|
28
|
-
names.each do |name|
|
29
|
-
declared_model(name)
|
30
|
-
end
|
31
|
-
end
|
32
|
-
alias_method :form_models, :declared_models
|
33
|
-
|
34
|
-
def child_model(name, opts={}, &block)
|
35
|
-
@models ||= []
|
36
|
-
@models << name
|
37
|
-
@child_models ||= []
|
38
|
-
@child_models << name
|
39
|
-
attr_accessor name
|
40
|
-
define_method("initialize_#{name}") do
|
41
|
-
instance_variable_set("@#{name}", instance_eval(&block))
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
# Properties
|
46
|
-
#------------------------------------------------------------------------
|
47
12
|
def property_mappings
|
48
13
|
# Take the form of {:property => {:model => model, :field => field, :ignore_blank => false}}
|
49
14
|
@property_mappings ||= Hash.new
|
@@ -89,57 +54,48 @@ module FreeForm
|
|
89
54
|
end
|
90
55
|
end
|
91
56
|
|
92
|
-
attr_accessor :parent_form
|
93
|
-
|
94
|
-
class DateParamsFilter
|
95
|
-
def call(params)
|
96
|
-
date_attributes = {}
|
97
|
-
|
98
|
-
params.each do |attribute, value|
|
99
|
-
if value.is_a?(Hash)
|
100
|
-
call(value) # TODO: #validate should only handle local form params.
|
101
|
-
elsif matches = attribute.match(/^(\w+)\(.i\)$/)
|
102
|
-
date_attribute = matches[1]
|
103
|
-
date_attributes[date_attribute] = params_to_date(
|
104
|
-
params.delete("#{date_attribute}(1i)"),
|
105
|
-
params.delete("#{date_attribute}(2i)"),
|
106
|
-
params.delete("#{date_attribute}(3i)")
|
107
|
-
)
|
108
|
-
end
|
109
|
-
end
|
110
|
-
params.merge!(date_attributes)
|
111
|
-
end
|
112
|
-
|
113
|
-
private
|
114
|
-
def params_to_date(year, month, day)
|
115
|
-
day ||= 1 # FIXME: is that really what we want? test.
|
116
|
-
begin # TODO: test fails.
|
117
|
-
return Date.new(year.to_i, month.to_i, day.to_i)
|
118
|
-
rescue ArgumentError => e
|
119
|
-
return nil
|
120
|
-
end
|
121
|
-
end
|
122
|
-
end
|
123
|
-
|
124
57
|
def assign_params(params)
|
125
|
-
|
126
|
-
|
127
|
-
|
58
|
+
self.tap do |s|
|
59
|
+
FreeForm::DateParamsFilter.new.call(params)
|
60
|
+
before_assign_params(params)
|
61
|
+
params.each_pair do |attribute, value|
|
62
|
+
assign_attribute(attribute, value)
|
63
|
+
end
|
64
|
+
after_assign_params(params)
|
128
65
|
end
|
129
|
-
self
|
130
66
|
end
|
131
67
|
alias_method :assign_attributes, :assign_params
|
132
68
|
alias_method :populate, :assign_params
|
133
69
|
alias_method :fill, :assign_params
|
134
70
|
|
71
|
+
def before_assign_params(params)
|
72
|
+
end
|
73
|
+
alias_method :before_assign_attributes, :before_assign_params
|
74
|
+
alias_method :before_populate, :before_assign_params
|
75
|
+
alias_method :before_fill, :before_assign_params
|
76
|
+
|
77
|
+
def after_assign_params(params)
|
78
|
+
end
|
79
|
+
alias_method :after_assign_attributes, :after_assign_params
|
80
|
+
alias_method :after_populate, :after_assign_params
|
81
|
+
alias_method :after_fill, :after_assign_params
|
82
|
+
|
83
|
+
def model_property_mappings
|
84
|
+
self.class.property_mappings
|
85
|
+
end
|
86
|
+
|
135
87
|
private
|
136
88
|
def assign_attribute(attribute, value)
|
137
89
|
self.send :"#{attribute}=", value unless ignore?(attribute, value)
|
138
90
|
end
|
139
91
|
|
140
92
|
def ignore?(attribute, value)
|
141
|
-
mapping =
|
142
|
-
|
93
|
+
mapping = model_property_mappings[attribute.to_sym]
|
94
|
+
if mapping.present?
|
95
|
+
mapping[:ignore_blank] && value.blank?
|
96
|
+
else
|
97
|
+
false
|
98
|
+
end
|
143
99
|
end
|
144
100
|
end
|
145
101
|
end
|
@@ -6,59 +6,73 @@ module FreeForm
|
|
6
6
|
end
|
7
7
|
|
8
8
|
module ClassMethods
|
9
|
+
def validate_nested_forms
|
10
|
+
validate :validate_nested_forms
|
11
|
+
end
|
12
|
+
|
9
13
|
def validate_models
|
10
|
-
validate :
|
14
|
+
validate :validate_component_models
|
11
15
|
end
|
12
16
|
end
|
13
17
|
|
14
18
|
protected
|
15
|
-
def
|
16
|
-
|
17
|
-
if send(form_model).is_a?(Array)
|
18
|
-
# If it's an array, we're dealing with nested forms
|
19
|
-
errors.add(:base, "has invalid nested forms") unless validate_nested_forms(send(form_model))
|
20
|
-
else
|
21
|
-
# Otherwise, validate the form object
|
22
|
-
validate_form_model(form_model)
|
23
|
-
end
|
24
|
-
end
|
19
|
+
def validate_nested_forms
|
20
|
+
models.each { |m| validate_nested_form(m) if m.is_a?(FreeForm::Form) }
|
25
21
|
end
|
26
22
|
|
27
|
-
|
28
|
-
|
29
|
-
form_validity = true
|
30
|
-
form_array.each do |model|
|
31
|
-
destroyed = model.respond_to?(:marked_for_destruction?) ? model.marked_for_destruction? : false
|
32
|
-
unless model.valid? || destroyed
|
33
|
-
form_validity = false
|
34
|
-
end
|
35
|
-
end
|
36
|
-
form_validity
|
23
|
+
def validate_component_models
|
24
|
+
models.each { |m| validate_model(m) unless m.is_a?(FreeForm::Form) }
|
37
25
|
end
|
38
26
|
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
return model.valid?
|
27
|
+
private
|
28
|
+
def validate_nested_form(form)
|
29
|
+
errors.add(:base, "has invalid nested forms") unless marked_for_destruction_or_valid?(form)
|
43
30
|
end
|
44
31
|
|
45
|
-
def
|
46
|
-
model = send(form_model)
|
32
|
+
def validate_model(model)
|
47
33
|
model.valid?
|
34
|
+
add_model_errors_to_form(model)
|
35
|
+
end
|
36
|
+
|
37
|
+
def marked_for_destruction_or_valid?(form)
|
38
|
+
form_marked_for_destruction?(form) || form.valid?
|
39
|
+
end
|
40
|
+
|
41
|
+
def form_marked_for_destruction?(form)
|
42
|
+
form.respond_to?(:marked_for_destruction?) ? form.marked_for_destruction? : false
|
43
|
+
end
|
44
|
+
|
45
|
+
def add_model_errors_to_form(model)
|
48
46
|
model.errors.each do |error, message|
|
49
|
-
|
50
|
-
|
51
|
-
|
47
|
+
add_error_to_form(model, error, message)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def add_error_to_form(model, error, message)
|
52
|
+
field = find_form_field_from_model_field(model, error)
|
53
|
+
if field
|
54
|
+
errors.add(field, message)
|
52
55
|
end
|
53
56
|
end
|
54
57
|
|
55
|
-
def find_form_field_from_model_field(model,
|
56
|
-
|
57
|
-
|
58
|
+
def find_form_field_from_model_field(model, error_field)
|
59
|
+
model_property_mappings.each_pair do |property, attributes|
|
60
|
+
model_sym = model_symbol_from_model(model)
|
61
|
+
field_sym = error_field.to_sym
|
62
|
+
|
63
|
+
if (attributes[:model] == model_sym) && (attributes[:field] == field_sym)
|
58
64
|
return property
|
59
65
|
end
|
60
66
|
end
|
61
|
-
|
67
|
+
nil
|
68
|
+
end
|
69
|
+
|
70
|
+
def model_symbol_from_model(model)
|
71
|
+
models_as_symbols.find { |sym| return sym if send(sym) == model }
|
72
|
+
end
|
73
|
+
|
74
|
+
def models_as_symbols
|
75
|
+
self.class.models.map { |x| x.to_sym }
|
62
76
|
end
|
63
77
|
end
|
64
78
|
end
|