has_moderated 0.0.9 → 0.0.10
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +12 -0
- data/lib/generators/has_moderated/install/templates/moderation.rb +2 -73
- data/lib/has_moderated/carrier_wave.rb +67 -0
- data/lib/has_moderated/moderation_model.rb +106 -0
- data/lib/has_moderated/version.rb +1 -1
- data/lib/has_moderated.rb +21 -4
- data/test/dummy/app/models/moderation.rb +2 -73
- data/test/dummy/app/models/photo.rb +6 -0
- data/test/dummy/app/models/task.rb +2 -1
- data/test/dummy/app/models/task_photo.rb +5 -0
- data/test/dummy/app/uploaders/generic_uploader.rb +49 -0
- data/test/dummy/db/development.sqlite3 +0 -0
- data/test/dummy/db/migrate/20111003205633_create_photos.rb +9 -0
- data/test/dummy/db/migrate/20111003234101_create_task_photos.rb +10 -0
- data/test/dummy/db/schema.rb +14 -1
- data/test/dummy/db/test.sqlite3 +0 -0
- data/test/dummy/falaf/test.rb +0 -0
- data/test/dummy/log/development.log +628 -1251
- data/test/dummy/log/test.log +8473 -10270
- data/test/dummy/public/uploads/task_photo/photo/logo_arnes.gif +0 -0
- data/test/dummy/spec/factories/photos.rb +7 -0
- data/test/dummy/spec/factories/task_photos.rb +7 -0
- data/test/dummy/spec/models/photo_spec.rb +67 -0
- data/test/dummy/spec/models/task_photo_spec.rb +31 -0
- data/test/dummy/spec/models/task_spec.rb +1 -1
- metadata +97 -73
data/README.rdoc
CHANGED
@@ -50,6 +50,18 @@ To moderate destruction of records, use
|
|
50
50
|
|
51
51
|
has_moderated_destroy
|
52
52
|
|
53
|
+
== Moderating associations on existing records
|
54
|
+
Sometimes you will want to moderate association changes for existing records, not only on create. Right now, there is only one way to do this and it's not as automagic as most of the other things. Instead of doing something like
|
55
|
+
|
56
|
+
post.comments << new_comment
|
57
|
+
post.scores << new_score
|
58
|
+
|
59
|
+
You will *instead* have to call add_associations_moderated like so
|
60
|
+
|
61
|
+
post.add_associations_moderated(:comments => [new_comment], :scores => [new_score])
|
62
|
+
|
63
|
+
The values can be either new records (not in the database), existing records, or Fixnum (numerical) IDs. Please note you should not use .build to create new records, because if you call save on the parent model it will automatically create the record, bypassing moderation.
|
64
|
+
|
53
65
|
== Manage moderations
|
54
66
|
To see pending moderations, simply call
|
55
67
|
|
@@ -1,76 +1,5 @@
|
|
1
1
|
class Moderation < ActiveRecord::Base
|
2
2
|
belongs_to :moderatable, :polymorphic => true
|
3
|
-
|
4
|
-
|
5
|
-
# case: moderated destruction
|
6
|
-
if attr_name == '-' && attr_value.class == String && attr_value == "destroy"
|
7
|
-
moderatable.has_moderated_updating = true
|
8
|
-
moderatable.destroy
|
9
|
-
moderatable.has_moderated_updating = false
|
10
|
-
self.destroy
|
11
|
-
elsif attr_name == '-'
|
12
|
-
loaded_val = YAML::load(attr_value)
|
13
|
-
# case: moderated existance (new record)
|
14
|
-
if moderatable_id.blank?
|
15
|
-
# create the main record
|
16
|
-
rec = moderatable_type.constantize.new
|
17
|
-
attrs = loaded_val[:main_model]
|
18
|
-
# bypass attr_accessible protection
|
19
|
-
attrs.each_pair do |key, val|
|
20
|
-
rec.send(key.to_s+"=", val) unless key.to_s == 'id'
|
21
|
-
end
|
22
|
-
# temporarily disable moderation check on save, and save updated record
|
23
|
-
rec.has_moderated_updating = true
|
24
|
-
rec.save(:validate => false) # don't run validations
|
25
|
-
rec.has_moderated_updating = false
|
26
|
-
# case: moderated associations (existing record)
|
27
|
-
else
|
28
|
-
rec = moderatable
|
29
|
-
end
|
30
|
-
|
31
|
-
# check for saved associated records
|
32
|
-
loaded_val[:associations].each_pair do |assoc_name, assoc_records|
|
33
|
-
# read reflections attribute to determine proper class name and primary key
|
34
|
-
assoc_details = rec.class.reflections[assoc_name.to_sym]
|
35
|
-
m = assoc_details.class_name.constantize
|
36
|
-
|
37
|
-
# all records for this associated model
|
38
|
-
assoc_records.each do |attrs|
|
39
|
-
if attrs.class == Fixnum # associate to existing record
|
40
|
-
arec = m.find_by_id(attrs)
|
41
|
-
rec.send(assoc_name.to_s) << arec if arec # add the association, if the record still exists
|
42
|
-
else # create a new record
|
43
|
-
arec = m.new # new associated model
|
44
|
-
attrs.each_pair do |key, val|
|
45
|
-
arec.send(key.to_s+"=", val) unless key.to_s == 'id'
|
46
|
-
end
|
47
|
-
fk = if assoc_details.respond_to?(:foreign_key)
|
48
|
-
assoc_details.foreign_key
|
49
|
-
else # version < 3.1
|
50
|
-
assoc_details.primary_key_name
|
51
|
-
end
|
52
|
-
arec.send(fk.to_s+"=", rec.id) # set association to the newly created record
|
53
|
-
# disable moderation for associated model (if enabled)
|
54
|
-
arec.has_moderated_updating = true if arec.respond_to?("has_moderated_updating=")
|
55
|
-
arec.save(:validate => false) # don't run validations
|
56
|
-
arec.has_moderated_updating = false if arec.respond_to?("has_moderated_updating=")
|
57
|
-
end
|
58
|
-
end
|
59
|
-
end
|
60
|
-
self.destroy # destroy this moderation since it has been applied
|
61
|
-
rec
|
62
|
-
# case: moderated attribute (existing record)
|
63
|
-
else
|
64
|
-
moderatable.has_moderated_updating = true
|
65
|
-
# bypass attr_accessible protection
|
66
|
-
moderatable.send(attr_name.to_s+"=", YAML::load(attr_value))
|
67
|
-
moderatable.save(:validate => false) # don't run validations
|
68
|
-
moderatable.has_moderated_updating = false
|
69
|
-
self.destroy # destroy this moderation since it has been applied
|
70
|
-
end
|
71
|
-
end
|
72
|
-
|
73
|
-
def discard
|
74
|
-
self.destroy
|
75
|
-
end
|
3
|
+
|
4
|
+
include HasModerated::ModerationModel
|
76
5
|
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
module HasModerated
|
3
|
+
module CarrierWave
|
4
|
+
|
5
|
+
def self.included(base)
|
6
|
+
base.send :extend, ClassMethods
|
7
|
+
base.send :include, InstanceMethods
|
8
|
+
|
9
|
+
base.alias_method_chain :store_photo!, :moderation
|
10
|
+
base.alias_method_chain :write_photo_identifier, :moderation
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.photo_tmp_delete(value)
|
14
|
+
FileUtils.rm(value) # remove temp file
|
15
|
+
FileUtils.rmdir(File.expand_path("..", value)) # will only remove folder if empty
|
16
|
+
end
|
17
|
+
|
18
|
+
module ClassMethods
|
19
|
+
# use class method because we only operate on hash parameters, not with a real record
|
20
|
+
# here we can delete the photo from tmp
|
21
|
+
def moderatable_discard(moderation)
|
22
|
+
value = moderation.interpreted_value
|
23
|
+
if value && value.respond_to?("[]") &&
|
24
|
+
value[:main_model] && value[:main_model][:photo_tmp_file]
|
25
|
+
HasModerated::CarrierWave::photo_tmp_delete(value[:main_model][:photo_tmp_file])
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
module InstanceMethods
|
31
|
+
attr_accessor :has_moderated_updating # in case this model itself is not moderated
|
32
|
+
# maybe autodetect fields that use carrierwave, or specify them
|
33
|
+
def moderatable_hashize
|
34
|
+
attrs = self.attributes
|
35
|
+
attrs = attrs.merge({
|
36
|
+
:photo_tmp_file => self.photo.file.file
|
37
|
+
}) if self.photo && self.photo.file
|
38
|
+
end
|
39
|
+
|
40
|
+
def photo_tmp_file=(value)
|
41
|
+
self.photo.store!(File.open(value))
|
42
|
+
HasModerated::CarrierWave::photo_tmp_delete(value)
|
43
|
+
end
|
44
|
+
|
45
|
+
def store_photo_with_moderation!
|
46
|
+
is_moderated = self.class.respond_to?(:moderated_attributes) &&
|
47
|
+
self.class.moderated_attributes.include?("photo")
|
48
|
+
if self.has_moderated_updating || !is_moderated
|
49
|
+
store_photo_without_moderation!
|
50
|
+
else
|
51
|
+
self.moderations.create!({
|
52
|
+
:attr_name => "photo_tmp_file",
|
53
|
+
:attr_value => self.photo.file.file
|
54
|
+
})
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def write_photo_identifier_with_moderation
|
59
|
+
is_moderated = self.class.respond_to?(:moderated_attributes) &&
|
60
|
+
self.class.moderated_attributes.include?("photo")
|
61
|
+
if self.has_moderated_updating || !is_moderated
|
62
|
+
write_photo_identifier_without_moderation
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,106 @@
|
|
1
|
+
module HasModerated
|
2
|
+
module ModerationModel
|
3
|
+
|
4
|
+
def interpreted_value
|
5
|
+
@interpreted_value ||= if attr_name == '-'
|
6
|
+
YAML::load(attr_value)
|
7
|
+
else
|
8
|
+
attr_value
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def create_from_value
|
13
|
+
if moderatable_id.blank?
|
14
|
+
# create the main record
|
15
|
+
rec = moderatable_type.constantize.new
|
16
|
+
attrs = interpreted_value[:main_model]
|
17
|
+
# bypass attr_accessible protection
|
18
|
+
attrs && attrs.each_pair do |key, val|
|
19
|
+
rec.send(key.to_s+"=", val) unless key.to_s == 'id'
|
20
|
+
end
|
21
|
+
rec
|
22
|
+
else
|
23
|
+
nil
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def update_associations_from_value rec
|
28
|
+
# loop association types, e.g. :comments
|
29
|
+
interpreted_value[:associations].each_pair do |assoc_name, assoc_records|
|
30
|
+
# read reflections attribute to determine proper class name and primary key
|
31
|
+
assoc_details = rec.class.reflections[assoc_name.to_sym]
|
32
|
+
m = assoc_details.class_name.constantize
|
33
|
+
|
34
|
+
# all instances for this association type
|
35
|
+
assoc_records.each do |attrs|
|
36
|
+
# PARAM = ID
|
37
|
+
if attrs.class == Fixnum
|
38
|
+
arec = m.find_by_id(attrs)
|
39
|
+
# add the association, if the record still existss
|
40
|
+
rec.send(assoc_name.to_s) << arec if arec
|
41
|
+
# PARAM = Hash (create)
|
42
|
+
else
|
43
|
+
arec = m.new
|
44
|
+
attrs.each_pair do |key, val|
|
45
|
+
arec.send(key.to_s+"=", val) unless key.to_s == 'id'
|
46
|
+
end
|
47
|
+
fk = if assoc_details.respond_to?(:foreign_key)
|
48
|
+
assoc_details.foreign_key
|
49
|
+
else # Rails < v3.1
|
50
|
+
assoc_details.primary_key_name
|
51
|
+
end
|
52
|
+
arec.send(fk.to_s+"=", rec.id) # set association to the newly created record
|
53
|
+
# disable moderation for associated model (if moderated)
|
54
|
+
arec.has_moderated_updating = true if arec.respond_to?("has_moderated_updating=")
|
55
|
+
arec.save(:validate => false) # don't run validations
|
56
|
+
arec.has_moderated_updating = false if arec.respond_to?("has_moderated_updating=")
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def accept
|
63
|
+
# DESTROY
|
64
|
+
if attr_name == '-' && attr_value.class == String && attr_value == "destroy"
|
65
|
+
moderatable.moderatable_updating { moderatable.destroy }
|
66
|
+
self.destroy
|
67
|
+
|
68
|
+
# CREATE or ASSOCIATIONS
|
69
|
+
elsif attr_name == '-'
|
70
|
+
loaded_val = YAML::load(attr_value)
|
71
|
+
# case: moderated existance (new record)
|
72
|
+
if moderatable_id.blank?
|
73
|
+
rec = create_from_value
|
74
|
+
# save, don't run validations
|
75
|
+
rec.moderatable_updating { rec.save(:validate => false) }
|
76
|
+
# case: moderated associations (existing record)
|
77
|
+
else
|
78
|
+
rec = moderatable
|
79
|
+
end
|
80
|
+
|
81
|
+
# check for saved associated records
|
82
|
+
update_associations_from_value rec
|
83
|
+
|
84
|
+
self.destroy # destroy this moderation since it has been applied
|
85
|
+
rec
|
86
|
+
|
87
|
+
# CHANGE ATTRIBUTE
|
88
|
+
else
|
89
|
+
moderatable.moderatable_updating do
|
90
|
+
# bypass attr_accessible protection
|
91
|
+
moderatable.send(attr_name.to_s+"=", YAML::load(attr_value))
|
92
|
+
moderatable.save(:validate => false) # don't run validations
|
93
|
+
end
|
94
|
+
self.destroy # destroy this moderation since it has been applied
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def discard
|
99
|
+
if moderatable_type
|
100
|
+
klass = moderatable_type.constantize
|
101
|
+
klass.moderatable_discard(self) if klass.respond_to?(:moderatable_discard)
|
102
|
+
end
|
103
|
+
self.destroy
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
data/lib/has_moderated.rb
CHANGED
@@ -1,3 +1,6 @@
|
|
1
|
+
require 'has_moderated/moderation_model'
|
2
|
+
require 'has_moderated/carrier_wave'
|
3
|
+
|
1
4
|
module HasModerated
|
2
5
|
|
3
6
|
def self.included(base)
|
@@ -110,7 +113,7 @@ module HasModerated
|
|
110
113
|
|
111
114
|
def get_assocs_for_moderation options
|
112
115
|
assocs = []
|
113
|
-
|
116
|
+
|
114
117
|
unless options.blank?
|
115
118
|
unless options[:with_associations].blank?
|
116
119
|
if options[:with_associations] == :all
|
@@ -129,7 +132,7 @@ module HasModerated
|
|
129
132
|
one_assoc = []
|
130
133
|
self.send(assoc).each do |m|
|
131
134
|
if m.new_record?
|
132
|
-
one_assoc.push(m
|
135
|
+
one_assoc.push(get_moderation_attributes(m))
|
133
136
|
else
|
134
137
|
one_assoc.push(m.id)
|
135
138
|
end
|
@@ -140,11 +143,19 @@ module HasModerated
|
|
140
143
|
assoc_attrs
|
141
144
|
end
|
142
145
|
|
146
|
+
def get_moderation_attributes(model)
|
147
|
+
if model.respond_to?(:moderatable_hashize)
|
148
|
+
model.moderatable_hashize
|
149
|
+
else
|
150
|
+
model.attributes
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
143
154
|
def to_moderation_created options
|
144
155
|
assoc_attrs = get_assocs_for_moderation(options)
|
145
156
|
|
146
157
|
attr_value = {
|
147
|
-
:main_model => self
|
158
|
+
:main_model => get_moderation_attributes(self),
|
148
159
|
:associations => assoc_attrs
|
149
160
|
}
|
150
161
|
|
@@ -182,7 +193,7 @@ module HasModerated
|
|
182
193
|
if m.class == Fixnum
|
183
194
|
one_assoc.push(m)
|
184
195
|
elsif m.new_record?
|
185
|
-
one_assoc.push(m
|
196
|
+
one_assoc.push(get_moderation_attributes(m))
|
186
197
|
else
|
187
198
|
one_assoc.push(m.id)
|
188
199
|
end
|
@@ -202,6 +213,12 @@ module HasModerated
|
|
202
213
|
|
203
214
|
moderations
|
204
215
|
end
|
216
|
+
|
217
|
+
def moderatable_updating
|
218
|
+
self.has_moderated_updating = true
|
219
|
+
yield(self)
|
220
|
+
self.has_moderated_updating = false
|
221
|
+
end
|
205
222
|
end
|
206
223
|
end
|
207
224
|
|
@@ -1,76 +1,5 @@
|
|
1
1
|
class Moderation < ActiveRecord::Base
|
2
2
|
belongs_to :moderatable, :polymorphic => true
|
3
|
-
|
4
|
-
|
5
|
-
# case: moderated destruction
|
6
|
-
if attr_name == '-' && attr_value.class == String && attr_value == "destroy"
|
7
|
-
moderatable.has_moderated_updating = true
|
8
|
-
moderatable.destroy
|
9
|
-
moderatable.has_moderated_updating = false
|
10
|
-
self.destroy
|
11
|
-
elsif attr_name == '-'
|
12
|
-
loaded_val = YAML::load(attr_value)
|
13
|
-
# case: moderated existance (new record)
|
14
|
-
if moderatable_id.blank?
|
15
|
-
# create the main record
|
16
|
-
rec = moderatable_type.constantize.new
|
17
|
-
attrs = loaded_val[:main_model]
|
18
|
-
# bypass attr_accessible protection
|
19
|
-
attrs.each_pair do |key, val|
|
20
|
-
rec.send(key.to_s+"=", val) unless key.to_s == 'id'
|
21
|
-
end
|
22
|
-
# temporarily disable moderation check on save, and save updated record
|
23
|
-
rec.has_moderated_updating = true
|
24
|
-
rec.save(:validate => false) # don't run validations
|
25
|
-
rec.has_moderated_updating = false
|
26
|
-
# case: moderated associations (existing record)
|
27
|
-
else
|
28
|
-
rec = moderatable
|
29
|
-
end
|
30
|
-
|
31
|
-
# check for saved associated records
|
32
|
-
loaded_val[:associations].each_pair do |assoc_name, assoc_records|
|
33
|
-
# read reflections attribute to determine proper class name and primary key
|
34
|
-
assoc_details = rec.class.reflections[assoc_name.to_sym]
|
35
|
-
m = assoc_details.class_name.constantize
|
36
|
-
|
37
|
-
# all records for this associated model
|
38
|
-
assoc_records.each do |attrs|
|
39
|
-
if attrs.class == Fixnum # associate to existing record
|
40
|
-
arec = m.find_by_id(attrs)
|
41
|
-
rec.send(assoc_name.to_s) << arec if arec # add the association, if the record still exists
|
42
|
-
else # create a new record
|
43
|
-
arec = m.new # new associated model
|
44
|
-
attrs.each_pair do |key, val|
|
45
|
-
arec.send(key.to_s+"=", val) unless key.to_s == 'id'
|
46
|
-
end
|
47
|
-
fk = if assoc_details.respond_to?(:foreign_key)
|
48
|
-
assoc_details.foreign_key
|
49
|
-
else # version < 3.1
|
50
|
-
assoc_details.primary_key_name
|
51
|
-
end
|
52
|
-
arec.send(fk.to_s+"=", rec.id) # set association to the newly created record
|
53
|
-
# disable moderation for associated model (if enabled)
|
54
|
-
arec.has_moderated_updating = true if arec.respond_to?("has_moderated_updating=")
|
55
|
-
arec.save(:validate => false) # don't run validations
|
56
|
-
arec.has_moderated_updating = false if arec.respond_to?("has_moderated_updating=")
|
57
|
-
end
|
58
|
-
end
|
59
|
-
end
|
60
|
-
self.destroy # destroy this moderation since it has been applied
|
61
|
-
rec
|
62
|
-
# case: moderated attribute (existing record)
|
63
|
-
else
|
64
|
-
moderatable.has_moderated_updating = true
|
65
|
-
# bypass attr_accessible protection
|
66
|
-
moderatable.send(attr_name.to_s+"=", YAML::load(attr_value))
|
67
|
-
moderatable.save(:validate => false) # don't run validations
|
68
|
-
moderatable.has_moderated_updating = false
|
69
|
-
self.destroy # destroy this moderation since it has been applied
|
70
|
-
end
|
71
|
-
end
|
72
|
-
|
73
|
-
def discard
|
74
|
-
self.destroy
|
75
|
-
end
|
3
|
+
|
4
|
+
include HasModerated::ModerationModel
|
76
5
|
end
|
@@ -1,7 +1,8 @@
|
|
1
1
|
class Task < ActiveRecord::Base
|
2
2
|
attr_accessible :title
|
3
3
|
has_many :subtasks
|
4
|
+
has_many :task_photos
|
4
5
|
has_moderated :title, :desc, { :with_associations => [:subtasks] }
|
5
|
-
has_moderated_create :with_associations => [:subtasks]
|
6
|
+
has_moderated_create :with_associations => [:subtasks, :task_photos]
|
6
7
|
has_moderated_destroy
|
7
8
|
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
class GenericUploader < CarrierWave::Uploader::Base
|
4
|
+
|
5
|
+
# Include RMagick or ImageScience support:
|
6
|
+
# include CarrierWave::RMagick
|
7
|
+
# include CarrierWave::MiniMagick
|
8
|
+
# include CarrierWave::ImageScience
|
9
|
+
|
10
|
+
# Choose what kind of storage to use for this uploader:
|
11
|
+
storage :file
|
12
|
+
# storage :fog
|
13
|
+
|
14
|
+
# Override the directory where uploaded files will be stored.
|
15
|
+
# This is a sensible default for uploaders that are meant to be mounted:
|
16
|
+
def store_dir
|
17
|
+
"uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
|
18
|
+
end
|
19
|
+
|
20
|
+
# Provide a default URL as a default if there hasn't been a file uploaded:
|
21
|
+
# def default_url
|
22
|
+
# "/images/fallback/" + [version_name, "default.png"].compact.join('_')
|
23
|
+
# end
|
24
|
+
|
25
|
+
# Process files as they are uploaded:
|
26
|
+
# process :scale => [200, 300]
|
27
|
+
#
|
28
|
+
# def scale(width, height)
|
29
|
+
# # do something
|
30
|
+
# end
|
31
|
+
|
32
|
+
# Create different versions of your uploaded files:
|
33
|
+
# version :thumb do
|
34
|
+
# process :scale => [50, 50]
|
35
|
+
# end
|
36
|
+
|
37
|
+
# Add a white list of extensions which are allowed to be uploaded.
|
38
|
+
# For images you might use something like this:
|
39
|
+
# def extension_white_list
|
40
|
+
# %w(jpg jpeg gif png)
|
41
|
+
# end
|
42
|
+
|
43
|
+
# Override the filename of the uploaded files:
|
44
|
+
# Avoid using model.id or version_name here, see uploader/store.rb for details.
|
45
|
+
# def filename
|
46
|
+
# "something.jpg" if original_filename
|
47
|
+
# end
|
48
|
+
|
49
|
+
end
|
Binary file
|
data/test/dummy/db/schema.rb
CHANGED
@@ -10,7 +10,7 @@
|
|
10
10
|
#
|
11
11
|
# It's strongly recommended to check this file into your version control system.
|
12
12
|
|
13
|
-
ActiveRecord::Schema.define(:version =>
|
13
|
+
ActiveRecord::Schema.define(:version => 20111003234101) do
|
14
14
|
|
15
15
|
create_table "moderations", :force => true do |t|
|
16
16
|
t.integer "moderatable_id"
|
@@ -21,6 +21,12 @@ ActiveRecord::Schema.define(:version => 20110908025606) do
|
|
21
21
|
t.datetime "updated_at"
|
22
22
|
end
|
23
23
|
|
24
|
+
create_table "photos", :force => true do |t|
|
25
|
+
t.string "photo"
|
26
|
+
t.datetime "created_at"
|
27
|
+
t.datetime "updated_at"
|
28
|
+
end
|
29
|
+
|
24
30
|
create_table "subtasks", :force => true do |t|
|
25
31
|
t.integer "task_id"
|
26
32
|
t.string "title"
|
@@ -37,6 +43,13 @@ ActiveRecord::Schema.define(:version => 20110908025606) do
|
|
37
43
|
t.datetime "updated_at"
|
38
44
|
end
|
39
45
|
|
46
|
+
create_table "task_photos", :force => true do |t|
|
47
|
+
t.string "photo"
|
48
|
+
t.integer "task_id"
|
49
|
+
t.datetime "created_at"
|
50
|
+
t.datetime "updated_at"
|
51
|
+
end
|
52
|
+
|
40
53
|
create_table "tasks", :force => true do |t|
|
41
54
|
t.string "title"
|
42
55
|
t.string "desc"
|
data/test/dummy/db/test.sqlite3
CHANGED
Binary file
|
File without changes
|