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.
Files changed (46) hide show
  1. data/README.rdoc +48 -9
  2. data/lib/has_moderated.rb +13 -234
  3. data/lib/has_moderated/carrier_wave.rb +2 -2
  4. data/lib/has_moderated/common.rb +129 -0
  5. data/lib/has_moderated/moderated_associations.rb +59 -0
  6. data/lib/has_moderated/moderated_attributes.rb +74 -0
  7. data/lib/has_moderated/moderated_create.rb +48 -0
  8. data/lib/has_moderated/moderated_destroy.rb +36 -0
  9. data/lib/has_moderated/moderation_model.rb +64 -23
  10. data/lib/has_moderated/user_hooks.rb +10 -0
  11. data/lib/has_moderated/version.rb +1 -1
  12. data/test/dummy/app/models/hjoin_test.rb +3 -0
  13. data/test/dummy/app/models/hmanythrough_join.rb +4 -0
  14. data/test/dummy/app/models/hmanythrough_test.rb +4 -0
  15. data/test/dummy/app/models/hone_test.rb +3 -0
  16. data/test/dummy/app/models/photo.rb +1 -1
  17. data/test/dummy/app/models/subtask.rb +1 -0
  18. data/test/dummy/app/models/task.rb +7 -2
  19. data/test/dummy/db/development.sqlite3 +0 -0
  20. data/test/dummy/db/migrate/20111008195728_create_hone_tests.rb +9 -0
  21. data/test/dummy/db/migrate/20111008195809_create_hjoin_tests.rb +13 -0
  22. data/test/dummy/db/migrate/20111009193145_fix_join_table.rb +8 -0
  23. data/test/dummy/db/migrate/20111009201729_add_title_to_hone_tests.rb +5 -0
  24. data/test/dummy/db/migrate/20111009205517_create_hmanythrough_tests.rb +9 -0
  25. data/test/dummy/db/migrate/20111009205545_create_hmanythrough_joins.rb +11 -0
  26. data/test/dummy/db/schema.rb +33 -1
  27. data/test/dummy/db/test.sqlite3 +0 -0
  28. data/test/dummy/log/development.log +4508 -0
  29. data/test/dummy/log/test.log +78674 -0
  30. data/test/dummy/public/test.jpg +0 -0
  31. data/test/dummy/public/uploads/task_photo/photo/1/test.jpg +0 -0
  32. data/test/dummy/spec/factories/hjoin_tests.rb +7 -0
  33. data/test/dummy/spec/factories/hmanythrough_joins.rb +9 -0
  34. data/test/dummy/spec/factories/hmanythrough_tests.rb +7 -0
  35. data/test/dummy/spec/factories/hone_tests.rb +7 -0
  36. data/test/dummy/spec/models/hjoin_test_spec.rb +36 -0
  37. data/test/dummy/spec/models/hmanythrough_test_spec.rb +99 -0
  38. data/test/dummy/spec/models/hone_test_spec.rb +36 -0
  39. data/test/dummy/spec/models/photo_holder_spec.rb +9 -17
  40. data/test/dummy/spec/models/photo_spec.rb +16 -29
  41. data/test/dummy/spec/models/task_photo_spec.rb +3 -9
  42. data/test/dummy/spec/models/task_spec.rb +36 -2
  43. data/test/dummy/spec/support/photos.rb +28 -0
  44. metadata +50 -8
  45. data/test/dummy/falaf/test.rb +0 -0
  46. 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 update_associations_from_value rec
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
- interpreted_value[:associations] ||= {}
54
+ interpreted_assocs ||= {}
30
55
  # loop association types, e.g. :comments
31
- interpreted_value[:associations].each_pair do |assoc_name, assoc_records|
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
- # PARAM = ID
40
- if attrs.class == Fixnum
41
- arec = m.find_by_id(attrs)
42
- # add the association, if the record still existss
43
- rec.send(assoc_name.to_s) << arec if arec
44
- # PARAM = Hash (create)
45
- else
46
- arec = m.new
47
- # set foreign key first, may be required sometimes
48
- fk = if assoc_details.respond_to?(:foreign_key)
49
- assoc_details.foreign_key
50
- else # Rails < v3.1
51
- assoc_details.primary_key_name
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.send(fk.to_s+"=", rec.id) # set association to the newly created record
54
- attrs && attrs.each_pair do |key, val|
55
- arec.send(key.to_s+"=", val) unless key.to_s == 'id' || key.to_s == fk.to_s
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
@@ -0,0 +1,10 @@
1
+ module HasModerated
2
+ module UserHooks
3
+ module ClassMethods
4
+ def moderation_creating &block
5
+ cattr_accessor :moderation_creating_hook
6
+ self.moderation_creating_hook = block
7
+ end
8
+ end
9
+ end
10
+ end
@@ -1,3 +1,3 @@
1
1
  module HasModerated
2
- VERSION = "0.0.21"
2
+ VERSION = "0.0.24"
3
3
  end
@@ -0,0 +1,3 @@
1
+ class HjoinTest < ActiveRecord::Base
2
+ has_and_belongs_to_many :tasks
3
+ end
@@ -0,0 +1,4 @@
1
+ class HmanythroughJoin < ActiveRecord::Base
2
+ belongs_to :task
3
+ belongs_to :hmanythrough_test
4
+ end
@@ -0,0 +1,4 @@
1
+ class HmanythroughTest < ActiveRecord::Base
2
+ has_many :hmanythrough_join
3
+ has_many :tasks, :through => :hmanythrough_join
4
+ end
@@ -0,0 +1,3 @@
1
+ class HoneTest < ActiveRecord::Base
2
+ belongs_to :task
3
+ end
@@ -2,6 +2,6 @@ class Photo < ActiveRecord::Base
2
2
  belongs_to :photo_holder
3
3
  mount_uploader :photo, GenericUploader
4
4
  has_moderated_create
5
- has_moderated :photo
5
+ has_moderated :carrierwave_photo
6
6
  include HasModerated::CarrierWave
7
7
  end
@@ -1,3 +1,4 @@
1
1
  class Subtask < ActiveRecord::Base
2
2
  belongs_to :task
3
+ belongs_to :task_all
3
4
  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
- has_moderated :title, :desc, { :with_associations => [:subtasks] }
6
- has_moderated_create :with_associations => [:subtasks, :task_photos]
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
@@ -0,0 +1,9 @@
1
+ class CreateHoneTests < ActiveRecord::Migration
2
+ def change
3
+ create_table :hone_tests do |t|
4
+ t.integer :task_id
5
+
6
+ t.timestamps
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,13 @@
1
+ class CreateHjoinTests < ActiveRecord::Migration
2
+ def change
3
+ create_table :hjoin_tests do |t|
4
+ t.string :title
5
+
6
+ t.timestamps
7
+ end
8
+ create_table :hjoin_tests_tasks do |t|
9
+ t.integer :task_id
10
+ t.integer :hjoin_test_id
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,8 @@
1
+ class FixJoinTable < ActiveRecord::Migration
2
+ def up
3
+ remove_column :hjoin_tests_tasks, :id
4
+ end
5
+
6
+ def down
7
+ end
8
+ end
@@ -0,0 +1,5 @@
1
+ class AddTitleToHoneTests < ActiveRecord::Migration
2
+ def change
3
+ add_column :hone_tests, :title, :string
4
+ end
5
+ end