Permalink
Browse files

carrierwave moderation updated

  • Loading branch information...
1 parent 166afc1 commit ce20dc9e97183f774dbc18c4aac9ae32ebbd706a @mrbrdo committed May 20, 2012
Showing with 292 additions and 422 deletions.
  1. +0 −1 Gemfile
  2. +0 −3 Gemfile.lock
  3. +36 −13 README.rdoc
  4. +2 −0 lib/has_moderated.rb
  5. +69 −46 lib/has_moderated/carrier_wave.rb
  6. +1 −1 lib/has_moderated/moderated_create.rb
  7. +7 −3 lib/has_moderated/moderation_model.rb
  8. +4 −0 test/dummy/app/models/photo.rb
  9. +0 −10 test/dummy/db/migrate/20110901013205_create_tasks.rb
  10. +0 −11 test/dummy/db/migrate/20110901013228_create_subtasks.rb
  11. +0 −15 test/dummy/db/migrate/20110901013618_create_moderations.rb
  12. +0 −10 test/dummy/db/migrate/20110908025410_create_task_alls.rb
  13. +0 −5 test/dummy/db/migrate/20110908025606_add_task_all_id_to_subtasks.rb
  14. +0 −9 test/dummy/db/migrate/20111003205633_create_photos.rb
  15. +0 −10 test/dummy/db/migrate/20111003234101_create_task_photos.rb
  16. +0 −10 test/dummy/db/migrate/20111004153147_create_hook_tests.rb
  17. +0 −10 test/dummy/db/migrate/20111004164509_create_photo_holders.rb
  18. +0 −9 test/dummy/db/migrate/20111008195728_create_hone_tests.rb
  19. +0 −13 test/dummy/db/migrate/20111008195809_create_hjoin_tests.rb
  20. +0 −8 test/dummy/db/migrate/20111009193145_fix_join_table.rb
  21. +0 −5 test/dummy/db/migrate/20111009201729_add_title_to_hone_tests.rb
  22. +0 −9 test/dummy/db/migrate/20111009205517_create_hmanythrough_tests.rb
  23. +0 −11 test/dummy/db/migrate/20111009205545_create_hmanythrough_joins.rb
  24. +0 −11 test/dummy/db/migrate/20111018172409_create_hone_as_tests.rb
  25. +0 −10 test/dummy/db/migrate/20111018174319_create_hmany_fk_tests.rb
  26. +0 −13 test/dummy/db/migrate/20111018180207_create_habtm_name_tests.rb
  27. +0 −10 test/dummy/db/migrate/20120209045206_create_photo_relateds.rb
  28. +0 −20 test/dummy/db/migrate/20120515155730_create_moderations2.rb
  29. +0 −36 test/dummy/db/migrate/20120515174306_prepare_for_new_tests.rb
  30. +0 −8 test/dummy/db/migrate/20120515175621_remove_photo_relateds.rb
  31. +48 −0 test/dummy/db/migrate/20120520215008_initial_schema.rb
  32. +13 −0 test/dummy/db/migrate/20120520215224_create_photos.rb
  33. +11 −1 test/dummy/db/schema.rb
  34. BIN test/dummy/public/uploads/{task_photo/photo → photo/avatar}/1/test.jpg
  35. BIN test/dummy/public/uploads/{task_photo/photo → photo/avatar}/1/thumb_test.jpg
  36. +0 −7 test/dummy/spec/factories/habtm_name_tests.rb
  37. +0 −7 test/dummy/spec/factories/hjoin_tests.rb
  38. +0 −8 test/dummy/spec/factories/hmany_fk_tests.rb
  39. +0 −9 test/dummy/spec/factories/hmanythrough_joins.rb
  40. +0 −7 test/dummy/spec/factories/hmanythrough_tests.rb
  41. +0 −9 test/dummy/spec/factories/hone_as_tests.rb
  42. +0 −7 test/dummy/spec/factories/hone_tests.rb
  43. +0 −8 test/dummy/spec/factories/hook_tests.rb
  44. +0 −7 test/dummy/spec/factories/photo_holders.rb
  45. +0 −8 test/dummy/spec/factories/photo_relateds.rb
  46. +0 −7 test/dummy/spec/factories/photos.rb
  47. +0 −8 test/dummy/spec/factories/task_alls.rb
  48. +0 −7 test/dummy/spec/factories/task_photos.rb
  49. +95 −0 test/dummy/spec/models/photo_spec.rb
  50. +6 −2 test/dummy/spec/support/photos.rb
View
@@ -14,7 +14,6 @@ gemspec
# gem 'ruby-debug'
gem 'rspec'
gem 'rspec-rails'
-gem 'factory_girl'
gem 'rails3-generators'
gem 'carrierwave'
gem 'ruby-debug'
View
@@ -41,8 +41,6 @@ GEM
columnize (0.3.6)
diff-lcs (1.1.3)
erubis (2.7.0)
- factory_girl (2.5.1)
- activesupport
ffi (1.0.11)
guard (1.0.3)
ffi (>= 0.5.0)
@@ -130,7 +128,6 @@ PLATFORMS
DEPENDENCIES
carrierwave
- factory_girl
guard-rspec
guard-spork
has_moderated!
View
@@ -88,9 +88,13 @@ You can also see moderations for a specific record. For example, if you have Pos
post = Post.first
post.moderations
-Moderation is a normal ActiveRecord model, you can inspect it in rails console to see what it holds. Data is serialized in YAML format and can be deserialized by calling
+Moderation is a normal ActiveRecord model, you can inspect it in rails console to see what it holds. Data is serialized in YAML format
- YAML::load(moderation.data)
+ moderation.data
+
+The data can be deserialized using YAML::load, but this has already been done for you
+
+ moderation.parsed_data
To accept a moderation, call
@@ -139,24 +143,48 @@ This is just one example how you can do it. You need the attr_accessor here beca
== CarrierWave support
-There is support for CarrierWave uploads to be moderated. You must put this line into the model that has a CarrierWave uploader mounted:
+There is support for CarrierWave uploads to be moderated. If you need some more customization look at this module in lib/has_moderated/carrier_wave.rb and make your own version.
+
+=== Example of moderating uploads
+
+This will moderate the upload no matter if the record is being created, or updated. Other unmoderated fields will be saved normally.
+ mount_uploader :avatar, GenericUploader
include HasModerated::CarrierWave
+ has_moderated_carrierwave_field :avatar
+ has_moderated :avatar
-Right now *you must use the field name "photo" for the upload filename* because it is currently hardcoded into this module. If you do this, then moderation for the photo should work correctly.
+=== Example of moderating create of the whole model using a CarrierWave uploader
-It does not matter if this model has any moderation itself or if you just have an association to it from some other model that is moderated. You must include this module in either case, because it ensures proper serialization of the photo information.
-If you want to moderate changes to the photo on this model itself (e.g. not only when its associated to something else), add also
+This will moderate creating the whole record (all its fields), including the upload.
- has_moderated :carrierwave_photo
+ mount_uploader :avatar, GenericUploader
+ has_moderated_create
+ include HasModerated::CarrierWave
+ has_moderated_carrierwave_field :avatar
+
+To moderate later changes to the upload (avatar), additionally add
-If you need some more customization look at this module in lib/has_moderated/carrier_wave.rb and just copy the methods into your model and customize them (with some care when you do this, some methods should be class methods).
+ has_moderated :avatar
+
+=== Example of moderating on association
+
+If you are moderating some other model, and the model with the upload is an association to it, you still need to add this
+
+ mount_uploader :avatar, GenericUploader
+ include HasModerated::CarrierWave
+ has_moderated_carrierwave_field :avatar
+
+This will only moderate the upload when it's being saved through an association which has
+
+ has_moderated_association :photos
== Tests
I've tested this project using RSpec. You can find the tests in
test/dummy/spec/models/task_spec.rb
+ test/dummy/spec/models/photo_spec.rb
You can run the tests by running
@@ -187,11 +215,6 @@ to make it possible to support other than activerecord, use activemodel when its
use YARD for docs
check again railscasts episodes for gems (e.g. railties)
--
-
-make hasone, hasmany etc. each a separate "extension" (like carrierwave). for tests just use 2 models (task, subtask) and dont define has_many in model but in test
-
-Amend moderations... Eg if you create a new record and save it, then change something additionally and save again.
Preview method which gives changed object but doesnt save it.
== License
@@ -13,6 +13,8 @@
require 'has_moderated/moderated_create'
require 'has_moderated/moderated_destroy'
+require 'has_moderated/carrier_wave'
+
module HasModerated
def self.included(base)
HasModerated::Common::included(base)
@@ -4,10 +4,6 @@ module CarrierWave
def self.included(base)
base.send :extend, ClassMethods
- base.send :include, InstanceMethods
-
- base.alias_method_chain :store_photo!, :moderation
- base.alias_method_chain :write_photo_identifier, :moderation
end
def self.photo_tmp_delete(value)
@@ -29,57 +25,84 @@ def self.photo_tmp_delete(value)
end
module ClassMethods
+ def has_moderated_carrierwave_field field_names
+ base = self
+ base.send :include, InstanceMethods
+
+ cattr_accessor :moderated_carrierwave_fields
+
+ field_names = [field_names] unless field_names.kind_of? Array
+
+ field_names.each do |field_name|
+ field_name = field_name.to_s
+ self.moderated_carrierwave_fields ||= []
+ self.moderated_carrierwave_fields.push(field_name)
+
+ base.send :define_method, "#{field_name}_tmp_file=" do |value|
+ self.send("#{field_name}=", File.open(value))
+ HasModerated::CarrierWave::photo_tmp_delete(value)
+ end
+
+ base.send :define_method, "store_#{field_name}_with_moderation!" do
+ is_moderated = self.class.respond_to?(:moderated_attributes) &&
+ self.class.moderated_attributes.include?(field_name)
+ if !is_moderated || self.moderation_disabled || !self.send("#{field_name}_changed?")
+ self.send("store_#{field_name}_without_moderation!")
+ else
+ self.create_moderation_with_hooks!({
+ :attributes => {
+ "#{field_name}_tmp_file" => self.send(field_name).file.file
+ }
+ })
+ end
+ end
+
+ base.send :define_method, "write_#{field_name}_identifier_with_moderation" do
+ is_moderated = self.class.respond_to?(:moderated_attributes) &&
+ self.class.moderated_attributes.include?(field_name)
+ if !is_moderated || self.moderation_disabled || !self.send("#{field_name}_changed?")
+ self.send("write_#{field_name}_identifier_without_moderation")
+ end
+ end
+
+ base.alias_method_chain :get_moderation_attributes, :carrierwave unless base.instance_methods.include?("get_moderation_attributes_without_carrierwave")
+ base.alias_method_chain "store_#{field_name}!", :moderation
+ base.alias_method_chain "write_#{field_name}_identifier", :moderation
+ end
+ end
+
# use class method because we only operate on hash parameters, not with a real record
# here we can delete the photo from tmp
def moderatable_discard(moderation)
- value = moderation.interpreted_value
- if moderation.attr_name == "-" && value && value.respond_to?("[]") &&
- value[:main_model] && value[:main_model][:photo_tmp_file]
- value = value[:main_model][:photo_tmp_file]
- elsif moderation.attr_name != "photo_tmp_file"
- return # we dont want to process anything else than the above
- end
-
- unless value.blank?
- HasModerated::CarrierWave::photo_tmp_delete(value)
+ value = moderation.parsed_data
+
+ moderated_carrierwave_fields.each do |field_name|
+ if value.kind_of? Hash
+ if value.has_key?(:create) && value[:create].has_key?(:attributes)
+ value = value[:create]
+ end
+ if value.has_key?(:attributes) && value[:attributes].has_key?("#{field_name}_tmp_file")
+ value = value[:attributes].send("#{field_name}_tmp_file")
+ if value.present?
+ HasModerated::CarrierWave::photo_tmp_delete(value)
+ end
+ else
+ return # we dont want to process anything else than the above
+ end
+ end
end
end
end
module InstanceMethods
- attr_accessor :moderation_disabled # in case this model itself is not moderated
- # maybe autodetect fields that use carrierwave, or specify them
- def moderatable_hashize
- attrs = self.attributes
- attrs = attrs.merge({
- :photo_tmp_file => self.photo.file.file
- }) if self.photo && self.photo.file
- end
-
- def photo_tmp_file=(value)
- self.photo = File.open(value)
- HasModerated::CarrierWave::photo_tmp_delete(value)
- end
-
- def store_photo_with_moderation!
- is_moderated = self.class.respond_to?(:moderated_attributes) &&
- self.class.moderated_attributes.include?("carrierwave_photo")
- if self.moderation_disabled || !is_moderated || !self.photo_changed?
- store_photo_without_moderation!
- else
- self.moderations.create!({
- :attr_name => "photo_tmp_file",
- :attr_value => self.photo.file.file
- })
- end
- end
-
- def write_photo_identifier_with_moderation
- is_moderated = self.class.respond_to?(:moderated_attributes) &&
- self.class.moderated_attributes.include?("carrierwave_photo")
- if self.moderation_disabled || !is_moderated || !self.photo_changed?
- write_photo_identifier_without_moderation
+ def get_moderation_attributes_with_carrierwave
+ attrs = get_moderation_attributes_without_carrierwave
+ self.class.moderated_carrierwave_fields.each do |field_name|
+ attrs = attrs.merge({
+ "#{field_name}_tmp_file" => self.send(field_name).file.file
+ }) if self.send(field_name) && self.send(field_name).file
end
+ attrs
end
end
end
@@ -26,7 +26,7 @@ def self.apply(moderation, value)
rec.send(key.to_s+"=", val) unless key.to_s == 'id'
end
rec.without_moderation { rec.save(:validate => false) }
- moderation.moderatable = rec
+ moderation.moderatable = rec # just so associations can be applied in next line
HasModerated::Associations::Base::ApplyModeration::apply(moderation, value[:create])
end
end
@@ -1,10 +1,14 @@
module HasModerated
module ModerationModel
+ def parsed_data
+ @parsed_data ||= YAML::load(data)
+ end
+
def accept
- loaded_val = YAML::load(data)
- HasModerated::Associations::Base::ApplyModeration::apply(self, loaded_val)
- HasModerated::ModeratedAttributes::ApplyModeration::apply(self, loaded_val)
+ loaded_val = parsed_data
HasModerated::ModeratedCreate::ApplyModeration::apply(self, loaded_val)
+ HasModerated::ModeratedAttributes::ApplyModeration::apply(self, loaded_val)
+ HasModerated::Associations::Base::ApplyModeration::apply(self, loaded_val)
HasModerated::ModeratedDestroy::ApplyModeration::apply(self, loaded_val)
self.destroy
end
@@ -0,0 +1,4 @@
+class Photo < ActiveRecord::Base
+ mount_uploader :avatar, GenericUploader
+ mount_uploader :picture, GenericUploader
+end
@@ -1,10 +0,0 @@
-class CreateTasks < ActiveRecord::Migration
- def change
- create_table :tasks do |t|
- t.string :title
- t.string :desc
-
- t.timestamps
- end
- end
-end
@@ -1,11 +0,0 @@
-class CreateSubtasks < ActiveRecord::Migration
- def change
- create_table :subtasks do |t|
- t.integer :task_id
- t.string :title
- t.string :desc
-
- t.timestamps
- end
- end
-end
@@ -1,15 +0,0 @@
-class CreateModerations < ActiveRecord::Migration
- def self.up
- create_table "moderations" do |t|
- t.integer "moderatable_id", :null => true
- t.string "moderatable_type", :null => false
- t.string "attr_name", :limit => 60, :null => false
- t.text "attr_value", :null => false
- t.timestamps
- end
- end
-
- def self.down
- drop_table :moderations
- end
-end
@@ -1,10 +0,0 @@
-class CreateTaskAlls < ActiveRecord::Migration
- def change
- create_table :task_alls do |t|
- t.string :title
- t.string :value
-
- t.timestamps
- end
- end
-end
@@ -1,5 +0,0 @@
-class AddTaskAllIdToSubtasks < ActiveRecord::Migration
- def change
- add_column :subtasks, :task_all_id, :integer
- end
-end
@@ -1,9 +0,0 @@
-class CreatePhotos < ActiveRecord::Migration
- def change
- create_table :photos do |t|
- t.string :photo
-
- t.timestamps
- end
- end
-end
@@ -1,10 +0,0 @@
-class CreateTaskPhotos < ActiveRecord::Migration
- def change
- create_table :task_photos do |t|
- t.string :photo
- t.integer :task_id
-
- t.timestamps
- end
- end
-end
@@ -1,10 +0,0 @@
-class CreateHookTests < ActiveRecord::Migration
- def change
- create_table :hook_tests do |t|
- t.string :title
- t.string :foo
-
- t.timestamps
- end
- end
-end
@@ -1,10 +0,0 @@
-class CreatePhotoHolders < ActiveRecord::Migration
- def change
- create_table :photo_holders do |t|
- t.string :title
-
- t.timestamps
- end
- add_column :photos, :photo_holder_id, :integer
- end
-end
@@ -1,9 +0,0 @@
-class CreateHoneTests < ActiveRecord::Migration
- def change
- create_table :hone_tests do |t|
- t.integer :task_id
-
- t.timestamps
- end
- end
-end
Oops, something went wrong.

0 comments on commit ce20dc9

Please sign in to comment.