effective_trash 0.2.1 → 0.2.2

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: b5861ff673da253d2c1b764bad5f96c21c4ede0f
4
- data.tar.gz: 619b6e251bc29e258dfb2daddcb7e022a7efc4bd
3
+ metadata.gz: d48b6ae4a747e8d6d2567827966736aff26b6b53
4
+ data.tar.gz: e4eb0078becab79191be39d8bb2b0d94159e43f7
5
5
  SHA512:
6
- metadata.gz: 0cc1f9d9d136367ca6777e4f81733a4bc97e6518efee7f8186292a4eb106ae95c4f4f931350485f2d40eeb4369040904076316db05c9910cbc4016feaf267b8b
7
- data.tar.gz: 198377e4829662be812a8bdbb21eafd8b4e8432954a2311347afc45eb64d38ec7e6f926331d3efb89217e4df695d9f3fea898ce668e649884d9af37878aaa9e3
6
+ metadata.gz: 0ff0bc35b9b92526df5bd06991f872f57a5a831779524774490e353160f9cc06c7ed6e46077e4d284d3af8e5a3ace5f5a47d814f540eec77c52a40998b5f9dd1
7
+ data.tar.gz: 208dfa88a8522b943c9135e138a5040ce58916bc2ac21e11bb6609145e20e047244562847fa833e9690896a271a63d2778831d62159fd5f9c265e7e1f1538dfd
data/README.md CHANGED
@@ -81,6 +81,23 @@ can :admin, :effective_trash
81
81
 
82
82
  The user must be permitted to to `:update` an `Effective::Trash` in order to restore the trashed item.
83
83
 
84
+ ## Upgrade database from archived booleans
85
+
86
+ Use the following generator, to produce a database migration:
87
+
88
+ ```
89
+ rails generate effective_trash:trash_archived_booleans
90
+ ```
91
+
92
+ The migration will trash all `archived?` objects, delete them, and replace the archived boolean on the corresponding database table.
93
+
94
+ This upgrades from this gem author's previous archived implementation, which was:
95
+
96
+ - Use an `archived` boolean on each model.
97
+ - Call the model by a scope (or default scope, yuck) somehting like `Post.where(archived: false)`.
98
+
99
+ Don't do that.
100
+
84
101
  ## License
85
102
 
86
103
  MIT License. Copyright [Code and Effect Inc.](http://www.codeandeffect.com/)
@@ -18,7 +18,7 @@ module Admin
18
18
 
19
19
  def show
20
20
  @trash = Effective::Trash.all.find(params[:id])
21
- @page_title = "Trash item - #{@trash.to_s}"
21
+ @page_title = "Trash item - #{@trash.trashed_to_s}"
22
22
 
23
23
  EffectiveTrash.authorized?(self, :show, @trash)
24
24
  EffectiveTrash.authorized?(self, :admin, :effective_trash)
@@ -28,8 +28,7 @@ module Effective
28
28
 
29
29
  Effective::Trash.transaction do
30
30
  begin
31
- @trash.restore_trash!
32
- @trash.destroy!
31
+ @trash.restore!
33
32
  flash[:success] = "Successfully restored #{@trash}"
34
33
  rescue => e
35
34
  flash[:danger] = "Unable to restore: #{e.message}"
@@ -10,21 +10,23 @@ module EffectiveTrashHelper
10
10
  # Any other options are sent to the table tag
11
11
  def tableize_hash(hash, options = {})
12
12
  if hash.present? && hash.kind_of?(Hash)
13
- content_tag(:table, options) do
14
- hash.map do |k, v|
15
- content_tag(:tr) do
16
- content_tag((options[:th] ? :th : :td), k) +
17
- content_tag(:td) do
18
- if v.kind_of?(Hash)
19
- tableize_hash(v, options.merge({:class => 'table table-bordered', :th => (options.key?(:sub_th) ? options[:sub_th] : options[:th])}))
20
- elsif v.kind_of?(Array)
21
- '[' + v.join(', ') + ']'
22
- else
23
- v.to_s
13
+ content_tag(:table, class: options[:class]) do
14
+ content_tag(:tbody) do
15
+ hash.map do |k, v|
16
+ content_tag(:tr) do
17
+ content_tag((options[:th] ? :th : :td), k) +
18
+ content_tag(:td) do
19
+ if v.kind_of?(Hash)
20
+ tableize_hash(v, options.merge({class: 'table table-hover', th: (options.key?(:sub_th) ? options[:sub_th] : options[:th])}))
21
+ elsif v.kind_of?(Array)
22
+ '[' + v.join(', ') + ']'
23
+ else
24
+ v.to_s
25
+ end
24
26
  end
25
27
  end
26
- end
27
- end.join('').html_safe
28
+ end.join('').html_safe
29
+ end
28
30
  end.html_safe
29
31
  else
30
32
  hash.to_s.html_safe
@@ -17,14 +17,7 @@ module ActsAsTrashable
17
17
  has_one :trash, as: :trashed, class_name: Effective::Trash
18
18
 
19
19
  before_destroy do
20
- trash = Effective::Trash.new(
21
- trashed: self,
22
- user: EffectiveTrash.current_user,
23
- trashed_to_s: to_s,
24
- trashed_extra: (trashed_extra if respond_to?(:trashed_extra)),
25
-
26
- details: EffectiveTrash::ActiveRecordSerializer.new(self, acts_as_trashable_options).attributes
27
- ).save!
20
+ EffectiveTrash.trash!(self)
28
21
  end
29
22
 
30
23
  # Parse Options
@@ -11,14 +11,14 @@ if defined?(EffectiveDatatables)
11
11
  table_column :id, visible: false
12
12
 
13
13
  unless attributes[:user_id] || attributes[:user] || (attributes[:user] == false)
14
- table_column :user, label: 'Destroyed by', visible: false
14
+ table_column :user, label: 'Destroyed by'
15
15
  end
16
16
 
17
17
  table_column :trashed_type, label: 'Type'
18
18
  table_column :trashed_id, label: 'Original Id', visible: false
19
19
  table_column :trashed_to_s, label: 'Item'
20
20
 
21
- table_column :details, visible: true, sortable: false do |trash|
21
+ table_column :details, visible: false, sortable: false do |trash|
22
22
  tableize_hash(trash.details, th: true, sub_th: false, width: '100%')
23
23
  end
24
24
 
@@ -19,7 +19,7 @@ module Effective
19
19
  default_scope -> { order(updated_at: :desc) }
20
20
 
21
21
  def to_s
22
- [trashed_type, trashed_id].join(' ').presence || 'New Trash item'
22
+ trashed_to_s.presence || [trashed_type, trashed_id].join(' ').presence || 'New Trash item'
23
23
  end
24
24
 
25
25
  def details
@@ -28,9 +28,24 @@ module Effective
28
28
 
29
29
  # So this is a Trash item
30
30
  # When we delete ourselves, we restore this trash item first
31
- def restore_trash!
31
+ def restore!
32
32
  raise 'no attributes to restore from' unless details.kind_of?(Hash) && details[:attributes].present?
33
- trashed_type.constantize.new(details[:attributes]).save!
33
+
34
+ resource = Effective::Resource.new(trashed_type)
35
+ object = trashed_type.constantize.new(details[:attributes])
36
+
37
+ resource.nested_resources.each do |association|
38
+ if details[association.name].present? && object.respond_to?("#{association.name}_attributes=")
39
+ nested_attributes = details[association.name].inject({}) do |h, (index, nested)|
40
+ h[index] = nested[:attributes].except('id', association.inverse_of.foreign_key); h
41
+ end
42
+
43
+ object.send("#{association.name}_attributes=", nested_attributes)
44
+ end
45
+ end
46
+
47
+ object.save!(validate: false)
48
+ destroy!
34
49
  end
35
50
 
36
51
  end
@@ -0,0 +1,28 @@
1
+ class TrashArchivedBooleans < ActiveRecord::Migration[4.2]
2
+ def self.up
3
+ Rails.application.eager_load!
4
+ klasses = ActiveRecord::Base.descendants
5
+ .reject { |klass| klass.abstract_class? }
6
+ .select { |klass| (klass.new.respond_to?(:archived?) rescue false) }
7
+
8
+ klasses.each do |klass|
9
+ puts "Trashing #{klass.table_name}"
10
+
11
+ ids = [] # to delete
12
+
13
+ klass.unscoped.where(archived: true).find_each do |resource|
14
+ print '.'
15
+ EffectiveTrash.trash!(resource)
16
+ ids << resource.id
17
+ end
18
+
19
+ klass.where(id: ids).delete_all
20
+ end
21
+
22
+ klasses.each { |klass| remove_column(klass.table_name, :archived) }
23
+ end
24
+
25
+ def self.down
26
+ raise 'TODO: this could be written'
27
+ end
28
+ end
@@ -1,3 +1,3 @@
1
1
  module EffectiveTrash
2
- VERSION = '0.2.1'.freeze
2
+ VERSION = '0.2.2'.freeze
3
3
  end
@@ -1,4 +1,5 @@
1
1
  require 'haml-rails'
2
+ require 'effective_resources'
2
3
  require 'effective_trash/engine'
3
4
  require 'effective_trash/version'
4
5
 
@@ -31,4 +32,16 @@ module EffectiveTrash
31
32
  @effective_trash_current_user
32
33
  end
33
34
 
35
+ # Trash it - Does not delete the original object.
36
+ # This is run in a before_destroy, or through a script.
37
+ def self.trash!(obj)
38
+ trash = Effective::Trash.new(
39
+ trashed: obj,
40
+ user: EffectiveTrash.current_user,
41
+ trashed_to_s: obj.to_s,
42
+ trashed_extra: (trashed_extra if obj.respond_to?(:trashed_extra)),
43
+ details: Effective::Resource.new(obj).instance_attributes
44
+ ).save!
45
+ end
46
+
34
47
  end
@@ -0,0 +1,25 @@
1
+ # bundle exec rails generate effective_trash:trash_archived_booleans
2
+
3
+ module EffectiveTrash
4
+ module Generators
5
+ class TrashArchivedBooleansGenerator < Rails::Generators::Base
6
+ include Rails::Generators::Migration
7
+
8
+ desc 'Upgrade all tables from boolean archived implementation. Trash all previously archived records'
9
+
10
+ source_root File.expand_path('../../template', __FILE__)
11
+
12
+ def self.next_migration_number(dirname)
13
+ if not ActiveRecord::Base.timestamped_migrations
14
+ Time.new.utc.strftime('%Y%m%d%H%M%S')
15
+ else
16
+ '%.3d' % (current_migration_number(dirname) + 1)
17
+ end
18
+ end
19
+
20
+ def create_migration_file
21
+ migration_template ('../' * 3) + 'db/trash/trash_archived_booleans.rb', 'db/migrate/trash_archived_booleans.rb'
22
+ end
23
+ end
24
+ end
25
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: effective_trash
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.2.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Code and Effect
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-01-09 00:00:00.000000000 Z
11
+ date: 2017-02-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -38,6 +38,20 @@ dependencies:
38
38
  - - ">="
39
39
  - !ruby/object:Gem::Version
40
40
  version: 2.0.0
41
+ - !ruby/object:Gem::Dependency
42
+ name: effective_resources
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
41
55
  - !ruby/object:Gem::Dependency
42
56
  name: coffee-rails
43
57
  requirement: !ruby/object:Gem::Requirement
@@ -105,12 +119,13 @@ files:
105
119
  - config/effective_trash.rb
106
120
  - config/routes.rb
107
121
  - db/migrate/01_create_effective_trash.rb.erb
122
+ - db/trash/trash_archived_booleans.rb
108
123
  - lib/effective_trash.rb
109
- - lib/effective_trash/active_record_serializer.rb
110
124
  - lib/effective_trash/engine.rb
111
125
  - lib/effective_trash/set_current_user.rb
112
126
  - lib/effective_trash/version.rb
113
127
  - lib/generators/effective_trash/install_generator.rb
128
+ - lib/generators/effective_trash/trash_archived_booleans_generator.rb
114
129
  homepage: https://github.com/code-and-effect/effective_trash
115
130
  licenses:
116
131
  - MIT
@@ -1,61 +0,0 @@
1
- module EffectiveTrash
2
- class ActiveRecordSerializer
3
- attr_accessor :resource, :options
4
-
5
- def initialize(resource, options = {})
6
- raise ArgumentError.new('options must be a Hash') unless options.kind_of?(Hash)
7
-
8
- @resource = resource
9
- @options = options
10
- end
11
-
12
- def attributes
13
- attributes = { attributes: resource.attributes }
14
-
15
- # Collect to_s representations of all belongs_to associations
16
- (resource.class.try(:reflect_on_all_associations, :belongs_to) || []).each do |association|
17
- attributes[association.name] = resource.send(association.name).to_s.presence
18
- end
19
-
20
- # Collect to_s representations for all has_one associations
21
- (resource.class.try(:reflect_on_all_associations, :has_one) || []).each do |association|
22
- next if association.name == :trash && resource.respond_to?(:acts_as_trashable_options) # We skip our own association
23
- attributes[association.name] = resource.send(association.name).to_s.presence
24
- end
25
-
26
- # Collects attributes for all accepts_as_nested_parameters has_many associations
27
- (resource.class.try(:reflect_on_all_autosave_associations) || []).each do |association|
28
- attributes[association.name] = {}
29
-
30
- Array(resource.send(association.name)).each_with_index do |child, index|
31
- attributes[association.name][index+1] = ActiveRecordLogger.new(child, options).attributes
32
- end
33
- end
34
-
35
- attributes.delete_if { |k, v| v.blank? }
36
- end
37
-
38
- private
39
-
40
- # TODO: Make this work better with nested objects
41
- def applicable(attributes)
42
- atts = if options[:only].present?
43
- attributes.slice(*options[:only])
44
- elsif options[:except].present?
45
- attributes.except(*options[:except])
46
- else
47
- attributes.except(:updated_at, :created_at)
48
- end
49
-
50
- (options[:additionally] || []).each do |attribute|
51
- value = (resource.send(attribute) rescue :effective_trash_nope)
52
- next if attributes[attribute].present? || value == :effective_trash_nope
53
-
54
- atts[attribute] = value
55
- end
56
-
57
- atts
58
- end
59
-
60
- end
61
- end