freeform 0.0.4 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +8 -17
- data/Gemfile +1 -1
- data/Gemfile.lock +150 -0
- data/MIT-LICENSE +20 -0
- data/README.md +31 -43
- data/Rakefile +32 -1
- data/freeform.gemspec +22 -15
- data/lib/freeform/builder/builder_mixin.rb +111 -0
- data/lib/freeform/builder/builders.rb +32 -0
- data/lib/freeform/builder/engine.rb +14 -0
- data/lib/freeform/builder/view_helper.rb +56 -0
- data/lib/freeform/form/form_input_key.rb +1 -1
- data/lib/freeform/form/nested.rb +17 -55
- data/lib/freeform/form/property.rb +82 -42
- data/lib/freeform/form/validation.rb +38 -11
- data/lib/freeform/form.rb +24 -27
- data/lib/freeform/version.rb +1 -1
- data/lib/freeform.rb +4 -0
- data/lib/generators/freeform/install_generator.rb +17 -0
- data/lib/tasks/freeform_tasks.rake +4 -0
- data/spec/acceptance_spec.rb +261 -155
- data/spec/builder/builder_spec.rb +215 -0
- data/spec/builder/view_helper_spec.rb +97 -0
- data/spec/dummy/README.rdoc +28 -0
- data/spec/dummy/Rakefile +6 -0
- data/spec/dummy/app/assets/images/.keep +0 -0
- data/spec/dummy/app/assets/javascripts/application.js +5 -0
- data/spec/dummy/app/assets/javascripts/jquery.js +9404 -0
- data/spec/dummy/app/assets/javascripts/jquery_events_test.js +19 -0
- data/spec/dummy/app/assets/javascripts/projects.js +2 -0
- data/spec/dummy/app/assets/javascripts/prototype.js +6082 -0
- data/spec/dummy/app/assets/javascripts/prototype_events_test.js +20 -0
- data/spec/dummy/app/assets/stylesheets/application.css +7 -0
- data/spec/dummy/app/assets/stylesheets/companies.css +4 -0
- data/spec/dummy/app/assets/stylesheets/projects.css +4 -0
- data/spec/dummy/app/controllers/application_controller.rb +3 -0
- data/spec/dummy/app/controllers/companies_controller.rb +5 -0
- data/spec/dummy/app/controllers/projects_controller.rb +11 -0
- data/spec/dummy/app/forms/milestone_form.rb +4 -0
- data/spec/dummy/app/forms/project_form.rb +11 -0
- data/spec/dummy/app/forms/task_form.rb +10 -0
- data/spec/dummy/app/helpers/application_helper.rb +2 -0
- data/spec/dummy/app/mailers/.keep +0 -0
- data/spec/dummy/app/models/.keep +0 -0
- data/spec/dummy/app/models/company.rb +5 -0
- data/spec/dummy/app/models/milestone.rb +6 -0
- data/spec/dummy/app/models/project.rb +9 -0
- data/spec/dummy/app/models/project_task.rb +3 -0
- data/spec/dummy/app/models/task.rb +7 -0
- data/spec/dummy/app/views/companies/new.html.erb +16 -0
- data/spec/dummy/app/views/layouts/application.html.erb +19 -0
- data/spec/dummy/app/views/projects/new.html.erb +13 -0
- data/spec/dummy/app/views/projects/without_intermediate_inputs.html.erb +11 -0
- data/spec/dummy/bin/bundle +3 -0
- data/spec/dummy/bin/rails +4 -0
- data/spec/dummy/bin/rake +4 -0
- data/spec/dummy/config/application.rb +35 -0
- data/spec/dummy/config/boot.rb +5 -0
- data/spec/dummy/config/database.yml +25 -0
- data/spec/dummy/config/environment.rb +5 -0
- data/spec/dummy/config/environments/development.rb +29 -0
- data/spec/dummy/config/environments/production.rb +80 -0
- data/spec/dummy/config/environments/test.rb +36 -0
- data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
- data/spec/dummy/config/initializers/inflections.rb +16 -0
- data/spec/dummy/config/initializers/mime_types.rb +5 -0
- data/spec/dummy/config/initializers/secret_token.rb +13 -0
- data/spec/dummy/config/initializers/session_store.rb +3 -0
- data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/spec/dummy/config/locales/en.yml +23 -0
- data/spec/dummy/config/routes.rb +5 -0
- data/spec/dummy/config.ru +4 -0
- data/spec/dummy/db/migrate/20110710143903_initial_tables.rb +38 -0
- data/spec/dummy/db/schema.rb +43 -0
- data/spec/dummy/db/test.sqlite3 +0 -0
- data/spec/dummy/lib/assets/.keep +0 -0
- data/spec/dummy/log/.keep +0 -0
- data/spec/dummy/log/development.log +0 -0
- data/spec/dummy/log/test.log +39736 -0
- data/spec/dummy/public/404.html +58 -0
- data/spec/dummy/public/422.html +58 -0
- data/spec/dummy/public/500.html +57 -0
- data/spec/dummy/public/favicon.ico +0 -0
- data/spec/dummy/tmp/cache/assets/C54/850/sprockets%2Fd484f47085686f151320ff7248bb5105 +0 -0
- data/spec/dummy/tmp/cache/assets/C76/160/sprockets%2F49c594d143212b346d11f1ecf9358103 +0 -0
- data/spec/dummy/tmp/cache/assets/C99/4D0/sprockets%2F5e30a6b911437f1428dc32c3ae182123 +0 -0
- data/spec/dummy/tmp/cache/assets/C99/7D0/sprockets%2F79513e6956e0ee8624976e041fd5636d +0 -0
- data/spec/dummy/tmp/cache/assets/CAA/C90/sprockets%2F1e6c8ee1258009385ccf5b84015424b3 +0 -0
- data/spec/dummy/tmp/cache/assets/CB2/CB0/sprockets%2F11cc8d161d71a716dd36f16849d90870 +0 -0
- data/spec/dummy/tmp/cache/assets/CB7/7F0/sprockets%2Fac97b043470f6fcc925c352f16956643 +0 -0
- data/spec/dummy/tmp/cache/assets/CBA/680/sprockets%2F912d84e091e5f2190b1ab7926de19679 +0 -0
- data/spec/dummy/tmp/cache/assets/CC7/430/sprockets%2F48e99a3e16ba3e65749e009d82546f94 +0 -0
- data/spec/dummy/tmp/cache/assets/CD8/370/sprockets%2F357970feca3ac29060c1e3861e2c0953 +0 -0
- data/spec/dummy/tmp/cache/assets/CDB/8A0/sprockets%2Faed2a2575c376263c26e93b56b57051d +0 -0
- data/spec/dummy/tmp/cache/assets/CF1/E80/sprockets%2F7735295e1e3085f2e1dc29d59a45e8e6 +0 -0
- data/spec/dummy/tmp/cache/assets/D0F/E60/sprockets%2F1123d9a479fdf5c2b8415087e2a43ec6 +0 -0
- data/spec/dummy/tmp/cache/assets/D1F/A10/sprockets%2F60317e62cb324bfd9987e8da9636fd06 +0 -0
- data/spec/dummy/tmp/cache/assets/D25/E20/sprockets%2F29ba1a4a2b611731334f54abb9e5b5d1 +0 -0
- data/spec/dummy/tmp/cache/assets/D32/A10/sprockets%2F13fe41fee1fe35b49d145bcc06610705 +0 -0
- data/spec/dummy/tmp/cache/assets/D35/760/sprockets%2F49e26620c5c743ac4cdab7703f54db06 +0 -0
- data/spec/dummy/tmp/cache/assets/D49/870/sprockets%2F90896142645585acc8baf56ad57e3afb +0 -0
- data/spec/dummy/tmp/cache/assets/D4E/1B0/sprockets%2Ff7cbd26ba1d28d48de824f0e94586655 +0 -0
- data/spec/dummy/tmp/cache/assets/D5A/EA0/sprockets%2Fd771ace226fc8215a3572e0aa35bb0d6 +0 -0
- data/spec/dummy/tmp/cache/assets/D62/F00/sprockets%2F6ac03a007f26b1c18ed3d53498ad3eb8 +0 -0
- data/spec/dummy/tmp/cache/assets/D79/BC0/sprockets%2F85a1db977361cc5130fcefb4637ff67e +0 -0
- data/spec/dummy/tmp/cache/assets/D87/1F0/sprockets%2F61c9ceafb877fb740c67416ff6f782a9 +0 -0
- data/spec/dummy/tmp/cache/assets/DA8/900/sprockets%2Fde7a2b3987b89b9d9afb268ce4204a4a +0 -0
- data/spec/dummy/tmp/cache/assets/DAD/4F0/sprockets%2F765acd1bf68dc90f7d3e61da78b1e659 +0 -0
- data/spec/dummy/tmp/cache/assets/DDC/400/sprockets%2Fcffd775d018f68ce5dba1ee0d951a994 +0 -0
- data/spec/dummy/tmp/cache/assets/E03/3F0/sprockets%2F82b37ae9eccec44c1ef44cfdd07d8534 +0 -0
- data/spec/dummy/tmp/cache/assets/E04/890/sprockets%2F2f5173deea6c795b8fdde723bb4b63af +0 -0
- data/spec/dummy/tmp/cache/assets/E0A/CA0/sprockets%2F7fe72ac1c0db1a7e8e7f59cf25e8a39e +0 -0
- data/spec/dummy/tmp/cache/assets/E20/9B0/sprockets%2F2fa6cd86b1af7bda41f5b7921cdadf10 +0 -0
- data/spec/dummy/tmp/cache/assets/E3A/A60/sprockets%2F7c72c96cfc66454caf5fc8ca0fedd4f3 +0 -0
- data/spec/dummy/tmp/cache/assets/E54/400/sprockets%2Fd0cbc16cc37efcf9dc41f242b5dbbf81 +0 -0
- data/spec/dummy/tmp/cache/assets/EB7/AB0/sprockets%2F801d29a5debdbfbfb4eef14d70d9bcdb +0 -0
- data/spec/dummy/tmp/cache/assets/F48/5E0/sprockets%2F26cd6ffcffbebbe2fd6cd1a8f0c2debc +0 -0
- data/spec/form/nested_spec.rb +75 -61
- data/spec/form/property_spec.rb +167 -14
- data/spec/form/validation_spec.rb +46 -23
- data/spec/javascript_spec.rb +60 -0
- data/spec/persistence_spec.rb +608 -0
- data/spec/spec_helper.rb +18 -2
- data/vendor/assets/javascripts/jquery_freeform.js +120 -0
- data/vendor/assets/javascripts/jquery_nested_form.js +0 -0
- data/vendor/assets/javascripts/prototype_freeform.js +69 -0
- data/vendor/assets/javascripts/prototype_nested_form.js +0 -0
- metadata +341 -3
data/lib/freeform/form/nested.rb
CHANGED
@@ -1,5 +1,3 @@
|
|
1
|
-
require 'freeform/form/property'
|
2
|
-
|
3
1
|
module FreeForm
|
4
2
|
module Nested
|
5
3
|
def self.included(base)
|
@@ -9,55 +7,18 @@ module FreeForm
|
|
9
7
|
module ClassMethods
|
10
8
|
# Nested Forms
|
11
9
|
#------------------------------------------------------------------------
|
12
|
-
attr_accessor :nested_forms
|
10
|
+
attr_accessor :nested_forms
|
13
11
|
|
14
|
-
def nested_form(attribute, options={}
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
unless initializer_method.nil?
|
19
|
-
define_singleton_method(:"#{initializer_method}") do
|
20
|
-
var = instance_variable_get(:"@#{initializer_method}")
|
21
|
-
var ||= {}
|
22
|
-
var
|
23
|
-
end
|
24
|
-
|
25
|
-
define_singleton_method(:"#{initializer_method}=") do |val|
|
26
|
-
instance_variable_set(:"@#{initializer_method}", val)
|
27
|
-
end
|
28
|
-
end
|
12
|
+
def nested_form(attribute, options={})
|
13
|
+
nested_form_class = options[:class]
|
14
|
+
@nested_forms ||= {}
|
15
|
+
@nested_forms.merge!({:"#{attribute}" => nested_form_class})
|
29
16
|
|
30
17
|
# Define an attr_accessor for the parent class to hold this attribute
|
31
18
|
declared_model(attribute)
|
32
19
|
|
33
|
-
# Define the new class, and set it up with a new name
|
34
|
-
nested_form_class = Class.new(FreeForm::Form) do
|
35
|
-
include FreeForm::Property
|
36
|
-
self.instance_eval(&block)
|
37
|
-
|
38
|
-
define_singleton_method(:default_initializer) do
|
39
|
-
unless initializer_method.nil?
|
40
|
-
method = parent_class.send(initializer_method)
|
41
|
-
if method.is_a? Proc
|
42
|
-
method.call
|
43
|
-
else
|
44
|
-
method
|
45
|
-
end
|
46
|
-
end
|
47
|
-
end
|
48
|
-
|
49
|
-
def initialize(p={}, *args)
|
50
|
-
p = self.class.default_initializer.merge(p)
|
51
|
-
super(p, *args)
|
52
|
-
end
|
53
|
-
end
|
54
|
-
self.const_set("#{attribute.to_s.camelize}Form", nested_form_class)
|
55
|
-
|
56
|
-
@nested_forms ||= {}
|
57
|
-
@nested_forms.merge!({:"#{attribute}" => nested_form_class})
|
58
|
-
|
59
20
|
# Defined other methods
|
60
|
-
define_nested_model_methods(attribute, nested_form_class)
|
21
|
+
define_nested_model_methods(attribute, nested_form_class, options)
|
61
22
|
|
62
23
|
# Setup Handling for nested attributes
|
63
24
|
define_nested_attribute_methods(attribute, nested_form_class)
|
@@ -65,18 +26,10 @@ module FreeForm
|
|
65
26
|
alias_method :has_many, :nested_form
|
66
27
|
alias_method :has_one, :nested_form
|
67
28
|
|
68
|
-
# Supporting Methods
|
69
|
-
#------------------------------------------------------------------------
|
70
|
-
def reflect_on_association(key, *args)
|
71
|
-
reflection = OpenStruct.new
|
72
|
-
reflection.klass = self.nested_forms[key]
|
73
|
-
reflection
|
74
|
-
end
|
75
|
-
|
76
29
|
protected
|
77
30
|
# Defining Helper Methods For Models
|
78
31
|
#------------------------------------------------------------------------
|
79
|
-
def define_nested_model_methods(attribute, form_class)
|
32
|
+
def define_nested_model_methods(attribute, form_class, options={})
|
80
33
|
singularized_attribute = attribute.to_s.singularize.to_s
|
81
34
|
|
82
35
|
# Example: form.addresses will return all nested address forms
|
@@ -85,9 +38,18 @@ module FreeForm
|
|
85
38
|
end
|
86
39
|
|
87
40
|
# Example: form.build_addresses (optional custom initializer)
|
88
|
-
define_method(:"build_#{attribute}") do |initializer=
|
41
|
+
define_method(:"build_#{attribute}") do |initializer=nil|
|
42
|
+
# Builder object
|
43
|
+
parent_object = self
|
44
|
+
|
89
45
|
# Get correct class
|
90
46
|
form_class = self.class.nested_forms[:"#{attribute}"]
|
47
|
+
|
48
|
+
# Default Initializer
|
49
|
+
if options[:default_initializer]
|
50
|
+
initializer ||= instance_eval(&options[:default_initializer])
|
51
|
+
end
|
52
|
+
initializer ||= {}
|
91
53
|
|
92
54
|
# Build new model
|
93
55
|
form_model = form_class.new(initializer)
|
@@ -13,6 +13,10 @@ module FreeForm
|
|
13
13
|
@models ||= []
|
14
14
|
end
|
15
15
|
|
16
|
+
def child_models
|
17
|
+
@child_models ||= []
|
18
|
+
end
|
19
|
+
|
16
20
|
def declared_model(name, opts={})
|
17
21
|
@models ||= []
|
18
22
|
@models << name
|
@@ -27,73 +31,109 @@ module FreeForm
|
|
27
31
|
end
|
28
32
|
alias_method :form_models, :declared_models
|
29
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
|
+
|
30
45
|
# Properties
|
31
46
|
#------------------------------------------------------------------------
|
32
|
-
def
|
33
|
-
|
47
|
+
def property_mappings
|
48
|
+
# Take the form of {:property => {:model => model, :field => field, :ignore_blank => false}}
|
49
|
+
@property_mappings ||= Hash.new
|
34
50
|
end
|
35
51
|
|
36
52
|
def allow_destroy_on_save
|
37
53
|
# Define _destroy method for marked-for-destruction handling
|
38
54
|
attr_accessor :_destroy
|
39
|
-
|
55
|
+
define_method(:_destroy=) do |value|
|
56
|
+
false_values = [nil, 0 , false, "0", "false"]
|
57
|
+
@_destroy = !(false_values.include?(value))
|
58
|
+
end
|
59
|
+
alias_method :marked_for_destruction?, :_destroy
|
60
|
+
define_method(:mark_for_destruction) do
|
61
|
+
@_destroy = true
|
62
|
+
end
|
40
63
|
end
|
41
64
|
|
42
65
|
def property(attribute, options={})
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
66
|
+
@property_mappings ||= Hash.new
|
67
|
+
model = options[:on] ? options [:on] : :self
|
68
|
+
field = options[:as] ? options[:as] : attribute.to_sym
|
69
|
+
ignore_blank = options[:ignore_blank] ? options[:ignore_blank] : false
|
70
|
+
@property_mappings.merge!({field => {:model => model, :field => attribute.to_sym, :ignore_blank => ignore_blank}})
|
71
|
+
|
72
|
+
if model == :self
|
47
73
|
attr_accessor attribute
|
74
|
+
else
|
75
|
+
define_method("#{field}") do
|
76
|
+
send("#{model}").send("#{attribute}")
|
77
|
+
end
|
78
|
+
|
79
|
+
define_method("#{field}=") do |value|
|
80
|
+
send("#{model}").send("#{attribute}=", value)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
attr_accessor :parent_form
|
87
|
+
|
88
|
+
class DateParamsFilter
|
89
|
+
def call(params)
|
90
|
+
date_attributes = {}
|
91
|
+
|
92
|
+
params.each do |attribute, value|
|
93
|
+
if value.is_a?(Hash)
|
94
|
+
call(value) # TODO: #validate should only handle local form params.
|
95
|
+
elsif matches = attribute.match(/^(\w+)\(.i\)$/)
|
96
|
+
date_attribute = matches[1]
|
97
|
+
date_attributes[date_attribute] = params_to_date(
|
98
|
+
params.delete("#{date_attribute}(1i)"),
|
99
|
+
params.delete("#{date_attribute}(2i)"),
|
100
|
+
params.delete("#{date_attribute}(3i)")
|
101
|
+
)
|
102
|
+
end
|
103
|
+
end
|
104
|
+
params.merge!(date_attributes)
|
105
|
+
end
|
106
|
+
|
107
|
+
private
|
108
|
+
def params_to_date(year, month, day)
|
109
|
+
day ||= 1 # FIXME: is that really what we want? test.
|
110
|
+
begin # TODO: test fails.
|
111
|
+
return Date.new(year.to_i, month.to_i, day.to_i)
|
112
|
+
rescue ArgumentError => e
|
113
|
+
return nil
|
48
114
|
end
|
49
|
-
@ignored_blank_params ||= []
|
50
|
-
@ignored_blank_params << attribute if options[:ignore_blank]
|
51
115
|
end
|
52
116
|
end
|
53
117
|
|
54
118
|
def assign_params(params)
|
55
|
-
|
119
|
+
DateParamsFilter.new.call(params)
|
56
120
|
params.each_pair do |attribute, value|
|
57
|
-
|
121
|
+
assign_attribute(attribute, value)
|
58
122
|
end
|
59
123
|
self
|
60
124
|
end
|
61
125
|
alias_method :assign_attributes, :assign_params
|
62
126
|
alias_method :populate, :assign_params
|
63
127
|
alias_method :fill, :assign_params
|
64
|
-
|
65
|
-
def ignore?(attribute, value)
|
66
|
-
ignored_if_blank = self.class.ignored_blank_params
|
67
|
-
return (ignored_if_blank.include?(attribute.to_sym) && value.blank?)
|
68
|
-
end
|
69
128
|
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
date_attributes = {}
|
74
|
-
params.each do |attribute, value|
|
75
|
-
if attribute.to_s.include?("(1i)") || attribute.to_s.include?("(2i)") || attribute.to_s.include?("(3i)")
|
76
|
-
date_attribute = attribute.to_s.gsub(/(\(.*\))/, "")
|
77
|
-
date_attributes[date_attribute.to_sym] = params_to_date(
|
78
|
-
params.delete("#{date_attribute}(1i)"),
|
79
|
-
params.delete("#{date_attribute}(2i)"),
|
80
|
-
params.delete("#{date_attribute}(3i)")
|
81
|
-
)
|
82
|
-
end
|
83
|
-
end
|
84
|
-
params.merge!(date_attributes)
|
129
|
+
private
|
130
|
+
def assign_attribute(attribute, value)
|
131
|
+
self.send :"#{attribute}=", value unless ignore?(attribute, value)
|
85
132
|
end
|
86
|
-
|
87
|
-
def
|
88
|
-
|
89
|
-
|
90
|
-
return Date.new(year.to_i, month.to_i, day.to_i)
|
91
|
-
rescue => e
|
92
|
-
return nil
|
93
|
-
end
|
133
|
+
|
134
|
+
def ignore?(attribute, value)
|
135
|
+
mapping = self.class.property_mappings[attribute.to_sym]
|
136
|
+
return (mapping[:ignore_blank] && value.blank?) unless mapping.nil?
|
94
137
|
end
|
95
138
|
end
|
96
|
-
|
97
|
-
#Instance Methods
|
98
|
-
#----------------------------------------------------------------------------
|
99
139
|
end
|
@@ -2,6 +2,7 @@ module FreeForm
|
|
2
2
|
module Validation
|
3
3
|
def self.included(base)
|
4
4
|
base.extend(ClassMethods)
|
5
|
+
extend FreeForm::Property
|
5
6
|
end
|
6
7
|
|
7
8
|
module ClassMethods
|
@@ -10,25 +11,51 @@ module FreeForm
|
|
10
11
|
end
|
11
12
|
end
|
12
13
|
|
13
|
-
|
14
|
+
protected
|
14
15
|
def model_validity
|
15
|
-
|
16
|
-
self.class.models.each do |form_model|
|
16
|
+
self.class.models.each do |form_model|
|
17
17
|
if send(form_model).is_a?(Array)
|
18
|
-
|
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))
|
19
20
|
else
|
20
|
-
|
21
|
+
# Otherwise, validate the form object
|
22
|
+
validate_form_model(form_model)
|
21
23
|
end
|
22
24
|
end
|
23
|
-
return model_validity
|
24
25
|
end
|
25
26
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
27
|
+
private
|
28
|
+
def validate_nested_forms(form_array)
|
29
|
+
form_validity = true
|
30
|
+
form_array.each do |model|
|
31
|
+
form_validity = false unless model.valid?
|
30
32
|
end
|
31
|
-
|
33
|
+
form_validity
|
34
|
+
end
|
35
|
+
|
36
|
+
def validate_form_model(form_model)
|
37
|
+
model = send(form_model)
|
38
|
+
append_errors(form_model)
|
39
|
+
return model.valid?
|
40
|
+
end
|
41
|
+
|
42
|
+
def append_errors(form_model)
|
43
|
+
model = send(form_model)
|
44
|
+
model.valid?
|
45
|
+
model.errors.each do |error, message|
|
46
|
+
if find_form_field_from_model_field(form_model, error)
|
47
|
+
self.errors.add(find_form_field_from_model_field(form_model, error), message)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def find_form_field_from_model_field(model, field)
|
53
|
+
self.class.property_mappings.each_pair do |property, attributes|
|
54
|
+
if (attributes[:model] == model.to_sym) && (attributes[:field] == field.to_sym)
|
55
|
+
return property
|
56
|
+
end
|
57
|
+
end
|
58
|
+
return false
|
32
59
|
end
|
33
60
|
end
|
34
61
|
end
|
data/lib/freeform/form.rb
CHANGED
@@ -22,51 +22,48 @@ module FreeForm
|
|
22
22
|
# Instance Methods
|
23
23
|
#----------------------------------------------------------------------------
|
24
24
|
# Required for ActiveModel
|
25
|
-
def persisted
|
26
|
-
false
|
27
|
-
end
|
25
|
+
def persisted?; false end
|
28
26
|
|
29
27
|
def initialize(h={})
|
30
28
|
h.each {|k,v| send("#{k}=",v)}
|
29
|
+
initialize_child_models
|
31
30
|
end
|
32
31
|
|
33
32
|
def save
|
34
33
|
return false unless valid?
|
34
|
+
|
35
35
|
self.class.models.each do |form_model|
|
36
|
-
|
37
|
-
|
38
|
-
else
|
39
|
-
if marked_for_destruction?
|
40
|
-
send(form_model).destroy
|
41
|
-
else
|
42
|
-
return false unless send(form_model).save
|
43
|
-
end
|
44
|
-
end
|
36
|
+
model = send(form_model)
|
37
|
+
model.is_a?(Array) ? model.each { |m| m.save } : save_or_destroy(model)
|
45
38
|
end
|
46
|
-
return true
|
47
39
|
end
|
48
40
|
|
49
41
|
def save!
|
50
42
|
raise FreeForm::FormInvalid, "form invalid." unless valid?
|
43
|
+
|
51
44
|
self.class.models.each do |form_model|
|
52
|
-
|
53
|
-
|
54
|
-
else
|
55
|
-
if marked_for_destruction?
|
56
|
-
send(form_model).destroy
|
57
|
-
else
|
58
|
-
send(form_model).save!
|
59
|
-
end
|
60
|
-
end
|
45
|
+
model = send(form_model)
|
46
|
+
model.is_a?(Array) ? model.each { |m| m.save! } : save_or_destroy!(model)
|
61
47
|
end
|
62
48
|
end
|
63
49
|
|
50
|
+
private
|
51
|
+
def initialize_child_models
|
52
|
+
self.class.child_models.each do |c|
|
53
|
+
send("initialize_#{c}")
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def save_or_destroy(model)
|
58
|
+
marked_for_destruction? ? model.destroy : model.save
|
59
|
+
end
|
60
|
+
|
61
|
+
def save_or_destroy!(model)
|
62
|
+
marked_for_destruction? ? model.destroy : model.save!
|
63
|
+
end
|
64
|
+
|
64
65
|
def marked_for_destruction?
|
65
|
-
|
66
|
-
return self._destroy
|
67
|
-
else
|
68
|
-
return false
|
69
|
-
end
|
66
|
+
respond_to?(:_destroy) ? _destroy : false
|
70
67
|
end
|
71
68
|
end
|
72
69
|
end
|
data/lib/freeform/version.rb
CHANGED
data/lib/freeform.rb
CHANGED
@@ -2,4 +2,8 @@ require 'freeform/version'
|
|
2
2
|
require 'freeform/form'
|
3
3
|
|
4
4
|
if defined?(Rails) # Where to include Rails specific modules...
|
5
|
+
require 'freeform/builder/builder_mixin'
|
6
|
+
require 'freeform/builder/builders'
|
7
|
+
require 'freeform/builder/view_helper'
|
8
|
+
require 'freeform/builder/engine'
|
5
9
|
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module FreeForm
|
2
|
+
module Generators
|
3
|
+
class InstallGenerator < Rails::Generators::Base
|
4
|
+
def self.source_root
|
5
|
+
File.expand_path('../../../../vendor/assets/javascripts', __FILE__)
|
6
|
+
end
|
7
|
+
|
8
|
+
def copy_jquery_file
|
9
|
+
if File.exists?('public/javascripts/prototype.js')
|
10
|
+
copy_file 'prototype_freeform.js', 'public/javascripts/freeform.js'
|
11
|
+
else
|
12
|
+
copy_file 'jquery_freeform.js', 'public/javascripts/freeform.js'
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|