worth_saving 0.0.9

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 (115) hide show
  1. checksums.yaml +15 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +90 -0
  4. data/Rakefile +29 -0
  5. data/app/assets/javascripts/worth_saving/application.js +15 -0
  6. data/app/assets/stylesheets/worth_saving/application.css +13 -0
  7. data/app/controllers/worth_saving/application_controller.rb +4 -0
  8. data/app/controllers/worth_saving/drafts_controller.rb +51 -0
  9. data/app/helpers/worth_saving/application_helper.rb +4 -0
  10. data/app/models/worth_saving/draft.rb +47 -0
  11. data/app/views/layouts/worth_saving/application.html.erb +14 -0
  12. data/config/routes.rb +3 -0
  13. data/db/migrate/20130911055236_create_worth_saving_drafts.rb +16 -0
  14. data/lib/tasks/worth_saving_tasks.rake +4 -0
  15. data/lib/worth_saving.rb +12 -0
  16. data/lib/worth_saving/action_view_ext.rb +11 -0
  17. data/lib/worth_saving/active_record_ext.rb +39 -0
  18. data/lib/worth_saving/engine.rb +15 -0
  19. data/lib/worth_saving/form.rb +15 -0
  20. data/lib/worth_saving/form/base.rb +21 -0
  21. data/lib/worth_saving/form/record.rb +53 -0
  22. data/lib/worth_saving/form/rendering.rb +100 -0
  23. data/lib/worth_saving/form_builder.rb +57 -0
  24. data/lib/worth_saving/info.rb +102 -0
  25. data/lib/worth_saving/version.rb +3 -0
  26. data/spec/app/controllers/drafts_controller_spec.rb +13 -0
  27. data/spec/app/models/worth_saving/draft_spec.rb +156 -0
  28. data/spec/dummy/README.rdoc +261 -0
  29. data/spec/dummy/Rakefile +7 -0
  30. data/spec/dummy/app/assets/javascripts/application.js +15 -0
  31. data/spec/dummy/app/assets/stylesheets/application.css +15 -0
  32. data/spec/dummy/app/controllers/application_controller.rb +24 -0
  33. data/spec/dummy/app/controllers/login_controller.rb +11 -0
  34. data/spec/dummy/app/controllers/pages_controller.rb +48 -0
  35. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  36. data/spec/dummy/app/models/page.rb +12 -0
  37. data/spec/dummy/app/models/subpage.rb +7 -0
  38. data/spec/dummy/app/models/user.rb +4 -0
  39. data/spec/dummy/app/views/layouts/application.html.erb +15 -0
  40. data/spec/dummy/app/views/pages/form.html.slim +53 -0
  41. data/spec/dummy/config.ru +4 -0
  42. data/spec/dummy/config/application.rb +66 -0
  43. data/spec/dummy/config/boot.rb +10 -0
  44. data/spec/dummy/config/database.yml +25 -0
  45. data/spec/dummy/config/environment.rb +5 -0
  46. data/spec/dummy/config/environments/development.rb +37 -0
  47. data/spec/dummy/config/environments/production.rb +67 -0
  48. data/spec/dummy/config/environments/test.rb +37 -0
  49. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  50. data/spec/dummy/config/initializers/inflections.rb +15 -0
  51. data/spec/dummy/config/initializers/mime_types.rb +5 -0
  52. data/spec/dummy/config/initializers/secret_token.rb +7 -0
  53. data/spec/dummy/config/initializers/session_store.rb +8 -0
  54. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  55. data/spec/dummy/config/locales/en.yml +5 -0
  56. data/spec/dummy/config/routes.rb +8 -0
  57. data/spec/dummy/db/development.sqlite3 +0 -0
  58. data/spec/dummy/db/migrate/20130911060226_create_worth_saving_drafts.worth_saving.rb +17 -0
  59. data/spec/dummy/db/migrate/20130912071319_create_users.rb +9 -0
  60. data/spec/dummy/db/migrate/20130912071446_create_pages.rb +9 -0
  61. data/spec/dummy/db/migrate/20130912145831_create_subpages.rb +10 -0
  62. data/spec/dummy/db/migrate/20130913060709_add_columns_to_subpages.rb +5 -0
  63. data/spec/dummy/db/migrate/20130913060847_add_columns_to_pages.rb +7 -0
  64. data/spec/dummy/db/schema.rb +52 -0
  65. data/spec/dummy/db/test.sqlite3 +0 -0
  66. data/spec/dummy/log/development.log +17536 -0
  67. data/spec/dummy/log/test.log +76256 -0
  68. data/spec/dummy/public/404.html +26 -0
  69. data/spec/dummy/public/422.html +26 -0
  70. data/spec/dummy/public/500.html +25 -0
  71. data/spec/dummy/public/favicon.ico +0 -0
  72. data/spec/dummy/script/rails +6 -0
  73. data/spec/dummy/tmp/cache/assets/CA6/7A0/sprockets%2Ff6723fb0918cb134f62480f155a0b364 +0 -0
  74. data/spec/dummy/tmp/cache/assets/CD8/370/sprockets%2F357970feca3ac29060c1e3861e2c0953 +0 -0
  75. data/spec/dummy/tmp/cache/assets/CF8/AF0/sprockets%2F228f63c526665cc53d670799eece3b98 +0 -0
  76. data/spec/dummy/tmp/cache/assets/D09/190/sprockets%2F993fae97313ed7d42322c85e60b02bb1 +0 -0
  77. data/spec/dummy/tmp/cache/assets/D1C/CE0/sprockets%2F9a5f4484900982bd33f792ca06e7f5ea +0 -0
  78. data/spec/dummy/tmp/cache/assets/D31/620/sprockets%2F01f101ae68348ed1bb4e46d7f452a73a +0 -0
  79. data/spec/dummy/tmp/cache/assets/D32/A10/sprockets%2F13fe41fee1fe35b49d145bcc06610705 +0 -0
  80. data/spec/dummy/tmp/cache/assets/D3C/300/sprockets%2Ffb893496ed88af814fa985858f60ee66 +0 -0
  81. data/spec/dummy/tmp/cache/assets/D43/EB0/sprockets%2F43d74a38cb4f14de5087ea7f871ac166 +0 -0
  82. data/spec/dummy/tmp/cache/assets/D4E/1B0/sprockets%2Ff7cbd26ba1d28d48de824f0e94586655 +0 -0
  83. data/spec/dummy/tmp/cache/assets/D5A/EA0/sprockets%2Fd771ace226fc8215a3572e0aa35bb0d6 +0 -0
  84. data/spec/dummy/tmp/cache/assets/D97/C50/sprockets%2F74b5c193fc06fb3cb3c4ac12ac7589a7 +0 -0
  85. data/spec/dummy/tmp/cache/assets/D9E/470/sprockets%2F36bde6f05aa955c51ab2cd97b59e742a +0 -0
  86. data/spec/dummy/tmp/cache/assets/DCF/000/sprockets%2Fcfbeb9f4e8b3b7d1ac752d93c64017d3 +0 -0
  87. data/spec/dummy/tmp/cache/assets/DDC/400/sprockets%2Fcffd775d018f68ce5dba1ee0d951a994 +0 -0
  88. data/spec/dummy/tmp/cache/assets/E04/890/sprockets%2F2f5173deea6c795b8fdde723bb4b63af +0 -0
  89. data/spec/dummy/tmp/cache/assets/test/sprockets/01f101ae68348ed1bb4e46d7f452a73a +0 -0
  90. data/spec/dummy/tmp/cache/assets/test/sprockets/13fe41fee1fe35b49d145bcc06610705 +0 -0
  91. data/spec/dummy/tmp/cache/assets/test/sprockets/228f63c526665cc53d670799eece3b98 +0 -0
  92. data/spec/dummy/tmp/cache/assets/test/sprockets/2f5173deea6c795b8fdde723bb4b63af +0 -0
  93. data/spec/dummy/tmp/cache/assets/test/sprockets/357970feca3ac29060c1e3861e2c0953 +0 -0
  94. data/spec/dummy/tmp/cache/assets/test/sprockets/36bde6f05aa955c51ab2cd97b59e742a +0 -0
  95. data/spec/dummy/tmp/cache/assets/test/sprockets/43d74a38cb4f14de5087ea7f871ac166 +0 -0
  96. data/spec/dummy/tmp/cache/assets/test/sprockets/74b5c193fc06fb3cb3c4ac12ac7589a7 +0 -0
  97. data/spec/dummy/tmp/cache/assets/test/sprockets/993fae97313ed7d42322c85e60b02bb1 +0 -0
  98. data/spec/dummy/tmp/cache/assets/test/sprockets/9a5f4484900982bd33f792ca06e7f5ea +0 -0
  99. data/spec/dummy/tmp/cache/assets/test/sprockets/cfbeb9f4e8b3b7d1ac752d93c64017d3 +0 -0
  100. data/spec/dummy/tmp/cache/assets/test/sprockets/cffd775d018f68ce5dba1ee0d951a994 +0 -0
  101. data/spec/dummy/tmp/cache/assets/test/sprockets/d771ace226fc8215a3572e0aa35bb0d6 +0 -0
  102. data/spec/dummy/tmp/cache/assets/test/sprockets/f6723fb0918cb134f62480f155a0b364 +0 -0
  103. data/spec/dummy/tmp/cache/assets/test/sprockets/f7cbd26ba1d28d48de824f0e94586655 +0 -0
  104. data/spec/dummy/tmp/cache/assets/test/sprockets/fb893496ed88af814fa985858f60ee66 +0 -0
  105. data/spec/factories.rb +28 -0
  106. data/spec/features/worth_saving_features_spec.rb +60 -0
  107. data/spec/lib/active_record_ext_spec.rb +291 -0
  108. data/spec/lib/info_spec.rb +29 -0
  109. data/spec/spec_helper.rb +37 -0
  110. data/spec/support/features.rb +8 -0
  111. data/spec/support/features/helpers.rb +96 -0
  112. data/vendor/assets/javascripts/worth_saving.js +10 -0
  113. data/vendor/assets/javascripts/worth_saving/form.js +64 -0
  114. data/vendor/assets/stylesheets/worth_saving.css +18 -0
  115. metadata +424 -0
@@ -0,0 +1,21 @@
1
+ module WorthSaving
2
+ module Form
3
+ class Base
4
+ include WorthSaving::Form::Rendering
5
+ include WorthSaving::Form::Record
6
+
7
+ def initialize(template, record, options, &proc)
8
+ @template = template
9
+ @record = record
10
+ @proc = proc
11
+ @interval = options.delete(:save_interval) || WorthSaving::Engine.config.default_save_interval
12
+ @options = options.merge builder: WorthSaving::FormBuilder
13
+ end
14
+
15
+ def render
16
+ options[:worth_saving_recovery] = recovery?
17
+ render_form
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,53 @@
1
+ module WorthSaving
2
+ module Form
3
+ module Record
4
+ def self.included(base)
5
+ base.send :include, InstanceMethods
6
+ end
7
+
8
+ module InstanceMethods
9
+ private
10
+
11
+ def record
12
+ @record
13
+ end
14
+
15
+ def draft
16
+ @draft ||= object.worth_saving_draft
17
+ end
18
+
19
+ def options
20
+ @options
21
+ end
22
+
23
+ def object
24
+ @object ||= record.is_a?(Array) ? record.last : record
25
+ end
26
+
27
+ def recovery?
28
+ return @recovery if @recovery == true || @recovery == false
29
+ if draft.nil?
30
+ return @recovery = false
31
+ elsif draft.reconstituted_record.attributes == object.attributes
32
+ draft.destroy
33
+ return @recovery = false
34
+ end
35
+ @recovery = true
36
+ end
37
+
38
+ def rescued_object
39
+ @rescued_object ||= draft && draft.reconstituted_record
40
+ end
41
+
42
+ def rescued_record
43
+ if record.is_a? Array
44
+ rescued_record = record.dup
45
+ rescued_record.last = rescued_object
46
+ else
47
+ rescued_record = rescued_object
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,100 @@
1
+ module WorthSaving
2
+ module Form
3
+ module Rendering
4
+ def self.included(base)
5
+ base.send :include, InstanceMethods
6
+ end
7
+
8
+ module InstanceMethods
9
+ def render_form
10
+ recovery? ? recovery_forms : standard_form
11
+ end
12
+
13
+ private
14
+
15
+ def recovery_forms
16
+ form_container 'recovery', recovery_header, main_form_container, recovery_form_container
17
+ end
18
+
19
+ def standard_form
20
+ form_container 'standard', main_form_container, draft_status_footer, draft_form_container
21
+ end
22
+
23
+ def form_container(type, *elements)
24
+ content = elements.join("\n").html_safe
25
+ @template.content_tag :div, content, class: "worth-saving-#{type}-form-container"
26
+ end
27
+
28
+ def main_form_container
29
+ @template.content_tag :div, main_form, form_container_attributes('saved')
30
+ end
31
+
32
+ def recovery_form_container
33
+ @template.content_tag :div, recovery_form, form_container_attributes('recovered')
34
+ end
35
+
36
+ def draft_form_container
37
+ @template.content_tag :div, draft_form, style: 'display: none'
38
+ end
39
+
40
+ def draft_form
41
+ draft_object = draft || object.build_worth_saving_draft
42
+ @template.form_for(draft_object, draft_form_options) do |f|
43
+ WorthSaving::Form::WORTH_SAVING_DRAFT_FORM_BLOCK.call f
44
+ end
45
+ end
46
+
47
+ def draft_form_options
48
+ url = @template.worth_saving.drafts_path
49
+ { url: url, html: { data: { worth_saving_draft_form_id: form_id } } }
50
+ end
51
+
52
+ def main_form
53
+ @template.form_for record, main_form_options, &@proc
54
+ end
55
+
56
+ def main_form_options
57
+ return options if recovery?
58
+ user_data = options.delete(:data) || {}
59
+ options.deep_merge(
60
+ html: {
61
+ data: user_data.merge(
62
+ worth_saving_form_id: form_id,
63
+ worth_saving_interval: @interval,
64
+ )
65
+ }
66
+ )
67
+ end
68
+
69
+ def recovery_form
70
+ @template.form_for rescued_record, options.merge(namespace: 'recovered'), &@proc
71
+ end
72
+
73
+ def form_container_attributes(form_type)
74
+ {
75
+ id: "worth-saving-#{form_type}-form-container-#{form_id}",
76
+ class: "worth-saving-form-container"
77
+ }
78
+ end
79
+
80
+ def recovery_header
81
+ @template.content_tag(:div, recovery_message, class: 'worth-saving-header-message')
82
+ end
83
+
84
+ def recovery_message
85
+ options.delete(:recovery_message) || WorthSaving::Engine.config.default_recovery_message
86
+ end
87
+
88
+ def draft_status_footer
89
+ @template.content_tag(:div, '',
90
+ class: 'worth-saving-form-message', id: "worth-saving-form-message-#{form_id}"
91
+ )
92
+ end
93
+
94
+ def form_id
95
+ @form_id ||= WorthSaving::FormBuilder.next_form_id
96
+ end
97
+ end
98
+ end
99
+ end
100
+ end
@@ -0,0 +1,57 @@
1
+ module WorthSaving
2
+ class FormBuilder < ActionView::Base.default_form_builder
3
+ def text_field(method, options = {})
4
+ process_options! method, options
5
+ super
6
+ end
7
+
8
+ def radio_button(method, tag_value, options = {})
9
+ process_options! method, options
10
+ super
11
+ end
12
+
13
+ def check_box(method, options = {}, checked_value = "1", unchecked_value = "0")
14
+ process_options! method, options
15
+ super
16
+ end
17
+
18
+ def text_area(method, options = {})
19
+ process_options! method, options
20
+ super
21
+ end
22
+
23
+ def select(method, choices, options = {}, html_options = {})
24
+ process_options! method, html_options
25
+ super
26
+ end
27
+
28
+ def hidden_field(method, options = {})
29
+ process_options! method, options
30
+ super
31
+ end
32
+
33
+ def fields_for(record_name, options = {}, &bloc)
34
+ options[:builder] = options[:builder].superclass unless object.worth_saving? record_name
35
+ super
36
+ end
37
+
38
+ def submit(value = nil, options = {})
39
+ value = 'Choose this copy' if self.options[:worth_saving_recovery]
40
+ super
41
+ end
42
+
43
+ def self.next_form_id
44
+ @@worth_saving_form_id ||= 0
45
+ @@worth_saving_form_id += 1
46
+ end
47
+
48
+ private
49
+
50
+ def process_options!(method, options)
51
+ if object.worth_saving? method
52
+ options[:data] ||= options.delete('data') || {}
53
+ options[:data].reverse_merge! worth_saving: true
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,102 @@
1
+ module WorthSaving
2
+ class Info
3
+ attr_reader :scope
4
+
5
+ def initialize(klass, opts)
6
+ register_class klass
7
+ set_up_options opts
8
+ end
9
+
10
+ def self.class_with_name(name)
11
+ classes.find{ |klass| klass.name == name.camelcase }
12
+ end
13
+
14
+ def self.attribute_whitelisting_required?
15
+ puts "Rails version: #{Rails.version}"
16
+ puts "Defined?(ProtectedAttributes): #{defined?(ProtectedAttributes) == 'constant'}"
17
+ result = Rails.version.match(/^3/).present? || defined?(ProtectedAttributes) == 'constant'
18
+ puts "Returning: #{result}"
19
+ result
20
+ end
21
+
22
+ def saves_field?(field)
23
+ !@excluded_fields.include? field
24
+ end
25
+
26
+ private
27
+
28
+ def self.classes
29
+ @@classes ||= []
30
+ end
31
+
32
+ def register_class(klass)
33
+ @klass = klass
34
+ self.class.classes << klass
35
+ end
36
+
37
+ def set_up_options(opts)
38
+ opts.reverse_merge! except: nil, scope: nil
39
+ @excluded_fields = [opts[:except]].flatten.compact
40
+ @excluded_fields.concat Rails.application.config.filter_parameters
41
+ set_up_scoped_draft opts[:scope]
42
+ end
43
+
44
+ def set_up_scoped_draft(scope)
45
+ unless @scope = scope
46
+ @klass.class_eval do
47
+ def worth_saving_draft
48
+ return super if persisted?
49
+ @worth_saving_draft ||= WorthSaving::Draft.where(recordable_id: nil, recordable_type: self.class.name).first
50
+ end
51
+ end
52
+ return
53
+ end
54
+ @scope_class = scope.to_s.camelcase.constantize
55
+
56
+ @klass.class_eval do
57
+ def build_worth_saving_draft(opts = {})
58
+ return super if persisted?
59
+ self.class.worth_saving_info.build_worth_saving_draft_by_scopeable self, opts
60
+ end
61
+
62
+ def worth_saving_draft
63
+ return super if persisted?
64
+ self.class.worth_saving_info.draft_by_scopeable self
65
+ end
66
+ end
67
+
68
+ class_eval do
69
+ def build_worth_saving_draft_by_scopeable(recordable, opts)
70
+ opts.merge! recordable_type: @klass.name, scopeable: scopeable(recordable)
71
+ WorthSaving::Draft.new opts
72
+ end
73
+
74
+ def draft_by_scopeable(recordable)
75
+ WorthSaving::Draft.where(
76
+ scopeable_id: scopeable_id(recordable),
77
+ scopeable_type: scope_class,
78
+ recordable_type: recordable.class.name
79
+ ).first
80
+ end
81
+
82
+ private
83
+
84
+ def scope_class
85
+ @scope_class
86
+ end
87
+
88
+ def scopeable_id(recordable)
89
+ recordable.send scopeable_foreign_key
90
+ end
91
+
92
+ def scopeable(recordable)
93
+ scope_class.find_by_id scopeable_id recordable
94
+ end
95
+
96
+ def scopeable_foreign_key
97
+ @scopeable_foreign_key ||= "#{@scope}_id"
98
+ end
99
+ end
100
+ end
101
+ end
102
+ end
@@ -0,0 +1,3 @@
1
+ module WorthSaving
2
+ VERSION = "0.0.9"
3
+ end
@@ -0,0 +1,13 @@
1
+ require 'spec_helper'
2
+
3
+ describe WorthSaving::DraftsController do
4
+ describe '#update' do
5
+ pending '' do
6
+ # raise Dummy::Application.inspect
7
+ end
8
+ end
9
+
10
+ describe '#create' do
11
+ pending
12
+ end
13
+ end
@@ -0,0 +1,156 @@
1
+ require 'spec_helper'
2
+
3
+ describe WorthSaving::Draft do
4
+ with_model :Record do
5
+ table do |t|
6
+ t.string :name
7
+ t.integer :age
8
+ end
9
+
10
+ model do
11
+ if Rails.version.match /^3/
12
+ attr_accessible :name, :age
13
+ end
14
+ end
15
+ end
16
+
17
+ before do
18
+ class WorthSaving::Info; end
19
+ end
20
+
21
+ subject { WorthSaving::Draft.table_name }
22
+
23
+ it { should eq 'worth_saving_drafts' }
24
+
25
+ describe 'associations' do
26
+ describe ':recordable' do
27
+ subject { WorthSaving::Draft.reflect_on_association :recordable }
28
+
29
+ its(:macro) { should eq :belongs_to }
30
+ its(:options) { should include :polymorphic }
31
+ end
32
+
33
+ describe ':scopeable' do
34
+ subject { WorthSaving::Draft.reflect_on_association :scopeable }
35
+
36
+ its(:macro) { should eq :belongs_to }
37
+ its(:options) { should include :polymorphic }
38
+ end
39
+ end
40
+
41
+ describe 'validations' do
42
+ let(:record_class_worth_saving_info) { double Object }
43
+
44
+ context 'unscoped recordable class' do
45
+ context 'missing recordable_type' do
46
+ let(:draft) { stub_model WorthSaving::Draft }
47
+
48
+ it 'expects recordable_type' do
49
+ draft.should_not be_valid
50
+ draft.errors[:recordable_type].should eq ["can't be blank"]
51
+ end
52
+ end
53
+
54
+ context 'valid draft' do
55
+ before do
56
+ WorthSaving::Info.should_receive(:class_with_name).with('Record').and_return Record
57
+ record_class_worth_saving_info.should_receive(:scope).and_return nil
58
+ Record.should_receive(:worth_saving_info).and_return record_class_worth_saving_info
59
+ end
60
+
61
+ subject { stub_model WorthSaving::Draft, recordable_type: 'Record' }
62
+ it { should be_valid }
63
+ end
64
+ end
65
+
66
+ context 'scoped recordable class' do
67
+ subject { draft }
68
+ let(:draft) { stub_model WorthSaving::Draft, recordable_type: 'Record' }
69
+
70
+ before do
71
+ WorthSaving::Info.should_receive(:class_with_name).with('Record').and_return Record
72
+ record_class_worth_saving_info.stub(:scope).and_return :user
73
+ Record.stub(:worth_saving_info).and_return record_class_worth_saving_info
74
+ end
75
+
76
+ context 'valid draft' do
77
+ before do
78
+ draft.stub(:scopeable).and_return double(Object)
79
+ end
80
+
81
+ it { should be_valid }
82
+ end
83
+
84
+ context 'missing scopeable' do
85
+ before do
86
+ draft.stub(:scopeable).and_return nil
87
+ draft.valid?
88
+ end
89
+
90
+ it { should_not be_valid }
91
+ its('errors.full_messages') { should eq ["Cannot save draft for new record without scopeable record.\nBe sure to build draft from Record with a non-nil user.\n"] }
92
+ end
93
+ end
94
+ end # validation
95
+
96
+ describe 'attr_accessible' do
97
+ subject { WorthSaving::Draft.attr_accessible[:default].to_a.reject(&:empty?) }
98
+
99
+ context 'whitelisting attributes is not required' do
100
+ before do
101
+ WorthSaving.send :remove_const, :Draft
102
+ WorthSaving::Info.should_receive(:attribute_whitelisting_required?).and_return false
103
+ load WorthSaving::Engine.root + 'app/models/worth_saving/draft.rb'
104
+ end
105
+
106
+ it { should be_empty }
107
+ end
108
+
109
+ context 'whitelisting attributes is required' do
110
+ before do
111
+ WorthSaving.send :remove_const, :Draft
112
+ WorthSaving::Info.should_receive(:attribute_whitelisting_required?).and_return true
113
+ load WorthSaving::Engine.root + 'app/models/worth_saving/draft.rb'
114
+ end
115
+
116
+ it { should include 'scopeable' }
117
+ it { should include 'recordable_id' }
118
+ it { should include 'recordable_type' }
119
+ it { should include 'scopeable_id' }
120
+ it { should include 'scopeable_type' }
121
+ it { should include 'form_data' }
122
+ end
123
+ end
124
+
125
+ describe '#reconstituted_record' do
126
+ subject { draft.reconstituted_record }
127
+
128
+ context 'recordable_type is missing' do
129
+ let(:draft) { stub_model WorthSaving::Draft, recordable_type: 'Record' }
130
+
131
+ before do
132
+ WorthSaving::Info.should_receive(:class_with_name).with('Record').and_return nil
133
+ end
134
+
135
+ it { should be_nil }
136
+ end
137
+
138
+ context 'recordable_type is present and name of a class' do
139
+ let(:draft) { stub_model WorthSaving::Draft, recordable_id: record.id, recordable_type: 'Record', form_data: form_data }
140
+ let(:record) { Record.create name: 'John Smith', age: nil }
141
+ let(:form_data) { 'record%5Bname%5D=John%20N%20Smith&record%5Bage%5D=42' }
142
+
143
+ before do
144
+ WorthSaving::Info.should_receive(:class_with_name).with('Record').and_return Record
145
+ end
146
+
147
+ its(:id) { should eq record.id }
148
+ its(:name) { should eq 'John N Smith' }
149
+ its(:age) { should eq 42 }
150
+ end
151
+ end
152
+
153
+ after :all do
154
+ load WorthSaving::Engine.root + 'app/models/worth_saving/draft.rb'
155
+ end
156
+ end