has_moderated 1.0.rc8 → 1.0.rc9
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +11 -11
- data/lib/has_moderated/moderation_preview.rb +27 -61
- data/lib/has_moderated/version.rb +1 -1
- data/test/dummy/log/test.log +62300 -0
- data/test/dummy/spec/models/task_spec.rb +11 -0
- metadata +204 -209
data/README.rdoc
CHANGED
@@ -5,7 +5,7 @@
|
|
5
5
|
|
6
6
|
Add it to your project's Gemfile
|
7
7
|
|
8
|
-
gem "has_moderated", ">=1.0.
|
8
|
+
gem "has_moderated", ">=1.0.rc9"
|
9
9
|
|
10
10
|
and run
|
11
11
|
|
@@ -116,20 +116,18 @@ You can see a preview of what a moderation will do.
|
|
116
116
|
|
117
117
|
=== Get a read-only preview
|
118
118
|
|
119
|
-
|
120
|
-
This object allows you to see the value of all attributes, as well as all the associations (including non-moderated).
|
121
|
-
It also supports dirty tracking through ActiveModel, so you can use all its functionality (http://api.rubyonrails.org/classes/ActiveModel/Dirty.html).
|
119
|
+
You can get a read-only preview of the actual ActiveRecord object. It allows you to see the value of all attributes, as well as all the associations (including non-moderated, except the moderations association). Since it is an ActiveRecord object, it also supports dirty tracking (http://api.rubyonrails.org/classes/ActiveModel/Dirty.html). Note that association methods (preview.some_association) are not real ActiveRecord relations, but just Arrays. If you really need real relations, look at live_preview below.
|
122
120
|
|
123
121
|
preview = moderation.preview
|
124
122
|
preview.some_attr # => "new value"
|
125
123
|
preview.some_attr_change # => ["old value", "new value"]
|
126
|
-
preview.some_association.first # =>
|
124
|
+
preview.some_association.first # => AR object
|
127
125
|
|
128
|
-
This preview is cached from applying the moderation in a transaction and then rolling it back (so it does not affect the database).
|
126
|
+
This preview is cached from applying the moderation in a transaction and then rolling it back (so it does not affect the database). Note if you have custom model methods that return other ActiveRecord records, those records will not be frozen, so if you save those changes WILL be written to the database.
|
129
127
|
|
130
|
-
=== Using the
|
128
|
+
=== Using the preview to modify the moderation
|
131
129
|
|
132
|
-
The
|
130
|
+
The preview described above has a nifty feature (1.0.rc7+) that allows you to update attributes in the moderation by manipulating the fake object. Right now it can only handle attributes and not associations, but that might change in the future. See example below on how to use this feature.
|
133
131
|
|
134
132
|
moderation.parsed_data # => {:attributes=>{"title"=>"Task 1"}}
|
135
133
|
preview = moderation.preview(:saveable => true)
|
@@ -139,16 +137,18 @@ The fake object described above has a nifty feature (1.0.rc7+) that allows you t
|
|
139
137
|
moderation.accept
|
140
138
|
Task.first.title # => "Task 2"
|
141
139
|
|
142
|
-
=== Get a
|
140
|
+
=== Get a live ActiveRecord preview
|
143
141
|
|
144
|
-
|
142
|
+
Usually you don't need to use this. The difference compared to the above method is that the above will freeze objects from the database and then roll back the transaction, and you will get the frozen copies that you can use at will. Those copies do have fake association methods that just return Arrays instead of AR relations.
|
143
|
+
|
144
|
+
In contrast to preview, live_preview will let you use the record while the transaction is still going on, so it is not even frozen. Also the association methods are real ActiveRecord relations in this case. After your block completes, the transaction will be rolled back and you will not have access to the preview anymore (and you should not use it outside of the block).
|
145
145
|
|
146
146
|
moderation.live_preview do |preview|
|
147
147
|
preview.some_attr # => "new value"
|
148
148
|
# note how we need to use .previous_changes when using live_preview,
|
149
149
|
# .changes will be blank as the record has already been saved to DB
|
150
150
|
preview.previous_changes # => {"attr"=>["old", "new"]}
|
151
|
-
preview.some_association.first # =>
|
151
|
+
preview.some_association.first # => AR object
|
152
152
|
end
|
153
153
|
|
154
154
|
Note that since a transaction is used in both cases, all the changes made to the database to produce the preview are only in effect inside the transaction, so the changes are only visible inside the transaction. For example, if a second database query comes from another Rails instance, it will not see the changes that are in effect in the transaction, even if the transaction is still in process.
|
@@ -8,7 +8,7 @@ module HasModerated
|
|
8
8
|
|
9
9
|
# attributes
|
10
10
|
data[:attributes] ||= Hash.new
|
11
|
-
@
|
11
|
+
@has_moderated_fake_attributes.each_pair do |key, value|
|
12
12
|
if value != @attributes_initial[key]
|
13
13
|
data[:attributes][key.to_s] = value
|
14
14
|
end
|
@@ -20,64 +20,32 @@ module HasModerated
|
|
20
20
|
end
|
21
21
|
end
|
22
22
|
|
23
|
-
|
24
|
-
|
25
|
-
include ActiveModel::Conversion
|
26
|
-
include ActiveModel::Dirty
|
27
|
-
|
28
|
-
attr_accessor :attributes
|
29
|
-
|
30
|
-
def initialize(based_on_model, based_on_moderation)
|
23
|
+
module FakeRecord
|
24
|
+
def fake!(based_on_model, based_on_moderation)
|
31
25
|
@based_on_model = based_on_model
|
32
26
|
@based_on_moderation = based_on_moderation
|
33
|
-
|
34
|
-
|
35
|
-
def persisted?
|
36
|
-
false
|
37
|
-
end
|
38
|
-
|
39
|
-
def attribute name
|
40
|
-
attributes[name]
|
41
|
-
end
|
42
|
-
|
43
|
-
def id
|
44
|
-
attributes["id"]
|
45
|
-
end
|
46
|
-
|
47
|
-
def to_s
|
48
|
-
"#<HasModerated::Fake#{@based_on_model.to_s}>"
|
49
|
-
end
|
50
|
-
|
51
|
-
def inspect
|
52
|
-
to_s.chomp(">") +
|
53
|
-
instance_variables.map{|name| " #{name}=#{instance_variable_get(name)}"}.join(",") +
|
54
|
-
", reflections.keys => [" + reflections.keys.map{|s| ":#{s}"}.join(", ")+ "]>"
|
55
|
-
end
|
56
|
-
end
|
57
|
-
|
58
|
-
def self.create_fake_association(attr_name, value, target)
|
59
|
-
target.send(:define_method, attr_name) do
|
60
|
-
value
|
27
|
+
self.freeze
|
61
28
|
end
|
62
29
|
end
|
63
30
|
|
64
31
|
def self.resolve_record(record, cache)
|
65
32
|
return nil if record.blank?
|
66
|
-
|
67
|
-
if
|
68
|
-
cache[
|
33
|
+
idx = cache.index(record)
|
34
|
+
if idx && idx.present?
|
35
|
+
cache[idx] # the difference is that the one in cache is frozen for sure
|
69
36
|
else
|
70
|
-
cache
|
37
|
+
cache.push(from_live(record, nil, false, cache))
|
38
|
+
cache.last
|
71
39
|
end
|
72
40
|
end
|
73
41
|
|
74
|
-
def self.from_live(record, moderation = nil, saveable = false, object_cache =
|
42
|
+
def self.from_live(record, moderation = nil, saveable = false, object_cache = [])
|
75
43
|
return nil if record.blank?
|
76
|
-
obj =
|
77
|
-
eigenclass = (class << obj ; self ; end)
|
44
|
+
obj = record
|
45
|
+
eigenclass = (class << obj ; include FakeRecord ; self ; end)
|
46
|
+
obj.fake!(record.class, moderation)
|
78
47
|
|
79
48
|
# attributes
|
80
|
-
obj.instance_variable_set(:@attributes, record.instance_variable_get(:@attributes))
|
81
49
|
changed_attributes = Hash.new
|
82
50
|
record.previous_changes.each_pair do |attr_name, values|
|
83
51
|
changed_attributes[attr_name] = values[0]
|
@@ -86,33 +54,31 @@ module HasModerated
|
|
86
54
|
|
87
55
|
# saveable
|
88
56
|
if saveable
|
89
|
-
obj.instance_variable_set(:@attributes_initial,
|
57
|
+
obj.instance_variable_set(:@attributes_initial, obj.instance_variable_get(:@attributes).dup)
|
90
58
|
eigenclass.send(:include, Saveable)
|
59
|
+
obj.instance_variable_set(:@has_moderated_fake_attributes, Hash.new)
|
91
60
|
obj.attributes.keys.each do |attr_name|
|
92
61
|
eigenclass.send(:define_method, "#{attr_name}=") do |value|
|
93
|
-
|
62
|
+
@has_moderated_fake_attributes[attr_name.to_s] = value
|
94
63
|
end
|
95
64
|
end
|
96
65
|
end
|
97
66
|
|
98
67
|
# associations
|
99
|
-
object_cache
|
100
|
-
|
101
|
-
object_cache[record.class][record.id] = obj
|
102
|
-
eigenclass.send(:define_method, :reflections) do
|
103
|
-
record.class.reflections.reject{|k,v| k.to_sym == :moderations}
|
104
|
-
end
|
68
|
+
object_cache.push(obj)
|
69
|
+
has_moderated_fake_associations = HashWithIndifferentAccess.new
|
105
70
|
record.class.reflections.values.reject{|s| s.name.to_sym == :moderations}.each do |reflection|
|
106
71
|
if reflection.macro == :has_one || reflection.macro == :belongs_to
|
107
|
-
|
108
|
-
reflection.name,
|
109
|
-
resolve_record(record.send(reflection.name), object_cache),
|
110
|
-
eigenclass)
|
72
|
+
has_moderated_fake_associations[reflection.name] = resolve_record(record.send(reflection.name), object_cache)
|
111
73
|
elsif reflection.collection?
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
74
|
+
has_moderated_fake_associations[reflection.name] = record.send(reflection.name).map{|r| resolve_record(r, object_cache)}
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
obj.instance_variable_set(:@has_moderated_fake_associations, has_moderated_fake_associations.freeze)
|
79
|
+
eigenclass.class_eval do
|
80
|
+
def association(name)
|
81
|
+
OpenStruct.new(:reader => @has_moderated_fake_associations[name].freeze)
|
116
82
|
end
|
117
83
|
end
|
118
84
|
|