8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
|
# File 'lib/conscript/orm/activerecord.rb', line 8
def register_for_draft(options = {})
cattr_accessor :conscript_options, :instance_accessor => false do
{
associations: [],
ignore_attributes: [self.primary_key, 'type', 'created_at', 'updated_at', 'draft_parent_id', 'is_draft'],
allow_update_with_drafts: false,
destroy_drafts_on_publish: true
}
end
self.conscript_options.slice(:associations, :ignore_attributes).each_pair {|key, value| self.conscript_options[key] = Array(value) | Array(options[key]) }
self.conscript_options[:associations].map!(&:to_sym)
self.conscript_options[:ignore_attributes].map!(&:to_s)
self.conscript_options.update options.slice(:allow_update_with_drafts, :destroy_drafts_on_publish)
belongs_to :draft_parent, class_name: self, inverse_of: :drafts
has_many :drafts, conditions: {is_draft: true}, class_name: self, foreign_key: :draft_parent_id, dependent: :destroy, inverse_of: :draft_parent
define_callbacks :publish_draft, :save_as_draft
before_save :check_no_drafts_exist if (self.conscript_options[:allow_update_with_drafts] == false)
set_callback :publish_draft, :after, :destroy_all_drafts if (self.conscript_options[:destroy_drafts_on_publish] == true)
if self.respond_to? :uploaders
self.uploaders.keys.each {|attribute| skip_callback :commit, :after, :"remove_#{attribute}!" }
after_commit :clean_uploaded_files_for_draft!, :on => :destroy
end
class_eval <<-RUBY
def self.published
where(is_draft: false)
end
def self.drafts
where(is_draft: true)
end
def save_as_draft!
run_callbacks :save_as_draft do
raise Conscript::Exception::AlreadyDraft if is_draft?
draft = new_record? ? self : dup(include: self.class.conscript_options[:associations]) do |original, dup|
# Workaround for CarrierWave uploaders on associated records. Copy the uploaded files.
if dup.class.respond_to? :uploaders
dup.class.uploaders.keys.each {|uploader| dup.send(uploader.to_s + "=", original.send(uploader)) }
end
end
draft.is_draft = true
draft.draft_parent = self unless new_record?
draft.save!
draft
end
end
def publish_draft
run_callbacks :publish_draft do
raise Conscript::Exception::NotADraft unless is_draft?
if !draft_parent_id
self.update_attribute(:is_draft, false)
return self
end
parent = self.draft_parent
::ActiveRecord::Base.transaction do
parent.assign_attributes attributes_to_publish, without_protection: true
self.class.conscript_options[:associations].each do |association|
case reflections[association].macro
when :has_many
parent.send(association.to_s + "=", self.send(association).collect do |child|
child.dup do |original, dup|
# Workaround for CarrierWave uploaders on associated records. Copy the uploaded files.
if dup.class.respond_to? :uploaders
dup.class.uploaders.keys.each {|uploader| dup.send(uploader.to_s + "=", original.send(uploader)) }
end
end
end)
end
end
self.reload
self.destroy
parent.save!
end
parent
end
end
def uploader_store_param
draft_parent_id.nil? ? to_param : draft_parent.to_param
end
private
def check_no_drafts_exist
errors[:base] << "Cannot save record while drafts exist"
drafts.count == 0
end
def attributes_to_publish
attributes.reject {|attribute| self.class.conscript_options[:ignore_attributes].include?(attribute) }
end
# Clean up CarrierWave uploads if there are no other instances using the files.
#
def clean_uploaded_files_for_draft!
self.class.uploaders.keys.each do |attribute|
filename = attributes[attribute.to_s]
cols = self.class.arel_table
self.send("remove_" + attribute.to_s + "!") if !draft_parent_id or self.class.where(cols[:id].eq(draft_parent_id).or(cols[:draft_parent_id].eq(draft_parent_id))).where(attribute => filename).count == 0
end
end
def destroy_all_drafts
draft_parent.drafts.destroy_all if draft_parent_id
end
RUBY
end
|