freeform 0.0.4 → 1.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.
Files changed (129) hide show
  1. data/.gitignore +8 -17
  2. data/Gemfile +1 -1
  3. data/Gemfile.lock +150 -0
  4. data/MIT-LICENSE +20 -0
  5. data/README.md +31 -43
  6. data/Rakefile +32 -1
  7. data/freeform.gemspec +22 -15
  8. data/lib/freeform/builder/builder_mixin.rb +111 -0
  9. data/lib/freeform/builder/builders.rb +32 -0
  10. data/lib/freeform/builder/engine.rb +14 -0
  11. data/lib/freeform/builder/view_helper.rb +56 -0
  12. data/lib/freeform/form/form_input_key.rb +1 -1
  13. data/lib/freeform/form/nested.rb +17 -55
  14. data/lib/freeform/form/property.rb +82 -42
  15. data/lib/freeform/form/validation.rb +38 -11
  16. data/lib/freeform/form.rb +24 -27
  17. data/lib/freeform/version.rb +1 -1
  18. data/lib/freeform.rb +4 -0
  19. data/lib/generators/freeform/install_generator.rb +17 -0
  20. data/lib/tasks/freeform_tasks.rake +4 -0
  21. data/spec/acceptance_spec.rb +261 -155
  22. data/spec/builder/builder_spec.rb +215 -0
  23. data/spec/builder/view_helper_spec.rb +97 -0
  24. data/spec/dummy/README.rdoc +28 -0
  25. data/spec/dummy/Rakefile +6 -0
  26. data/spec/dummy/app/assets/images/.keep +0 -0
  27. data/spec/dummy/app/assets/javascripts/application.js +5 -0
  28. data/spec/dummy/app/assets/javascripts/jquery.js +9404 -0
  29. data/spec/dummy/app/assets/javascripts/jquery_events_test.js +19 -0
  30. data/spec/dummy/app/assets/javascripts/projects.js +2 -0
  31. data/spec/dummy/app/assets/javascripts/prototype.js +6082 -0
  32. data/spec/dummy/app/assets/javascripts/prototype_events_test.js +20 -0
  33. data/spec/dummy/app/assets/stylesheets/application.css +7 -0
  34. data/spec/dummy/app/assets/stylesheets/companies.css +4 -0
  35. data/spec/dummy/app/assets/stylesheets/projects.css +4 -0
  36. data/spec/dummy/app/controllers/application_controller.rb +3 -0
  37. data/spec/dummy/app/controllers/companies_controller.rb +5 -0
  38. data/spec/dummy/app/controllers/projects_controller.rb +11 -0
  39. data/spec/dummy/app/forms/milestone_form.rb +4 -0
  40. data/spec/dummy/app/forms/project_form.rb +11 -0
  41. data/spec/dummy/app/forms/task_form.rb +10 -0
  42. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  43. data/spec/dummy/app/mailers/.keep +0 -0
  44. data/spec/dummy/app/models/.keep +0 -0
  45. data/spec/dummy/app/models/company.rb +5 -0
  46. data/spec/dummy/app/models/milestone.rb +6 -0
  47. data/spec/dummy/app/models/project.rb +9 -0
  48. data/spec/dummy/app/models/project_task.rb +3 -0
  49. data/spec/dummy/app/models/task.rb +7 -0
  50. data/spec/dummy/app/views/companies/new.html.erb +16 -0
  51. data/spec/dummy/app/views/layouts/application.html.erb +19 -0
  52. data/spec/dummy/app/views/projects/new.html.erb +13 -0
  53. data/spec/dummy/app/views/projects/without_intermediate_inputs.html.erb +11 -0
  54. data/spec/dummy/bin/bundle +3 -0
  55. data/spec/dummy/bin/rails +4 -0
  56. data/spec/dummy/bin/rake +4 -0
  57. data/spec/dummy/config/application.rb +35 -0
  58. data/spec/dummy/config/boot.rb +5 -0
  59. data/spec/dummy/config/database.yml +25 -0
  60. data/spec/dummy/config/environment.rb +5 -0
  61. data/spec/dummy/config/environments/development.rb +29 -0
  62. data/spec/dummy/config/environments/production.rb +80 -0
  63. data/spec/dummy/config/environments/test.rb +36 -0
  64. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  65. data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  66. data/spec/dummy/config/initializers/inflections.rb +16 -0
  67. data/spec/dummy/config/initializers/mime_types.rb +5 -0
  68. data/spec/dummy/config/initializers/secret_token.rb +13 -0
  69. data/spec/dummy/config/initializers/session_store.rb +3 -0
  70. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  71. data/spec/dummy/config/locales/en.yml +23 -0
  72. data/spec/dummy/config/routes.rb +5 -0
  73. data/spec/dummy/config.ru +4 -0
  74. data/spec/dummy/db/migrate/20110710143903_initial_tables.rb +38 -0
  75. data/spec/dummy/db/schema.rb +43 -0
  76. data/spec/dummy/db/test.sqlite3 +0 -0
  77. data/spec/dummy/lib/assets/.keep +0 -0
  78. data/spec/dummy/log/.keep +0 -0
  79. data/spec/dummy/log/development.log +0 -0
  80. data/spec/dummy/log/test.log +39736 -0
  81. data/spec/dummy/public/404.html +58 -0
  82. data/spec/dummy/public/422.html +58 -0
  83. data/spec/dummy/public/500.html +57 -0
  84. data/spec/dummy/public/favicon.ico +0 -0
  85. data/spec/dummy/tmp/cache/assets/C54/850/sprockets%2Fd484f47085686f151320ff7248bb5105 +0 -0
  86. data/spec/dummy/tmp/cache/assets/C76/160/sprockets%2F49c594d143212b346d11f1ecf9358103 +0 -0
  87. data/spec/dummy/tmp/cache/assets/C99/4D0/sprockets%2F5e30a6b911437f1428dc32c3ae182123 +0 -0
  88. data/spec/dummy/tmp/cache/assets/C99/7D0/sprockets%2F79513e6956e0ee8624976e041fd5636d +0 -0
  89. data/spec/dummy/tmp/cache/assets/CAA/C90/sprockets%2F1e6c8ee1258009385ccf5b84015424b3 +0 -0
  90. data/spec/dummy/tmp/cache/assets/CB2/CB0/sprockets%2F11cc8d161d71a716dd36f16849d90870 +0 -0
  91. data/spec/dummy/tmp/cache/assets/CB7/7F0/sprockets%2Fac97b043470f6fcc925c352f16956643 +0 -0
  92. data/spec/dummy/tmp/cache/assets/CBA/680/sprockets%2F912d84e091e5f2190b1ab7926de19679 +0 -0
  93. data/spec/dummy/tmp/cache/assets/CC7/430/sprockets%2F48e99a3e16ba3e65749e009d82546f94 +0 -0
  94. data/spec/dummy/tmp/cache/assets/CD8/370/sprockets%2F357970feca3ac29060c1e3861e2c0953 +0 -0
  95. data/spec/dummy/tmp/cache/assets/CDB/8A0/sprockets%2Faed2a2575c376263c26e93b56b57051d +0 -0
  96. data/spec/dummy/tmp/cache/assets/CF1/E80/sprockets%2F7735295e1e3085f2e1dc29d59a45e8e6 +0 -0
  97. data/spec/dummy/tmp/cache/assets/D0F/E60/sprockets%2F1123d9a479fdf5c2b8415087e2a43ec6 +0 -0
  98. data/spec/dummy/tmp/cache/assets/D1F/A10/sprockets%2F60317e62cb324bfd9987e8da9636fd06 +0 -0
  99. data/spec/dummy/tmp/cache/assets/D25/E20/sprockets%2F29ba1a4a2b611731334f54abb9e5b5d1 +0 -0
  100. data/spec/dummy/tmp/cache/assets/D32/A10/sprockets%2F13fe41fee1fe35b49d145bcc06610705 +0 -0
  101. data/spec/dummy/tmp/cache/assets/D35/760/sprockets%2F49e26620c5c743ac4cdab7703f54db06 +0 -0
  102. data/spec/dummy/tmp/cache/assets/D49/870/sprockets%2F90896142645585acc8baf56ad57e3afb +0 -0
  103. data/spec/dummy/tmp/cache/assets/D4E/1B0/sprockets%2Ff7cbd26ba1d28d48de824f0e94586655 +0 -0
  104. data/spec/dummy/tmp/cache/assets/D5A/EA0/sprockets%2Fd771ace226fc8215a3572e0aa35bb0d6 +0 -0
  105. data/spec/dummy/tmp/cache/assets/D62/F00/sprockets%2F6ac03a007f26b1c18ed3d53498ad3eb8 +0 -0
  106. data/spec/dummy/tmp/cache/assets/D79/BC0/sprockets%2F85a1db977361cc5130fcefb4637ff67e +0 -0
  107. data/spec/dummy/tmp/cache/assets/D87/1F0/sprockets%2F61c9ceafb877fb740c67416ff6f782a9 +0 -0
  108. data/spec/dummy/tmp/cache/assets/DA8/900/sprockets%2Fde7a2b3987b89b9d9afb268ce4204a4a +0 -0
  109. data/spec/dummy/tmp/cache/assets/DAD/4F0/sprockets%2F765acd1bf68dc90f7d3e61da78b1e659 +0 -0
  110. data/spec/dummy/tmp/cache/assets/DDC/400/sprockets%2Fcffd775d018f68ce5dba1ee0d951a994 +0 -0
  111. data/spec/dummy/tmp/cache/assets/E03/3F0/sprockets%2F82b37ae9eccec44c1ef44cfdd07d8534 +0 -0
  112. data/spec/dummy/tmp/cache/assets/E04/890/sprockets%2F2f5173deea6c795b8fdde723bb4b63af +0 -0
  113. data/spec/dummy/tmp/cache/assets/E0A/CA0/sprockets%2F7fe72ac1c0db1a7e8e7f59cf25e8a39e +0 -0
  114. data/spec/dummy/tmp/cache/assets/E20/9B0/sprockets%2F2fa6cd86b1af7bda41f5b7921cdadf10 +0 -0
  115. data/spec/dummy/tmp/cache/assets/E3A/A60/sprockets%2F7c72c96cfc66454caf5fc8ca0fedd4f3 +0 -0
  116. data/spec/dummy/tmp/cache/assets/E54/400/sprockets%2Fd0cbc16cc37efcf9dc41f242b5dbbf81 +0 -0
  117. data/spec/dummy/tmp/cache/assets/EB7/AB0/sprockets%2F801d29a5debdbfbfb4eef14d70d9bcdb +0 -0
  118. data/spec/dummy/tmp/cache/assets/F48/5E0/sprockets%2F26cd6ffcffbebbe2fd6cd1a8f0c2debc +0 -0
  119. data/spec/form/nested_spec.rb +75 -61
  120. data/spec/form/property_spec.rb +167 -14
  121. data/spec/form/validation_spec.rb +46 -23
  122. data/spec/javascript_spec.rb +60 -0
  123. data/spec/persistence_spec.rb +608 -0
  124. data/spec/spec_helper.rb +18 -2
  125. data/vendor/assets/javascripts/jquery_freeform.js +120 -0
  126. data/vendor/assets/javascripts/jquery_nested_form.js +0 -0
  127. data/vendor/assets/javascripts/prototype_freeform.js +69 -0
  128. data/vendor/assets/javascripts/prototype_nested_form.js +0 -0
  129. metadata +341 -3
@@ -0,0 +1,58 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>The page you were looking for doesn't exist (404)</title>
5
+ <style>
6
+ body {
7
+ background-color: #EFEFEF;
8
+ color: #2E2F30;
9
+ text-align: center;
10
+ font-family: arial, sans-serif;
11
+ }
12
+
13
+ div.dialog {
14
+ width: 25em;
15
+ margin: 4em auto 0 auto;
16
+ border: 1px solid #CCC;
17
+ border-right-color: #999;
18
+ border-left-color: #999;
19
+ border-bottom-color: #BBB;
20
+ border-top: #B00100 solid 4px;
21
+ border-top-left-radius: 9px;
22
+ border-top-right-radius: 9px;
23
+ background-color: white;
24
+ padding: 7px 4em 0 4em;
25
+ }
26
+
27
+ h1 {
28
+ font-size: 100%;
29
+ color: #730E15;
30
+ line-height: 1.5em;
31
+ }
32
+
33
+ body > p {
34
+ width: 33em;
35
+ margin: 0 auto 1em;
36
+ padding: 1em 0;
37
+ background-color: #F7F7F7;
38
+ border: 1px solid #CCC;
39
+ border-right-color: #999;
40
+ border-bottom-color: #999;
41
+ border-bottom-left-radius: 4px;
42
+ border-bottom-right-radius: 4px;
43
+ border-top-color: #DADADA;
44
+ color: #666;
45
+ box-shadow:0 3px 8px rgba(50, 50, 50, 0.17);
46
+ }
47
+ </style>
48
+ </head>
49
+
50
+ <body>
51
+ <!-- This file lives in public/404.html -->
52
+ <div class="dialog">
53
+ <h1>The page you were looking for doesn't exist.</h1>
54
+ <p>You may have mistyped the address or the page may have moved.</p>
55
+ </div>
56
+ <p>If you are the application owner check the logs for more information.</p>
57
+ </body>
58
+ </html>
@@ -0,0 +1,58 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>The change you wanted was rejected (422)</title>
5
+ <style>
6
+ body {
7
+ background-color: #EFEFEF;
8
+ color: #2E2F30;
9
+ text-align: center;
10
+ font-family: arial, sans-serif;
11
+ }
12
+
13
+ div.dialog {
14
+ width: 25em;
15
+ margin: 4em auto 0 auto;
16
+ border: 1px solid #CCC;
17
+ border-right-color: #999;
18
+ border-left-color: #999;
19
+ border-bottom-color: #BBB;
20
+ border-top: #B00100 solid 4px;
21
+ border-top-left-radius: 9px;
22
+ border-top-right-radius: 9px;
23
+ background-color: white;
24
+ padding: 7px 4em 0 4em;
25
+ }
26
+
27
+ h1 {
28
+ font-size: 100%;
29
+ color: #730E15;
30
+ line-height: 1.5em;
31
+ }
32
+
33
+ body > p {
34
+ width: 33em;
35
+ margin: 0 auto 1em;
36
+ padding: 1em 0;
37
+ background-color: #F7F7F7;
38
+ border: 1px solid #CCC;
39
+ border-right-color: #999;
40
+ border-bottom-color: #999;
41
+ border-bottom-left-radius: 4px;
42
+ border-bottom-right-radius: 4px;
43
+ border-top-color: #DADADA;
44
+ color: #666;
45
+ box-shadow:0 3px 8px rgba(50, 50, 50, 0.17);
46
+ }
47
+ </style>
48
+ </head>
49
+
50
+ <body>
51
+ <!-- This file lives in public/422.html -->
52
+ <div class="dialog">
53
+ <h1>The change you wanted was rejected.</h1>
54
+ <p>Maybe you tried to change something you didn't have access to.</p>
55
+ </div>
56
+ <p>If you are the application owner check the logs for more information.</p>
57
+ </body>
58
+ </html>
@@ -0,0 +1,57 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>We're sorry, but something went wrong (500)</title>
5
+ <style>
6
+ body {
7
+ background-color: #EFEFEF;
8
+ color: #2E2F30;
9
+ text-align: center;
10
+ font-family: arial, sans-serif;
11
+ }
12
+
13
+ div.dialog {
14
+ width: 25em;
15
+ margin: 4em auto 0 auto;
16
+ border: 1px solid #CCC;
17
+ border-right-color: #999;
18
+ border-left-color: #999;
19
+ border-bottom-color: #BBB;
20
+ border-top: #B00100 solid 4px;
21
+ border-top-left-radius: 9px;
22
+ border-top-right-radius: 9px;
23
+ background-color: white;
24
+ padding: 7px 4em 0 4em;
25
+ }
26
+
27
+ h1 {
28
+ font-size: 100%;
29
+ color: #730E15;
30
+ line-height: 1.5em;
31
+ }
32
+
33
+ body > p {
34
+ width: 33em;
35
+ margin: 0 auto 1em;
36
+ padding: 1em 0;
37
+ background-color: #F7F7F7;
38
+ border: 1px solid #CCC;
39
+ border-right-color: #999;
40
+ border-bottom-color: #999;
41
+ border-bottom-left-radius: 4px;
42
+ border-bottom-right-radius: 4px;
43
+ border-top-color: #DADADA;
44
+ color: #666;
45
+ box-shadow:0 3px 8px rgba(50, 50, 50, 0.17);
46
+ }
47
+ </style>
48
+ </head>
49
+
50
+ <body>
51
+ <!-- This file lives in public/500.html -->
52
+ <div class="dialog">
53
+ <h1>We're sorry, but something went wrong.</h1>
54
+ </div>
55
+ <p>If you are the application owner check the logs for more information.</p>
56
+ </body>
57
+ </html>
File without changes
@@ -3,56 +3,72 @@ require 'freeform/form/property'
3
3
  require 'freeform/form/nested'
4
4
 
5
5
  describe FreeForm::Nested do
6
- describe "class methods", :class_methods => true do
7
- describe "has_many", :has_many => true do
8
- let(:form_class) do
9
- klass = Class.new(Module) do
10
- include FreeForm::Property
11
- include FreeForm::Nested
12
-
13
- has_many :mailing_addresses, :class_initializer => :mailing_address_initializer do
14
- declared_model :address
15
-
16
- property :street, :on => :address
17
- end
6
+ describe "has_many", :has_many => true do
7
+ let!(:nested_class) do
8
+ klass = Class.new(Module) do
9
+ include FreeForm::Property
10
+ include FreeForm::Nested
11
+ declared_model :address
12
+
13
+ property :street, :on => :address
14
+
15
+ def initialize(h={})
16
+ h.each {|k,v| send("#{k}=",v)}
17
+ end
18
+ end
19
+ # This wrapper just avoids CONST warnings
20
+ v, $VERBOSE = $VERBOSE, nil
21
+ Module.const_set("MailingAddressForm", klass)
22
+ $VERBOSE = v
23
+ klass
24
+ end
18
25
 
19
- def initialize(h={})
20
- h.each {|k,v| send("#{k}=",v)}
21
- end
26
+ let(:form_class) do
27
+ klass = Class.new(Module) do
28
+ include FreeForm::Property
29
+ include FreeForm::Nested
30
+
31
+ has_many :mailing_addresses, :class => Module::MailingAddressForm, :default_initializer => :mailing_address_initializer
32
+
33
+ def initialize(h={})
34
+ h.each {|k,v| send("#{k}=",v)}
35
+ end
36
+
37
+ def mailing_address_initializer
38
+ { :address => OpenStruct.new(:id => Random.new.rand(1000000)) }
22
39
  end
23
- # This wrapper just avoids CONST warnings
24
- v, $VERBOSE = $VERBOSE, nil
25
- Module.const_set("DummyForm", klass)
26
- $VERBOSE = v
27
- klass
28
- end
29
-
30
- let(:form) do
31
- form_class.mailing_address_initializer = lambda { { :address => OpenStruct.new } }
32
- form_model = form_class.new
33
40
  end
41
+ # This wrapper just avoids CONST warnings
42
+ v, $VERBOSE = $VERBOSE, nil
43
+ Module.const_set("DummyForm", klass)
44
+ $VERBOSE = v
45
+ klass
46
+ end
34
47
 
35
- describe "form class" do
36
- it "sets nested_form in models" do
37
- form_class.models.should eq([:mailing_addresses])
38
- end
48
+ let(:form) do
49
+ form_model = form_class.new
50
+ end
51
+
52
+ describe "form class" do
53
+ it "sets nested_form in models" do
54
+ form_class.models.should eq([:mailing_addresses])
55
+ end
56
+ end
57
+
58
+ describe "building nested models" do
59
+ it "initializes with no nested models prebuilt" do
60
+ form.mailing_addresses.should eq([])
39
61
  end
40
62
 
41
- describe "building nested models" do
42
- it "initializes with no nested models prebuilt" do
43
- form.mailing_addresses.should eq([])
44
- end
45
-
63
+ context "with default initializer" do
46
64
  it "allows nested_forms to be built" do
47
65
  form.build_mailing_addresses
48
66
  form.mailing_addresses.should be_an(Array)
49
67
  form.mailing_addresses.should_not be_empty
50
- form.mailing_addresses.first.should be_a(Module::DummyForm::MailingAddressesForm)
68
+ form.mailing_addresses.first.should be_a(Module::MailingAddressForm)
51
69
  end
52
-
70
+
53
71
  it "builds unique models" do
54
- # Using module here, since they initialize uniquely
55
- form_class.mailing_address_initializer = lambda { { :address => Module.new } }
56
72
  form = form_class.new
57
73
  form.build_mailing_address
58
74
  form.build_mailing_address
@@ -60,36 +76,34 @@ describe FreeForm::Nested do
60
76
  address_2 = form.mailing_addresses.last.address
61
77
  address_1.should_not eq(address_2)
62
78
  end
63
-
64
- it "builds initialized models through reflection on association" do
65
- form_class.mailing_address_initializer = lambda { { :address => Module.new } }
66
- klass = form_class.reflect_on_association(:mailing_addresses).klass
67
- klass.new.address.should be_a(Module)
79
+ end
80
+
81
+ context "with custom initializer" do
82
+ it "allows nested_forms to be built" do
83
+ form.build_mailing_addresses(:address => OpenStruct.new)
84
+ form.mailing_addresses.should be_an(Array)
85
+ form.mailing_addresses.should_not be_empty
86
+ form.mailing_addresses.first.should be_a(Module::MailingAddressForm)
68
87
  end
69
-
88
+
70
89
  it "allows nested_forms to be built with custom initializers" do
71
90
  form.build_mailing_address(:address => OpenStruct.new(:street => "1600 Pennsylvania Ave."))
72
91
  form.mailing_addresses.first.street.should eq("1600 Pennsylvania Ave.")
73
92
  end
93
+ end
94
+ end
95
+
96
+ describe "setting attributes" do
97
+ describe "nested attribute assignment" do
98
+ let(:attributes) do
99
+ { :mailing_addresses_attributes => { "0" => { :street => "123 Main St." } } }
100
+ end
74
101
 
75
- it "reflects on association" do
76
- reflection = form_class.reflect_on_association(:mailing_addresses)
77
- reflection.klass.should eq(Module::DummyForm::MailingAddressesForm)
102
+ it "assigns nested attributes" do
103
+ form.fill(attributes)
104
+ form.mailing_addresses.first.street.should eq("123 Main St.")
78
105
  end
79
106
  end
80
-
81
- describe "setting attributes" do
82
- describe "nested attribute assignment" do
83
- let(:attributes) do
84
- { :mailing_addresses_attributes => { "0" => { :street => "123 Main St." } } }
85
- end
86
-
87
- it "assigns nested attributes" do
88
- form.fill(attributes)
89
- form.mailing_addresses.first.street.should eq("123 Main St.")
90
- end
91
- end
92
- end
93
- end
107
+ end
94
108
  end
95
109
  end
@@ -141,6 +141,39 @@ describe FreeForm::Property do
141
141
  form_class.models.should eq([:test_model_1, :test_model_2])
142
142
  end
143
143
  end
144
+
145
+ describe "child models", :child_models => true do
146
+ let(:form_class) do
147
+ Class.new(Module) do
148
+ include FreeForm::Property
149
+ form_model :test_model_1
150
+ child_model :test_model_2 do
151
+ test_model_1.build_child
152
+ end
153
+
154
+ def initialize(h={})
155
+ h.each {|k,v| send("#{k}=",v)}
156
+ initialize_test_model_2
157
+ end
158
+ end
159
+ end
160
+
161
+ let(:form) do
162
+ form_class.new(
163
+ :test_model_1 => OpenStruct.new(:dummy => "yes",
164
+ :build_child => OpenStruct.new(:field => "child model"))
165
+ )
166
+ end
167
+
168
+ it "sets declared models as accessor" do
169
+ form.test_model_1.should eq(OpenStruct.new(:dummy => "yes", :build_child => OpenStruct.new(:field => "child model")))
170
+ form.test_model_2.should eq(OpenStruct.new(:field => "child model"))
171
+ end
172
+
173
+ it "sets @models in class to declared models" do
174
+ form_class.models.should eq([:test_model_1, :test_model_2])
175
+ end
176
+ end
144
177
  end
145
178
 
146
179
  describe "properties", :properties => true do
@@ -152,6 +185,7 @@ describe FreeForm::Property do
152
185
 
153
186
  property :attribute_1, :on => :test_model
154
187
  property :attribute_2, :on => :test_model, :ignore_blank => true
188
+ property :attribute_3, :as => :test_attribute_3, :on => :test_model
155
189
 
156
190
  def initialize(h={})
157
191
  h.each {|k,v| send("#{k}=",v)}
@@ -165,25 +199,144 @@ describe FreeForm::Property do
165
199
  )
166
200
  end
167
201
 
168
- it "delegates properties to models" do
169
- form.attribute_1.should eq("yes")
170
- form.attribute_2.should be_nil
171
- end
172
-
173
- it "allows properties to be written, and delegates the values" do
174
- form.attribute_1 = "changed"
175
- form.attribute_1.should eq("changed")
176
- form.test_model.attribute_1.should eq("changed")
177
- end
178
-
179
- it "tracks ignored blank fields" do
180
- form_class.ignored_blank_params.should eq([:attribute_2])
181
- end
202
+ describe "delegation" do
203
+ it "delegates properties to models" do
204
+ form.attribute_1.should eq("yes")
205
+ form.attribute_2.should be_nil
206
+ end
207
+
208
+ it "allows properties to be written, and delegates the values" do
209
+ form.attribute_1 = "changed"
210
+ form.attribute_1.should eq("changed")
211
+ form.test_model.attribute_1.should eq("changed")
212
+ end
213
+
214
+ it "delegates using :as" do
215
+ form.test_attribute_3.should be_nil
216
+ form.test_attribute_3 = "set_using_as"
217
+ form.test_attribute_3.should eq("set_using_as")
218
+ form.test_model.attribute_3.should eq("set_using_as")
219
+ end
220
+ end
221
+
222
+ describe "property_mappings" do
223
+ it "sets appropriate property mappings" do
224
+ form_class.property_mappings.should eq(
225
+ { :attribute_1 => {:model => :test_model, :field => :attribute_1, :ignore_blank => false},
226
+ :attribute_2 => {:model => :test_model, :field => :attribute_2, :ignore_blank => true},
227
+ :test_attribute_3 => {:model => :test_model, :field => :attribute_3, :ignore_blank => false}
228
+ }
229
+ )
230
+ end
231
+ end
232
+ end
233
+
234
+ describe "allow_destroy_on_save", :allow_destroy_on_save => true do
235
+ let(:form_class) do
236
+ Class.new(Module) do
237
+ include FreeForm::Property
238
+ declared_model :test_model
239
+ allow_destroy_on_save
240
+
241
+ property :attribute_1, :on => :test_model
242
+ property :attribute_2, :on => :test_model, :ignore_blank => true
243
+
244
+ def initialize(h={})
245
+ h.each {|k,v| send("#{k}=",v)}
246
+ end
247
+ end
248
+ end
249
+
250
+ let(:form) do
251
+ form_class.new(:test_model => OpenStruct.new)
252
+ end
253
+
254
+ it "has _destroy accessor" do
255
+ form.should respond_to(:_destroy)
256
+ end
257
+
258
+ it "has marked_for_destruction? accessor" do
259
+ form.should respond_to(:marked_for_destruction?)
260
+ end
261
+
262
+ it "has destroy as false by default" do
263
+ form._destroy.should be_false
264
+ end
265
+
266
+ it "has marked_for_destruction? as false by default" do
267
+ form.marked_for_destruction?.should be_false
268
+ end
269
+
270
+ it "can be marked for destruction" do
271
+ form.marked_for_destruction?.should be_false
272
+ form.mark_for_destruction
273
+ form.marked_for_destruction?.should be_true
274
+ end
275
+
276
+ it "interprets '0' is not marked for destruction" do
277
+ form.fill({:_destroy => "0"})
278
+ form.marked_for_destruction?.should be_false
279
+ end
280
+
281
+ it "interprets 'false' is not marked for destruction" do
282
+ form.fill({:_destroy => "false"})
283
+ form.marked_for_destruction?.should be_false
284
+ end
285
+
286
+ it "interprets '1' is marked for destruction" do
287
+ form.fill({:_destroy => "1"})
288
+ form.marked_for_destruction?.should be_true
289
+ end
290
+
291
+ it "interprets 'true' is marked for destruction" do
292
+ form.fill({:_destroy => "true"})
293
+ form.marked_for_destruction?.should be_true
294
+ end
295
+
296
+ it "interprets '2' is marked for destruction" do
297
+ form.fill({:_destroy => "2"})
298
+ form.marked_for_destruction?.should be_true
299
+ end
182
300
  end
183
301
  end
184
302
  end
185
303
 
186
304
  describe "instance methods", :instance_methods => true do
305
+ describe "parent_form", :parent_form => true do
306
+ let(:form_class) do
307
+ Class.new(Module) do
308
+ include FreeForm::Property
309
+ declared_model :first_model
310
+ declared_model :second_model
311
+
312
+ property :attribute_1, :on => :first_model
313
+ property :attribute_2, :on => :first_model, :ignore_blank => true
314
+ property :attribute_3, :on => :second_model, :ignore_blank => true
315
+ property :attribute_4, :on => :second_model
316
+
317
+ def initialize(h)
318
+ h.each {|k,v| send("#{k}=",v)}
319
+ end
320
+ end
321
+ end
322
+
323
+ let(:form) do
324
+ form_class.new(
325
+ :first_model => OpenStruct.new(:attribute_1 => "first", :attribute_2 => "second"),
326
+ :second_model => OpenStruct.new(:attribute_3 => "third", :attribute_4 => "fourth"),
327
+ )
328
+ end
329
+
330
+ it "has parent_form as nil by default" do
331
+ form.parent_form.should be_nil
332
+ end
333
+
334
+ it "has can assign and reference parent_form" do
335
+ parent = Module.new
336
+ form.parent_form = parent
337
+ form.parent_form.should eq(parent)
338
+ end
339
+ end
187
340
  describe "assign_attributes", :assign_attributes => true do
188
341
  let(:form_class) do
189
342
  Class.new(Module) do