has_moderated 0.0.21 → 0.0.24

Sign up to get free protection for your applications and to get access to all the features.
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