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.
- checksums.yaml +15 -0
- data/MIT-LICENSE +20 -0
- data/README.md +90 -0
- data/Rakefile +29 -0
- data/app/assets/javascripts/worth_saving/application.js +15 -0
- data/app/assets/stylesheets/worth_saving/application.css +13 -0
- data/app/controllers/worth_saving/application_controller.rb +4 -0
- data/app/controllers/worth_saving/drafts_controller.rb +51 -0
- data/app/helpers/worth_saving/application_helper.rb +4 -0
- data/app/models/worth_saving/draft.rb +47 -0
- data/app/views/layouts/worth_saving/application.html.erb +14 -0
- data/config/routes.rb +3 -0
- data/db/migrate/20130911055236_create_worth_saving_drafts.rb +16 -0
- data/lib/tasks/worth_saving_tasks.rake +4 -0
- data/lib/worth_saving.rb +12 -0
- data/lib/worth_saving/action_view_ext.rb +11 -0
- data/lib/worth_saving/active_record_ext.rb +39 -0
- data/lib/worth_saving/engine.rb +15 -0
- data/lib/worth_saving/form.rb +15 -0
- data/lib/worth_saving/form/base.rb +21 -0
- data/lib/worth_saving/form/record.rb +53 -0
- data/lib/worth_saving/form/rendering.rb +100 -0
- data/lib/worth_saving/form_builder.rb +57 -0
- data/lib/worth_saving/info.rb +102 -0
- data/lib/worth_saving/version.rb +3 -0
- data/spec/app/controllers/drafts_controller_spec.rb +13 -0
- data/spec/app/models/worth_saving/draft_spec.rb +156 -0
- data/spec/dummy/README.rdoc +261 -0
- data/spec/dummy/Rakefile +7 -0
- data/spec/dummy/app/assets/javascripts/application.js +15 -0
- data/spec/dummy/app/assets/stylesheets/application.css +15 -0
- data/spec/dummy/app/controllers/application_controller.rb +24 -0
- data/spec/dummy/app/controllers/login_controller.rb +11 -0
- data/spec/dummy/app/controllers/pages_controller.rb +48 -0
- data/spec/dummy/app/helpers/application_helper.rb +2 -0
- data/spec/dummy/app/models/page.rb +12 -0
- data/spec/dummy/app/models/subpage.rb +7 -0
- data/spec/dummy/app/models/user.rb +4 -0
- data/spec/dummy/app/views/layouts/application.html.erb +15 -0
- data/spec/dummy/app/views/pages/form.html.slim +53 -0
- data/spec/dummy/config.ru +4 -0
- data/spec/dummy/config/application.rb +66 -0
- data/spec/dummy/config/boot.rb +10 -0
- data/spec/dummy/config/database.yml +25 -0
- data/spec/dummy/config/environment.rb +5 -0
- data/spec/dummy/config/environments/development.rb +37 -0
- data/spec/dummy/config/environments/production.rb +67 -0
- data/spec/dummy/config/environments/test.rb +37 -0
- data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/dummy/config/initializers/inflections.rb +15 -0
- data/spec/dummy/config/initializers/mime_types.rb +5 -0
- data/spec/dummy/config/initializers/secret_token.rb +7 -0
- data/spec/dummy/config/initializers/session_store.rb +8 -0
- data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/spec/dummy/config/locales/en.yml +5 -0
- data/spec/dummy/config/routes.rb +8 -0
- data/spec/dummy/db/development.sqlite3 +0 -0
- data/spec/dummy/db/migrate/20130911060226_create_worth_saving_drafts.worth_saving.rb +17 -0
- data/spec/dummy/db/migrate/20130912071319_create_users.rb +9 -0
- data/spec/dummy/db/migrate/20130912071446_create_pages.rb +9 -0
- data/spec/dummy/db/migrate/20130912145831_create_subpages.rb +10 -0
- data/spec/dummy/db/migrate/20130913060709_add_columns_to_subpages.rb +5 -0
- data/spec/dummy/db/migrate/20130913060847_add_columns_to_pages.rb +7 -0
- data/spec/dummy/db/schema.rb +52 -0
- data/spec/dummy/db/test.sqlite3 +0 -0
- data/spec/dummy/log/development.log +17536 -0
- data/spec/dummy/log/test.log +76256 -0
- data/spec/dummy/public/404.html +26 -0
- data/spec/dummy/public/422.html +26 -0
- data/spec/dummy/public/500.html +25 -0
- data/spec/dummy/public/favicon.ico +0 -0
- data/spec/dummy/script/rails +6 -0
- data/spec/dummy/tmp/cache/assets/CA6/7A0/sprockets%2Ff6723fb0918cb134f62480f155a0b364 +0 -0
- data/spec/dummy/tmp/cache/assets/CD8/370/sprockets%2F357970feca3ac29060c1e3861e2c0953 +0 -0
- data/spec/dummy/tmp/cache/assets/CF8/AF0/sprockets%2F228f63c526665cc53d670799eece3b98 +0 -0
- data/spec/dummy/tmp/cache/assets/D09/190/sprockets%2F993fae97313ed7d42322c85e60b02bb1 +0 -0
- data/spec/dummy/tmp/cache/assets/D1C/CE0/sprockets%2F9a5f4484900982bd33f792ca06e7f5ea +0 -0
- data/spec/dummy/tmp/cache/assets/D31/620/sprockets%2F01f101ae68348ed1bb4e46d7f452a73a +0 -0
- data/spec/dummy/tmp/cache/assets/D32/A10/sprockets%2F13fe41fee1fe35b49d145bcc06610705 +0 -0
- data/spec/dummy/tmp/cache/assets/D3C/300/sprockets%2Ffb893496ed88af814fa985858f60ee66 +0 -0
- data/spec/dummy/tmp/cache/assets/D43/EB0/sprockets%2F43d74a38cb4f14de5087ea7f871ac166 +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/D97/C50/sprockets%2F74b5c193fc06fb3cb3c4ac12ac7589a7 +0 -0
- data/spec/dummy/tmp/cache/assets/D9E/470/sprockets%2F36bde6f05aa955c51ab2cd97b59e742a +0 -0
- data/spec/dummy/tmp/cache/assets/DCF/000/sprockets%2Fcfbeb9f4e8b3b7d1ac752d93c64017d3 +0 -0
- data/spec/dummy/tmp/cache/assets/DDC/400/sprockets%2Fcffd775d018f68ce5dba1ee0d951a994 +0 -0
- data/spec/dummy/tmp/cache/assets/E04/890/sprockets%2F2f5173deea6c795b8fdde723bb4b63af +0 -0
- data/spec/dummy/tmp/cache/assets/test/sprockets/01f101ae68348ed1bb4e46d7f452a73a +0 -0
- data/spec/dummy/tmp/cache/assets/test/sprockets/13fe41fee1fe35b49d145bcc06610705 +0 -0
- data/spec/dummy/tmp/cache/assets/test/sprockets/228f63c526665cc53d670799eece3b98 +0 -0
- data/spec/dummy/tmp/cache/assets/test/sprockets/2f5173deea6c795b8fdde723bb4b63af +0 -0
- data/spec/dummy/tmp/cache/assets/test/sprockets/357970feca3ac29060c1e3861e2c0953 +0 -0
- data/spec/dummy/tmp/cache/assets/test/sprockets/36bde6f05aa955c51ab2cd97b59e742a +0 -0
- data/spec/dummy/tmp/cache/assets/test/sprockets/43d74a38cb4f14de5087ea7f871ac166 +0 -0
- data/spec/dummy/tmp/cache/assets/test/sprockets/74b5c193fc06fb3cb3c4ac12ac7589a7 +0 -0
- data/spec/dummy/tmp/cache/assets/test/sprockets/993fae97313ed7d42322c85e60b02bb1 +0 -0
- data/spec/dummy/tmp/cache/assets/test/sprockets/9a5f4484900982bd33f792ca06e7f5ea +0 -0
- data/spec/dummy/tmp/cache/assets/test/sprockets/cfbeb9f4e8b3b7d1ac752d93c64017d3 +0 -0
- data/spec/dummy/tmp/cache/assets/test/sprockets/cffd775d018f68ce5dba1ee0d951a994 +0 -0
- data/spec/dummy/tmp/cache/assets/test/sprockets/d771ace226fc8215a3572e0aa35bb0d6 +0 -0
- data/spec/dummy/tmp/cache/assets/test/sprockets/f6723fb0918cb134f62480f155a0b364 +0 -0
- data/spec/dummy/tmp/cache/assets/test/sprockets/f7cbd26ba1d28d48de824f0e94586655 +0 -0
- data/spec/dummy/tmp/cache/assets/test/sprockets/fb893496ed88af814fa985858f60ee66 +0 -0
- data/spec/factories.rb +28 -0
- data/spec/features/worth_saving_features_spec.rb +60 -0
- data/spec/lib/active_record_ext_spec.rb +291 -0
- data/spec/lib/info_spec.rb +29 -0
- data/spec/spec_helper.rb +37 -0
- data/spec/support/features.rb +8 -0
- data/spec/support/features/helpers.rb +96 -0
- data/vendor/assets/javascripts/worth_saving.js +10 -0
- data/vendor/assets/javascripts/worth_saving/form.js +64 -0
- data/vendor/assets/stylesheets/worth_saving.css +18 -0
- 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,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
|