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.
data/lib/freeform/form.rb CHANGED
@@ -2,6 +2,7 @@ require 'forwardable'
2
2
  require 'ostruct'
3
3
  require 'active_model'
4
4
  require 'freeform/form/form_input_key'
5
+ require 'freeform/form/model'
5
6
  require 'freeform/form/nested'
6
7
  require 'freeform/form/property'
7
8
  require 'freeform/form/validation'
@@ -15,10 +16,15 @@ module FreeForm
15
16
  include ActiveModel::Conversion
16
17
  include ActiveModel::Validations
17
18
  include FreeForm::FormInputKey
19
+ include FreeForm::Model
18
20
  include FreeForm::Nested
19
21
  include FreeForm::Property
20
22
  include FreeForm::Validation
21
23
 
24
+ # Default Validations
25
+ #----------------------------------------------------------------------------
26
+ validate_nested_forms
27
+
22
28
  # Instance Methods
23
29
  #----------------------------------------------------------------------------
24
30
  # Required for ActiveModel
@@ -30,61 +36,44 @@ module FreeForm
30
36
  end
31
37
 
32
38
  def save
33
- return false unless valid? || marked_for_destruction?
34
-
35
- # Save or destroy myself.
36
- self.class.models.each do |form_model|
37
- model = send(form_model)
38
- # This is for form models.
39
- unless model.is_a?(Array)
40
- if marked_for_destruction?
41
- model.destroy
42
- else
43
- model.save
44
- end
45
- end
46
- end
47
-
48
- # Loop through nested models sending them the save call
49
- self.class.models.each do |form_model|
50
- model = send(form_model)
51
- # This is for nested models.
52
- if model.is_a?(Array)
53
- model.each { |m| m.save }
54
- end
39
+ if valid?
40
+ before_save
41
+ models.each { |m| m.destroy if m.marked_for_destruction? }
42
+ models.each { |m| m.save unless m.marked_for_destruction? }
43
+ after_save
44
+ true
45
+ else
46
+ false
55
47
  end
56
48
  end
57
49
 
58
50
  def save!
59
- raise FreeForm::FormInvalid, "form invalid." unless valid?
60
-
61
- self.class.models.each do |form_model|
62
- model = send(form_model)
63
- model.is_a?(Array) ? model.each { |m| m.save! } : save_or_destroy!(model)
51
+ if valid?
52
+ save
53
+ else
54
+ raise FreeForm::FormInvalid, "form invalid."
64
55
  end
65
56
  end
66
57
 
67
- private
68
- def initialize_child_models
69
- self.class.child_models.each do |c|
70
- send("initialize_#{c}")
71
- end
58
+ def destroy
59
+ models.each { |m| m.destroy }
72
60
  end
73
61
 
74
- def save_or_destroy(model)
75
- marked_for_destruction? ? model.destroy : model.save
62
+ def marked_for_destruction?
63
+ respond_to?(:_destroy) ? _destroy : false
76
64
  end
77
65
 
78
- def save_or_destroy!(model)
79
- if marked_for_destruction?
80
- model.destroy
81
- else
82
- model.save!
83
- end
66
+ def before_save
84
67
  end
85
68
 
86
- def marked_for_destruction?
87
- respond_to?(:_destroy) ? _destroy : false
69
+ def after_save
70
+ end
71
+
72
+ private
73
+ def initialize_child_models
74
+ self.class.child_models.each do |c|
75
+ send("initialize_#{c}")
76
+ end
88
77
  end
89
78
  end
90
79
  end
@@ -1,3 +1,3 @@
1
1
  module Freeform
2
- VERSION = "1.0.11"
2
+ VERSION = "2.0.0"
3
3
  end
@@ -1,30 +1,13 @@
1
1
  require 'spec_helper'
2
+ require 'freeform/form'
2
3
 
3
4
  describe FreeForm::Form do
4
- let!(:task_class) do
5
- klass = Class.new(FreeForm::Form) do
6
- form_input_key :task
7
- form_model :task
8
- validate_models
9
- allow_destroy_on_save
10
-
11
- property :name, :on => :task
12
- property :start_date, :on => :task
13
- property :end_date, :on => :task
14
- end
15
- # This wrapper just avoids CONST warnings
16
- v, $VERBOSE = $VERBOSE, nil
17
- Module.const_set("TaskForm", klass)
18
- $VERBOSE = v
19
- klass
20
- end
21
-
22
5
  let(:form_class) do
23
6
  klass = Class.new(FreeForm::Form) do
24
7
  form_input_key :company
25
8
  form_models :company
26
9
  child_model :project do
27
- company.project.present? ? company.project : company.build_project
10
+ company.project || company.build_project
28
11
  end
29
12
  validate_models
30
13
  allow_destroy_on_save
@@ -33,9 +16,18 @@ describe FreeForm::Form do
33
16
  property :name, :on => :project, :as => :project_name
34
17
  property :due_date, :on => :project
35
18
 
36
- has_many :tasks, :class => Module::TaskForm, :default_initializer => :default_task_initializer
19
+ has_many :tasks do
20
+ form_input_key :task
21
+ form_model :task
22
+ validate_models
23
+ allow_destroy_on_save
24
+
25
+ property :name, :on => :task
26
+ property :start_date, :on => :task
27
+ property :end_date, :on => :task
28
+ end
37
29
 
38
- def default_task_initializer
30
+ def task_initializer
39
31
  { :task => project.tasks.build }
40
32
  end
41
33
  end
@@ -46,35 +38,48 @@ describe FreeForm::Form do
46
38
  klass
47
39
  end
48
40
 
41
+ let(:company) { Company.create!(:name => "Demo Corporation") }
42
+ let(:project) { Project.create!(:owner => company, :name => "Widget", :due_date => Date.new(2014, 1, 1)) }
43
+ let(:task_1) { Task.create!(:project => project, :name => "Task 1", :start_date => Date.new(2014, 2, 2), :end_date => Date.new(2014, 3, 3)) }
44
+ let(:task_2) { Task.create!(:project => project, :name => "Task 2", :start_date => Date.new(2014, 9, 1), :end_date => Date.new(2014, 10, 1)) }
45
+
49
46
  let(:form) do
50
- form_class.new( :company => Company.new ).tap do |f|
51
- f.build_task
47
+ form_class.new( :company => company ).tap do |f|
48
+ company.project.tasks.each do |task|
49
+ f.build_task(:task => task)
50
+ end
52
51
  end
53
52
  end
54
53
 
54
+ before(:each) do
55
+ company.reload
56
+ project.reload
57
+ task_1.reload
58
+ task_2.reload
59
+ end
60
+
55
61
  describe "form initialization", :initialization => true do
56
62
  it "initializes with Company model" do
57
- form.company.should be_a(Company)
63
+ form.company.should eq(company)
58
64
  end
59
65
 
60
66
  it "initializes with Project model" do
61
- form.project.should be_a(Project)
67
+ form.project.should eq(project)
62
68
  end
63
69
 
64
70
  it "initializes with Task model" do
65
- form.tasks.first.task.should be_a(Task)
71
+ form.tasks.first.task.should eq(task_1)
66
72
  end
67
73
 
68
74
  it "initializes with Task with project parent" do
69
75
  task = form.tasks.first.task
70
- task.should eq(form.project.tasks.first)
76
+ task.project.should eq(form.project)
71
77
  end
72
78
  end
73
79
 
74
80
  describe "building nested models", :nested_models => true do
75
81
  it "can build multiple tasks" do
76
- form.tasks.count.should eq(1)
77
- form.build_task
82
+ form.tasks.count.should eq(2)
78
83
  form.build_task
79
84
  form.tasks.count.should eq(3)
80
85
  end
@@ -85,6 +90,13 @@ describe FreeForm::Form do
85
90
  task_2 = form.tasks.last.task
86
91
  task_1.should_not eq(task_2)
87
92
  end
93
+
94
+ it "builds new tasks with project parent" do
95
+ form.build_task
96
+ task_1 = form.tasks.first.task
97
+ task_2 = form.tasks.last.task
98
+ task_1.project.should eq(task_2.project)
99
+ end
88
100
  end
89
101
 
90
102
  describe "assigning parameters", :assign_params => true do
@@ -187,8 +199,8 @@ describe FreeForm::Form do
187
199
  form.errors[:project_name].should eq(["can't be blank"])
188
200
  end
189
201
 
190
- it "should have errors on last tasks's start_date" do
191
- form.tasks.last.errors[:start_date].should eq(["can't be blank"])
202
+ it "should not have errors on last tasks's start_date" do
203
+ form.tasks.last.errors[:start_date].should be_empty
192
204
  end
193
205
  end
194
206
 
@@ -202,9 +214,9 @@ describe FreeForm::Form do
202
214
  :tasks_attributes => {
203
215
  "0" => {
204
216
  :name => "task_1",
205
- "start_date(1i)" => "2012",
206
- "start_date(2i)" => "1",
207
- "start_date(3i)" => "2",
217
+ "start_date(1i)" => nil,
218
+ "start_date(2i)" => nil,
219
+ "start_date(3i)" => nil,
208
220
  },
209
221
  "1" => {
210
222
  :name => "task_2",
@@ -224,84 +236,8 @@ describe FreeForm::Form do
224
236
  form.should_not be_valid
225
237
  end
226
238
 
227
- it "should have errors on last tasks's start_date" do
228
- form.tasks.last.errors[:start_date].should eq(["can't be blank"])
229
- end
230
- end
231
-
232
- context "with invalid form, and invalid marked for destruction nested model" do
233
- let(:attributes) do {
234
- :company_name => "",
235
- :project_name => "rails app",
236
- "due_date(1i)" => "2014",
237
- "due_date(2i)" => "10",
238
- "due_date(3i)" => "30",
239
- :tasks_attributes => {
240
- "0" => {
241
- :name => "task_1",
242
- "start_date(1i)" => "2012",
243
- "start_date(2i)" => "1",
244
- "start_date(3i)" => "2",
245
- },
246
- "1" => {
247
- :name => "task_2",
248
- "end_date(1i)" => "2011",
249
- "end_date(2i)" => "12",
250
- "end_date(3i)" => "15",
251
- :_destroy => "1"
252
- }
253
- } }
254
- end
255
-
256
- before(:each) do
257
- form.fill(attributes)
258
- form.valid?
259
- end
260
-
261
- it "should not be valid" do
262
- form.should_not be_valid
263
- end
264
-
265
- it "should not have errors" do
266
- form.errors[:company_name].should eq(["can't be blank"])
267
- end
268
- end
269
-
270
- context "with marked for destruction invalid nested model" do
271
- let(:attributes) do {
272
- :company_name => "dummycorp",
273
- :project_name => "rails app",
274
- "due_date(1i)" => "2014",
275
- "due_date(2i)" => "10",
276
- "due_date(3i)" => "30",
277
- :tasks_attributes => {
278
- "0" => {
279
- :name => "task_1",
280
- "start_date(1i)" => "2012",
281
- "start_date(2i)" => "1",
282
- "start_date(3i)" => "2",
283
- },
284
- "1" => {
285
- :name => "task_2",
286
- "end_date(1i)" => "2011",
287
- "end_date(2i)" => "12",
288
- "end_date(3i)" => "15",
289
- :_destroy => "1"
290
- }
291
- } }
292
- end
293
-
294
- before(:each) do
295
- form.fill(attributes)
296
- form.valid?
297
- end
298
-
299
- it "should be valid" do
300
- form.should be_valid
301
- end
302
-
303
- it "should not have errors" do
304
- form.errors.should be_empty
239
+ it "should have errors on first tasks's start_date" do
240
+ form.tasks.first.errors[:start_date].should eq(["can't be blank"])
305
241
  end
306
242
  end
307
243
 
@@ -369,19 +305,45 @@ describe FreeForm::Form do
369
305
  form.fill(attributes)
370
306
  end
371
307
 
372
- it "should return false on 'save'" do
373
- form.save.should be_false
308
+ describe "#save" do
309
+ it "should return false on 'save'" do
310
+ form.save.should be_false
311
+ end
312
+
313
+ it "does not update company model" do
314
+ form.save
315
+ company.reload.name.should_not eq("dummycorp")
316
+ end
317
+
318
+ it "does not update project model" do
319
+ form.save
320
+ project.reload.due_date.should_not eq(Date.new(2014, 10, 30))
321
+ end
322
+
323
+ it "does not update the first task model" do
324
+ form.save
325
+ task_1.reload.name.should_not eq("task_1")
326
+ task_1.reload.start_date.should_not eq(Date.new(2012, 1, 2))
327
+ end
328
+
329
+ it "does not update the second task model" do
330
+ form.save
331
+ task_2.reload.name.should_not eq("task_2")
332
+ task_2.reload.end_date.should_not eq(Date.new(2011, 12, 15))
333
+ end
374
334
  end
375
335
 
376
- it "should raise error on 'save!'" do
377
- expect{ form.save! }.to raise_error(FreeForm::FormInvalid)
336
+ describe "#save!" do
337
+ it "should raise error on 'save!'" do
338
+ expect{ form.save! }.to raise_error(FreeForm::FormInvalid)
339
+ end
378
340
  end
379
341
  end
380
342
 
381
- context "with invalid attributes, and marked for destruction nested model" do
343
+ context "with invalid, marked for destruction attributes" do
382
344
  let(:attributes) do {
383
345
  :company_name => "dummycorp",
384
- :project_name => "",
346
+ :project_name => "my_project",
385
347
  "due_date(1i)" => "2014",
386
348
  "due_date(2i)" => "10",
387
349
  "due_date(3i)" => "30",
@@ -392,8 +354,8 @@ describe FreeForm::Form do
392
354
  "start_date(2i)" => "1",
393
355
  "start_date(3i)" => "2",
394
356
  },
395
- "3234322345" => {
396
- :name => "task_2",
357
+ "1" => {
358
+ :name => nil,
397
359
  "end_date(1i)" => "2011",
398
360
  "end_date(2i)" => "12",
399
361
  "end_date(3i)" => "15",
@@ -406,82 +368,40 @@ describe FreeForm::Form do
406
368
  form.fill(attributes)
407
369
  end
408
370
 
409
- it "should not be valid" do
410
- form.should_not be_valid
411
- end
371
+ describe "#save" do
372
+ it "should return true on 'save'" do
373
+ form.save.should be_true
374
+ end
412
375
 
413
- describe "persisting destroy after failed save" do
414
- before(:each) { form.save }
376
+ it "updates company model" do
377
+ form.save
378
+ company.reload.name.should eq("dummycorp")
379
+ end
415
380
 
416
- it "should have the second form still set to _destroy" do
417
- form.tasks.second.should be_marked_for_destruction
381
+ it "updates project model" do
382
+ form.save
383
+ project.reload.name.should eq("my_project")
384
+ project.reload.due_date.should eq(Date.new(2014, 10, 30))
418
385
  end
419
- end
420
386
 
421
- # it "should have valid company and project after save", :failing => true do
422
- # form.save
423
- # # form.tasks.first.task.destroy
424
- # form.company.should be_valid
425
- # form.project.valid?
426
- # puts "Errors = #{form.project.errors.inspect}"
427
- # form.project.should be_valid
428
- # end
429
-
430
- # it "should not raise error on 'save!'" do
431
- # expect{ form.save! }.to_not raise_error
432
- # end
433
- end
434
-
435
- context "with invalid, marked for destruction nested model" do
436
- let(:attributes) do {
437
- :company_name => "dummycorp",
438
- :project_name => "railsapp",
439
- "due_date(1i)" => "2014",
440
- "due_date(2i)" => "10",
441
- "due_date(3i)" => "30",
442
- :tasks_attributes => {
443
- "0" => {
444
- :name => "task_1",
445
- "start_date(1i)" => "2012",
446
- "start_date(2i)" => "1",
447
- "start_date(3i)" => "2",
448
- },
449
- "1" => {
450
- :name => "task_2",
451
- "end_date(1i)" => "2011",
452
- "end_date(2i)" => "12",
453
- "end_date(3i)" => "15",
454
- :_destroy => "1"
455
- }
456
- } }
457
- end
387
+ it "updates the first task model" do
388
+ form.save
389
+ task_1.reload.name.should eq("task_1")
390
+ task_1.reload.start_date.should eq(Date.new(2012, 1, 2))
391
+ end
458
392
 
459
- before(:each) do
460
- form.fill(attributes)
393
+ it "destroys the second task model", :failing => true do
394
+ form.save
395
+ task_2.should_not exist_in_database
396
+ end
461
397
  end
462
398
 
463
- it { is pending }
464
-
465
- # it "should have valid company and project after save", :failing => true do
466
- # form.save
467
- # # form.tasks.last.task.destroy
468
- # # form.valid?
469
- # form.company.should be_valid
470
- # form.project.valid?
471
- # # puts "Errors = #{form.project.errors.inspect}"
472
-
473
- # # form.project.tasks.each do |task|
474
- # # puts "Task = #{task.inspect}"
475
- # # puts "Valid = #{task.valid?}"
476
- # # puts "Errors = #{task.errors.inspect}"
477
- # # end
478
- # form.project.should be_valid
479
- # end
480
-
481
- # # it "should not raise error on 'save!'" do
482
- # # expect{ form.save! }.to_not raise_error
483
- # # end
399
+ describe "#save!" do
400
+ it "should not raise error on 'save!'" do
401
+ expect{ form.save! }.to_not raise_error
402
+ end
484
403
  end
404
+ end
485
405
 
486
406
  context "with valid attributes" do
487
407
  let(:attributes) do {
@@ -492,13 +412,13 @@ describe FreeForm::Form do
492
412
  "due_date(3i)" => "30",
493
413
  :tasks_attributes => {
494
414
  "0" => {
495
- :name => "task_1",
415
+ :name => "new_task_1",
496
416
  "start_date(1i)" => "2012",
497
417
  "start_date(2i)" => "1",
498
418
  "start_date(3i)" => "2",
499
419
  },
500
420
  "1" => {
501
- :name => "task_2",
421
+ :name => "new_task_2",
502
422
  "start_date(1i)" => "2011",
503
423
  "start_date(2i)" => "8",
504
424
  "start_date(3i)" => "15",
@@ -513,81 +433,41 @@ describe FreeForm::Form do
513
433
  form.fill(attributes)
514
434
  end
515
435
 
516
- it "should return true on 'save', and call save on other models" do
517
- form.company.should_receive(:save).and_return(true)
518
- form.project.should_receive(:save).and_return(true)
519
- form.tasks.first.task.should_receive(:save).and_return(true)
520
- form.tasks.last.task.should_receive(:save).and_return(true)
521
- form.save
522
- end
436
+ describe "#save" do
437
+ it "should return true on 'save'" do
438
+ form.save.should be_true
439
+ end
523
440
 
524
- it "should return true on 'save!', and call save! on other models" do
525
- form.company.should_receive(:save!).and_return(true)
526
- form.project.should_receive(:save!).and_return(true)
527
- form.tasks.first.task.should_receive(:save!).and_return(true)
528
- form.tasks.last.task.should_receive(:save!).and_return(true)
529
- form.save!
530
- end
441
+ it "updates company model" do
442
+ form.save
443
+ company.reload.name.should eq("dummycorp")
444
+ end
531
445
 
532
- describe "destroying on save", :destroy_on_save => true do
533
- describe "save" do
534
- it "destroys models on save if set" do
535
- form._destroy = true
536
- form.company.should_receive(:destroy).and_return(true)
537
- form.project.should_receive(:destroy).and_return(true)
538
- form.tasks.first.task.should_receive(:save).and_return(true)
539
- form.tasks.last.task.should_receive(:save).and_return(true)
540
- form.save
541
- end
542
-
543
- it "destroys models on save if set through attribute" do
544
- form.fill({:_destroy => "1"})
545
- form.company.should_receive(:destroy).and_return(true)
546
- form.project.should_receive(:destroy).and_return(true)
547
- form.tasks.first.task.should_receive(:save).and_return(true)
548
- form.tasks.last.task.should_receive(:save).and_return(true)
549
- form.save
550
- end
551
-
552
- it "destroys nested models on save if set" do
553
- form.tasks.first._destroy = true
554
- form.company.should_receive(:save).and_return(true)
555
- form.project.should_receive(:save).and_return(true)
556
- form.tasks.first.task.should_receive(:destroy).and_return(true)
557
- form.tasks.last.task.should_receive(:save).and_return(true)
558
- form.save
559
- end
446
+ it "updates project model" do
447
+ form.save
448
+ project.reload.name.should eq("railsapp")
449
+ project.reload.due_date.should eq(Date.new(2014, 10, 30))
560
450
  end
561
451
 
562
- describe "save!" do
563
- it "destroys models on save! if set" do
564
- form._destroy = true
565
- form.company.should_receive(:destroy).and_return(true)
566
- form.project.should_receive(:destroy).and_return(true)
567
- form.tasks.first.task.should_receive(:save!).and_return(true)
568
- form.tasks.last.task.should_receive(:save!).and_return(true)
569
- form.save!
570
- end
571
-
572
- it "destroys models on save! if set" do
573
- form.fill({:_destroy => "1"})
574
- form.company.should_receive(:destroy).and_return(true)
575
- form.project.should_receive(:destroy).and_return(true)
576
- form.tasks.first.task.should_receive(:save!).and_return(true)
577
- form.tasks.last.task.should_receive(:save!).and_return(true)
578
- form.save!
579
- end
580
-
581
- it "destroys nested models on save! if set" do
582
- form.tasks.last._destroy = true
583
- form.company.should_receive(:save!).and_return(true)
584
- form.project.should_receive(:save!).and_return(true)
585
- form.tasks.first.task.should_receive(:save!).and_return(true)
586
- form.tasks.last.task.should_receive(:destroy).and_return(true)
587
- form.save!
588
- end
452
+ it "updates the first task model" do
453
+ form.save
454
+ task_1.reload.name.should eq("new_task_1")
455
+ task_1.reload.start_date.should eq(Date.new(2012, 1, 2))
456
+ end
457
+
458
+ it "updates the second task model" do
459
+ form.save
460
+ task_2.reload.name.should eq("new_task_2")
461
+ task_2.reload.start_date.should eq(Date.new(2011, 8, 15))
462
+ task_2.reload.end_date.should eq(Date.new(2011, 12, 15))
463
+ end
464
+ end
465
+
466
+ describe "#save!" do
467
+ it "should not raise error on 'save!'" do
468
+ expect{ form.save! }.to_not raise_error
589
469
  end
590
470
  end
591
471
  end
592
472
  end
593
- end
473
+ end