has_moderated 0.0.21 → 0.0.24
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/README.rdoc +48 -9
- data/lib/has_moderated.rb +13 -234
- data/lib/has_moderated/carrier_wave.rb +2 -2
- data/lib/has_moderated/common.rb +129 -0
- data/lib/has_moderated/moderated_associations.rb +59 -0
- data/lib/has_moderated/moderated_attributes.rb +74 -0
- data/lib/has_moderated/moderated_create.rb +48 -0
- data/lib/has_moderated/moderated_destroy.rb +36 -0
- data/lib/has_moderated/moderation_model.rb +64 -23
- data/lib/has_moderated/user_hooks.rb +10 -0
- data/lib/has_moderated/version.rb +1 -1
- data/test/dummy/app/models/hjoin_test.rb +3 -0
- data/test/dummy/app/models/hmanythrough_join.rb +4 -0
- data/test/dummy/app/models/hmanythrough_test.rb +4 -0
- data/test/dummy/app/models/hone_test.rb +3 -0
- data/test/dummy/app/models/photo.rb +1 -1
- data/test/dummy/app/models/subtask.rb +1 -0
- data/test/dummy/app/models/task.rb +7 -2
- data/test/dummy/db/development.sqlite3 +0 -0
- data/test/dummy/db/migrate/20111008195728_create_hone_tests.rb +9 -0
- data/test/dummy/db/migrate/20111008195809_create_hjoin_tests.rb +13 -0
- data/test/dummy/db/migrate/20111009193145_fix_join_table.rb +8 -0
- data/test/dummy/db/migrate/20111009201729_add_title_to_hone_tests.rb +5 -0
- data/test/dummy/db/migrate/20111009205517_create_hmanythrough_tests.rb +9 -0
- data/test/dummy/db/migrate/20111009205545_create_hmanythrough_joins.rb +11 -0
- data/test/dummy/db/schema.rb +33 -1
- data/test/dummy/db/test.sqlite3 +0 -0
- data/test/dummy/log/development.log +4508 -0
- data/test/dummy/log/test.log +78674 -0
- data/test/dummy/public/test.jpg +0 -0
- data/test/dummy/public/uploads/task_photo/photo/1/test.jpg +0 -0
- data/test/dummy/spec/factories/hjoin_tests.rb +7 -0
- data/test/dummy/spec/factories/hmanythrough_joins.rb +9 -0
- data/test/dummy/spec/factories/hmanythrough_tests.rb +7 -0
- data/test/dummy/spec/factories/hone_tests.rb +7 -0
- data/test/dummy/spec/models/hjoin_test_spec.rb +36 -0
- data/test/dummy/spec/models/hmanythrough_test_spec.rb +99 -0
- data/test/dummy/spec/models/hone_test_spec.rb +36 -0
- data/test/dummy/spec/models/photo_holder_spec.rb +9 -17
- data/test/dummy/spec/models/photo_spec.rb +16 -29
- data/test/dummy/spec/models/task_photo_spec.rb +3 -9
- data/test/dummy/spec/models/task_spec.rb +36 -2
- data/test/dummy/spec/support/photos.rb +28 -0
- metadata +50 -8
- data/test/dummy/falaf/test.rb +0 -0
- data/test/dummy/public/uploads/task_photo/photo/1/logo_arnes.gif +0 -0
@@ -0,0 +1,59 @@
|
|
1
|
+
module HasModerated
|
2
|
+
module ModeratedAssociations
|
3
|
+
module ClassMethods
|
4
|
+
def has_moderated_association *args
|
5
|
+
assocs = []
|
6
|
+
|
7
|
+
unless args.blank?
|
8
|
+
if args == [:all]
|
9
|
+
assocs = self.reflections.keys.reject do |r|
|
10
|
+
r == :moderations
|
11
|
+
end
|
12
|
+
else
|
13
|
+
assocs = args
|
14
|
+
assocs = [assocs] unless assocs.respond_to?("[]")
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
#TODO: should add to some class var and clean duplicates
|
19
|
+
|
20
|
+
after_initialize do
|
21
|
+
assocs.each do |assoc_name|
|
22
|
+
assoc = self.association(assoc_name)
|
23
|
+
if assoc.reflection.collection?
|
24
|
+
def assoc.add_to_target_with_moderation record
|
25
|
+
if !owner.new_record? && !owner.has_moderated_updating
|
26
|
+
#TODO: add moderation
|
27
|
+
owner.add_associations_moderated(self.reflection.name => [record])
|
28
|
+
record
|
29
|
+
else
|
30
|
+
add_to_target_without_moderation record
|
31
|
+
end
|
32
|
+
end
|
33
|
+
assoc.class_eval do
|
34
|
+
alias_method_chain :add_to_target, :moderation
|
35
|
+
end
|
36
|
+
else
|
37
|
+
def assoc.replace_with_moderation(record, save = true)
|
38
|
+
if !owner.new_record? && !owner.has_moderated_updating
|
39
|
+
#TODO: add moderation
|
40
|
+
owner.add_associations_moderated(self.reflection.name => [record])
|
41
|
+
record
|
42
|
+
else
|
43
|
+
replace_without_moderation record
|
44
|
+
end
|
45
|
+
end
|
46
|
+
assoc.class_eval do
|
47
|
+
alias_method_chain :replace, :moderation
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
module InstanceMethods
|
56
|
+
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
module HasModerated
|
2
|
+
module ModeratedAttributes
|
3
|
+
module ClassMethods
|
4
|
+
def has_moderated *args, &block
|
5
|
+
# Lazily include the instance methods so we don't clutter up
|
6
|
+
# any more ActiveRecord models than we have to.
|
7
|
+
send :include, InstanceMethods
|
8
|
+
|
9
|
+
has_many :moderations, :as => :moderatable, :dependent => :destroy
|
10
|
+
|
11
|
+
cattr_accessor :moderated_attributes
|
12
|
+
cattr_accessor :moderated_options
|
13
|
+
|
14
|
+
self.moderated_attributes ||= []
|
15
|
+
self.moderated_options ||= {}
|
16
|
+
|
17
|
+
args.each do |arg|
|
18
|
+
if arg.respond_to?("[]")
|
19
|
+
self.moderated_options = self.moderated_options.merge(arg)
|
20
|
+
else
|
21
|
+
self.moderated_attributes.push(arg.to_s)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
# use an attribute to temporarily disable moderation before_save filter
|
26
|
+
attr_accessor :has_moderated_updating
|
27
|
+
|
28
|
+
# send moderated attributes to moderation before saving the model
|
29
|
+
before_save do
|
30
|
+
if self.valid? && @has_moderated_updating != true &&
|
31
|
+
# don't save moderated attributes if create is moderated and it's a new record
|
32
|
+
!(self.class.respond_to?("moderated_create_options") && new_record?)
|
33
|
+
moderations = self.to_moderation
|
34
|
+
if self.id.blank?
|
35
|
+
@pending_moderations ||= []
|
36
|
+
@pending_moderations.concat(moderations)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
# when creating a new record, we must update moderations' id after it is known (after create)
|
42
|
+
after_create do
|
43
|
+
if !self.id.blank? && !@pending_moderations.blank?
|
44
|
+
@pending_moderations.each do |m|
|
45
|
+
m.update_attributes(:moderatable_id => self.id)
|
46
|
+
end
|
47
|
+
@pending_moderations.clear
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
module InstanceMethods
|
54
|
+
|
55
|
+
def to_moderation
|
56
|
+
moderations = []
|
57
|
+
self.changes.each_pair do |att_name, values|
|
58
|
+
att_name = att_name.to_s
|
59
|
+
if self.class.moderated_attributes.include?(att_name) && !(values[0].blank? && values[1].blank?)
|
60
|
+
moderations.push(create_moderation_with_hooks!({
|
61
|
+
:moderatable_type => self.class.to_s,
|
62
|
+
:moderatable_id => self.id,
|
63
|
+
:attr_name => att_name,
|
64
|
+
:attr_value => self.attributes[att_name].to_yaml
|
65
|
+
}))
|
66
|
+
self.send(att_name+"=", values[0])
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
moderations
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module HasModerated
|
2
|
+
module ModeratedCreate
|
3
|
+
module ClassMethods
|
4
|
+
def has_moderated_create *options
|
5
|
+
# Lazily include the instance methods so we don't clutter up
|
6
|
+
# any more ActiveRecord models than we have to.
|
7
|
+
send :include, InstanceMethods
|
8
|
+
|
9
|
+
# use an attribute to temporarily disable moderation before_save filter
|
10
|
+
attr_accessor :has_moderated_updating
|
11
|
+
|
12
|
+
# save options for use later
|
13
|
+
cattr_accessor :moderated_create_options
|
14
|
+
self.moderated_create_options = (options.count > 0) ? options[0] : {}
|
15
|
+
|
16
|
+
alias_method_chain :create_or_update, :moderation
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
module InstanceMethods
|
21
|
+
def create_or_update_with_moderation *args
|
22
|
+
if valid? && new_record? && @has_moderated_updating != true
|
23
|
+
to_moderation_created
|
24
|
+
true
|
25
|
+
else
|
26
|
+
create_or_update_without_moderation *args
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def to_moderation_created
|
31
|
+
options = self.class.moderated_create_options
|
32
|
+
assoc_attrs = HasModerated::Common::get_assocs_for_moderation(options[:with_associations], self)
|
33
|
+
|
34
|
+
attr_value = {
|
35
|
+
:main_model => get_moderation_attributes(self),
|
36
|
+
:associations => assoc_attrs
|
37
|
+
}
|
38
|
+
|
39
|
+
create_moderation_with_hooks!({
|
40
|
+
:moderatable_type => self.class.to_s,
|
41
|
+
:moderatable_id => self.id,
|
42
|
+
:attr_name => "-",
|
43
|
+
:attr_value => attr_value.to_yaml
|
44
|
+
})
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module HasModerated
|
2
|
+
module ModeratedDestroy
|
3
|
+
module ClassMethods
|
4
|
+
def has_moderated_destroy *options
|
5
|
+
# Lazily include the instance methods so we don't clutter up
|
6
|
+
# any more ActiveRecord models than we have to.
|
7
|
+
send :include, InstanceMethods
|
8
|
+
|
9
|
+
# use an attribute to temporarily disable moderation before_save filter
|
10
|
+
attr_accessor :has_moderated_updating
|
11
|
+
|
12
|
+
alias_method_chain :destroy, :moderation
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
module InstanceMethods
|
17
|
+
def destroy_with_moderation *args
|
18
|
+
if @has_moderated_updating == true
|
19
|
+
destroy_without_moderation *args
|
20
|
+
else
|
21
|
+
to_moderation_destroyed
|
22
|
+
true
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def to_moderation_destroyed
|
27
|
+
create_moderation_with_hooks!({
|
28
|
+
:moderatable_type => self.class.to_s,
|
29
|
+
:moderatable_id => self.id,
|
30
|
+
:attr_name => "-",
|
31
|
+
:attr_value => "destroy"
|
32
|
+
})
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -24,40 +24,81 @@ module HasModerated
|
|
24
24
|
end
|
25
25
|
end
|
26
26
|
|
27
|
-
def
|
27
|
+
def add_assoc_to_record arec, rec, assoc_name
|
28
|
+
return unless rec && arec
|
29
|
+
|
30
|
+
assoc = rec.class.reflections[assoc_name.to_sym]
|
31
|
+
|
32
|
+
if assoc.macro == :has_and_belongs_to_many || !assoc.options[:through].blank?
|
33
|
+
arec.send(rec.class.to_s.underscore.pluralize) << rec
|
34
|
+
elsif assoc.macro == :has_many || assoc.macro == :has_one
|
35
|
+
arec.send(rec.class.to_s.underscore + "=", rec)
|
36
|
+
#fk = if assoc.respond_to?(:foreign_key)
|
37
|
+
# assoc.foreign_key
|
38
|
+
#else # Rails < v3.1
|
39
|
+
# assoc.primary_key_name
|
40
|
+
#end
|
41
|
+
#arec.send(fk.to_s+"=", rec.id)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def try_moderatable_updating rec
|
46
|
+
rec.has_moderated_updating = true if rec.respond_to?("has_moderated_updating=")
|
47
|
+
yield(rec)
|
48
|
+
rec.has_moderated_updating = false if rec.respond_to?("has_moderated_updating=")
|
49
|
+
end
|
50
|
+
|
51
|
+
def update_associations_from_value rec, interpreted_assocs = nil
|
52
|
+
interpreted_assocs ||= interpreted_value[:associations]
|
28
53
|
# in case it's empty
|
29
|
-
|
54
|
+
interpreted_assocs ||= {}
|
30
55
|
# loop association types, e.g. :comments
|
31
|
-
|
56
|
+
interpreted_assocs.each_pair do |assoc_name, assoc_records|
|
32
57
|
# read reflections attribute to determine proper class name and primary key
|
33
58
|
assoc_details = rec.class.reflections[assoc_name.to_sym]
|
34
59
|
m = assoc_details.class_name.constantize
|
60
|
+
|
61
|
+
fk = if assoc_details.respond_to?(:foreign_key)
|
62
|
+
assoc_details.foreign_key
|
63
|
+
else # Rails < v3.1
|
64
|
+
assoc_details.primary_key_name
|
65
|
+
end
|
35
66
|
|
36
67
|
# all instances for this association type
|
37
68
|
assoc_records.each do |attrs|
|
38
69
|
next if attrs.blank?
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
70
|
+
if attrs.class != Fixnum && !attrs[:id].blank?
|
71
|
+
attrs = attrs[:id].to_i
|
72
|
+
end
|
73
|
+
try_moderatable_updating(rec) do
|
74
|
+
arec = nil
|
75
|
+
# PARAM = ID
|
76
|
+
if attrs.class == Fixnum
|
77
|
+
arec = m.find_by_id(attrs)
|
78
|
+
add_assoc_to_record(arec, rec, assoc_name)
|
79
|
+
# PARAM = Hash (create)
|
80
|
+
else
|
81
|
+
arec = m.new
|
82
|
+
# set foreign key first, may be required sometimes
|
83
|
+
add_assoc_to_record(arec, rec, assoc_name)
|
84
|
+
attrs && attrs.each_pair do |key, val|
|
85
|
+
next if key.to_s == "associations" || key.to_s == 'id' || key.to_s == fk
|
86
|
+
arec.send(key.to_s+"=", val)
|
87
|
+
end
|
88
|
+
if attrs[:associations]
|
89
|
+
update_associations_from_value arec, attrs[:associations]
|
90
|
+
end
|
52
91
|
end
|
53
|
-
arec
|
54
|
-
|
55
|
-
|
92
|
+
if arec
|
93
|
+
try_moderatable_updating(arec) do
|
94
|
+
arec.save(:validate => false) # don't run validations
|
95
|
+
end
|
96
|
+
if assoc_details.collection?
|
97
|
+
rec.send(assoc_name.to_s) << arec if arec
|
98
|
+
else
|
99
|
+
rec.send(assoc_name.to_s + "=", arec) if arec
|
100
|
+
end
|
56
101
|
end
|
57
|
-
# disable moderation for associated model (if moderated)
|
58
|
-
arec.has_moderated_updating = true if arec.respond_to?("has_moderated_updating=")
|
59
|
-
arec.save(:validate => false) # don't run validations
|
60
|
-
arec.has_moderated_updating = false if arec.respond_to?("has_moderated_updating=")
|
61
102
|
end
|
62
103
|
end
|
63
104
|
end
|
@@ -2,7 +2,12 @@ class Task < ActiveRecord::Base
|
|
2
2
|
attr_accessible :title
|
3
3
|
has_many :subtasks
|
4
4
|
has_many :task_photos
|
5
|
-
|
6
|
-
|
5
|
+
has_and_belongs_to_many :hjoin_tests
|
6
|
+
has_one :hone_test
|
7
|
+
has_many :hmanythrough_join
|
8
|
+
has_many :hmanythrough_test, :through => :hmanythrough_join
|
9
|
+
has_moderated :title, :desc
|
10
|
+
has_moderated_create :with_associations => [:subtasks, :task_photos, :hjoin_tests, :hone_test, :hmanythrough_test, :hmanythrough_join]
|
11
|
+
has_moderated_association :all
|
7
12
|
has_moderated_destroy
|
8
13
|
end
|
Binary file
|