deleted_at 0.5.0 → 0.6.0.pre.1
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 +5 -5
- data/CHANGELOG.md +57 -0
- data/README.md +41 -15
- data/lib/deleted_at.rb +4 -4
- data/lib/deleted_at/active_record.rb +28 -10
- data/lib/deleted_at/core.rb +6 -1
- data/lib/deleted_at/relation.rb +22 -36
- data/lib/deleted_at/version.rb +1 -1
- metadata +7 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 5f702112df5aaab3c584dd6cf56a7f106aee39a41e1474d9e676ba0e960b72ab
|
4
|
+
data.tar.gz: 423ac85c6209fe354ead11a2b4b758ddebc5ec151251303cae885e4f72c69075
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 260846b1749da3892ebc80a52b31d00a2a4f3738613bacfda250cd35582925c6795b76be40bdaafa5c5ac52b326e8da7a66af5ab64431ad26128d299735e1436
|
7
|
+
data.tar.gz: 49f6e710ac42079d03e88e993ebf2178c59a4faa189451255e962077c7dfbdaa23146e0028ca327edb0eafc8574296f56b06a27f00fc7e66bb22c397fd200d0f
|
data/CHANGELOG.md
CHANGED
@@ -0,0 +1,57 @@
|
|
1
|
+
# DeletedAt
|
2
|
+
|
3
|
+
## 0.6.0 _(September 4, 2018)_
|
4
|
+
- Added support for Rails 5.2
|
5
|
+
- Overhauled injection process for cleaner and more reliable sub-selecting
|
6
|
+
|
7
|
+
## 0.5.0 _(June 25, 2018)_
|
8
|
+
- Removed use of invasive views in preference of sub-selects
|
9
|
+
- Dropped support for Ruby 2.0, 2.1, 2.2
|
10
|
+
- Dropped support for Rails 4.1
|
11
|
+
- Default `deleted_at` options using `Proc`
|
12
|
+
|
13
|
+
## 0.4.0 _(Never Released)_
|
14
|
+
- Specs for Rails 4.0-5.1
|
15
|
+
- Uses `combustion` gem for cleaner and more comprehensive testing
|
16
|
+
- Added badges to ReadMe
|
17
|
+
- Using `:prepend` to leverage ancestry chain
|
18
|
+
- Add logger for internal use
|
19
|
+
- DRYd up init code
|
20
|
+
- Removed partially supported features
|
21
|
+
- Added DSL in migrations/schema for adding `deleted_at` timestamps to tables
|
22
|
+
|
23
|
+
## 0.3.0 _(May 10, 2017)_
|
24
|
+
- Add specs
|
25
|
+
- Clean up dependencies
|
26
|
+
- Auto-init models after installing views
|
27
|
+
- Remove chained `create` methods
|
28
|
+
|
29
|
+
## 0.2.6 _(April 06, 2017)_
|
30
|
+
- Add warning when no DB connection present
|
31
|
+
|
32
|
+
## 0.2.5 _(March 28, 2017)_
|
33
|
+
- Extract injections to `.load` method
|
34
|
+
|
35
|
+
## 0.2.4 _(February 03, 2017)_
|
36
|
+
- Use `becomes` to mask `::All` etc classes
|
37
|
+
|
38
|
+
## 0.2.3 _(February 03, 2017)_
|
39
|
+
- Chain `create!` method to work properly
|
40
|
+
|
41
|
+
## 0.2.2 _(February 03, 2017)_
|
42
|
+
- Chain `create` method to work properly
|
43
|
+
|
44
|
+
## 0.2.1 _(February 03, 2017)_
|
45
|
+
- More reliable table name handling
|
46
|
+
- Changed API for installing views (e.g. `destroy_deleted_view`, `uninstall_deleted_view`)
|
47
|
+
|
48
|
+
## 0.1.1 _(January 31, 2017)_
|
49
|
+
- Added instructions to readme
|
50
|
+
- Fixes stack-too-deep edge-case (by moving to `:include` over `:prepend`)
|
51
|
+
|
52
|
+
## 0.1.0 _(January 30, 2017)_
|
53
|
+
- Renames primary table to `model_name/all`
|
54
|
+
- Creates views for each model using `deleted_at`
|
55
|
+
- `model_name/deleted`
|
56
|
+
- `model_name/present`
|
57
|
+
- Classes created to read from views (`::All`, `::Present`, `::Deleted`)
|
data/README.md
CHANGED
@@ -1,12 +1,13 @@
|
|
1
|
-
[]()
|
2
|
+
[](https://rubygems.org/gems/deleted_at)
|
3
|
+
[](https://travis-ci.org/TwilightCoders/deleted_at)
|
4
|
+
[](https://codeclimate.com/github/TwilightCoders/deleted_at/maintainability)
|
5
|
+
[](https://codeclimate.com/github/TwilightCoders/deleted_at/coverage)
|
6
|
+
[](https://depfu.com/github/TwilightCoders/deleted_at)
|
6
7
|
|
7
8
|
# DeletedAt
|
8
9
|
|
9
|
-
Hide your "deleted" data (unless specifically asked for) without resorting to `default_scope` by leveraging in-line sub-selects. (See the [Upgrading](#upgrading) section)
|
10
|
+
Hide your "deleted" data (unless specifically asked for) [without resorting to](https://stackoverflow.com/a/25087337/1454158) `default_scope` by leveraging in-line sub-selects. (See the [Upgrading](#upgrading) section)
|
10
11
|
|
11
12
|
## Requirements
|
12
13
|
|
@@ -46,14 +47,10 @@ To work properly, the tables that back these models must have a `deleted_at` tim
|
|
46
47
|
```ruby
|
47
48
|
class AddDeletedAtColumnToUsers < ActiveRecord::Migration
|
48
49
|
|
49
|
-
def
|
50
|
+
def change
|
50
51
|
add_column :users, :deleted_at, 'timestamp with time zone'
|
51
52
|
end
|
52
53
|
|
53
|
-
def down
|
54
|
-
remove_column :users, :deleted_at, 'timestamp with time zone'
|
55
|
-
end
|
56
|
-
|
57
54
|
end
|
58
55
|
```
|
59
56
|
|
@@ -62,7 +59,7 @@ If you're starting with a brand-new table, the existing `timestamps` DSL has bee
|
|
62
59
|
```ruby
|
63
60
|
class CreatCommentsTable < ActiveRecord::Migration
|
64
61
|
|
65
|
-
def
|
62
|
+
def change
|
66
63
|
create_table :comments do |t|
|
67
64
|
# ...
|
68
65
|
# to the `timestamps` DSL
|
@@ -70,19 +67,48 @@ class CreatCommentsTable < ActiveRecord::Migration
|
|
70
67
|
end
|
71
68
|
end
|
72
69
|
|
73
|
-
|
74
|
-
|
70
|
+
end
|
71
|
+
```
|
72
|
+
|
73
|
+
## Performance
|
74
|
+
|
75
|
+
It's recommended (if your database engine supports it) to add partial indexes to the `deleted_at` columns. Remember that indexes work best when they represent a minority of the rows. It's up to you to determine the best index for your table.
|
76
|
+
|
77
|
+
Example 1:
|
78
|
+
|
79
|
+
You have a thriving business and your customers love your product and _rarely_ delete their account. You're likely to have way fewer rows `WHERE deleted_at IS NOT NULL`.
|
80
|
+
|
81
|
+
```ruby
|
82
|
+
class IndexDeletedAtColumns < ActiveRecord::Migration
|
83
|
+
|
84
|
+
def change
|
85
|
+
add_index :users, :deleted_at, where: "deleted_at IS NOT NULL"
|
75
86
|
end
|
76
87
|
|
77
88
|
end
|
78
89
|
```
|
79
90
|
|
91
|
+
Example 2:
|
92
|
+
|
93
|
+
You use expiring OAuth2 tokens as part of your application's authentication process. As time grows without bound rows `WHERE deleted_at IS NULL` will pale in comparison.
|
94
|
+
|
95
|
+
```ruby
|
96
|
+
class IndexDeletedAtColumns < ActiveRecord::Migration
|
97
|
+
|
98
|
+
def change
|
99
|
+
add_index :oauth_tokens, :deleted_at, where: "deleted_at IS NULL"
|
100
|
+
end
|
101
|
+
|
102
|
+
end
|
103
|
+
```
|
104
|
+
|
105
|
+
|
80
106
|
## [Upgrading](#upgrading)
|
81
107
|
|
82
108
|
If you've used `deleted_at` prior to v0.5.0, you'll need to migrate your schema. The new version of `deleted_at` no longer uses views, instead constructing a subselect on the relations. This significantly reduces code polution and monkey patching, as well as reducing the runtime memory usage for rails. Your Database will look (and be) a lot cleaner with no `deleted_at` views and your ERDs will be much cleaner as well.
|
83
109
|
|
84
110
|
Here is an example of a migration for upgrading
|
85
|
-
```
|
111
|
+
```ruby
|
86
112
|
require 'deleted_at/legacy'
|
87
113
|
|
88
114
|
DeletedAt.disable
|
data/lib/deleted_at.rb
CHANGED
@@ -41,10 +41,10 @@ module DeletedAt
|
|
41
41
|
end
|
42
42
|
|
43
43
|
def self.install(model)
|
44
|
-
logger.warn
|
45
|
-
|
46
|
-
|
47
|
-
|
44
|
+
logger.warn <<~STR
|
45
|
+
Great news! You're using the new and improved version of DeletedAt. No more table renaming.
|
46
|
+
You'll want to migrate your old models to use the new (non-view based) functionality.
|
47
|
+
Follow the instructions at #{gemspec.homepage}.
|
48
48
|
STR
|
49
49
|
end
|
50
50
|
|
@@ -5,31 +5,49 @@ module DeletedAt
|
|
5
5
|
module ActiveRecord
|
6
6
|
|
7
7
|
def self.prepended(subclass)
|
8
|
-
subclass.
|
9
|
-
subclass.const_get(:ActiveRecord_AssociationRelation).prepend(DeletedAt::Relation)
|
8
|
+
subclass.init_deleted_at_relations
|
10
9
|
subclass.extend(ClassMethods)
|
11
10
|
end
|
12
11
|
|
12
|
+
def initialize(*args)
|
13
|
+
super
|
14
|
+
@destroyed = !deleted_at.nil?
|
15
|
+
end
|
16
|
+
|
17
|
+
def destroy
|
18
|
+
soft_delete
|
19
|
+
super
|
20
|
+
end
|
21
|
+
|
22
|
+
def delete
|
23
|
+
soft_delete
|
24
|
+
super
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def soft_delete
|
30
|
+
update_columns(self.class.deleted_at_attributes)
|
31
|
+
@destroyed = true
|
32
|
+
end
|
33
|
+
|
13
34
|
module ClassMethods
|
14
35
|
|
15
36
|
def inherited(subclass)
|
16
37
|
super
|
17
|
-
subclass.
|
18
|
-
end
|
19
|
-
|
20
|
-
def all
|
21
|
-
const_get(:Present)
|
38
|
+
subclass.init_deleted_at_relations
|
22
39
|
end
|
23
40
|
|
24
41
|
def const_missing(const)
|
25
42
|
case const
|
26
|
-
when :All, :Deleted
|
27
|
-
|
28
|
-
|
43
|
+
when :All, :Deleted
|
44
|
+
all.tap do |_query|
|
45
|
+
_query.deleted_at_scope = const
|
29
46
|
end
|
30
47
|
else super
|
31
48
|
end
|
32
49
|
end
|
50
|
+
|
33
51
|
end
|
34
52
|
|
35
53
|
end
|
data/lib/deleted_at/core.rb
CHANGED
@@ -8,7 +8,6 @@ module DeletedAt
|
|
8
8
|
class << subclass
|
9
9
|
cattr_accessor :deleted_at
|
10
10
|
self.deleted_at = {}
|
11
|
-
alias all_without_deleted_at all
|
12
11
|
end
|
13
12
|
|
14
13
|
subclass.extend(ClassMethods)
|
@@ -43,6 +42,12 @@ module DeletedAt
|
|
43
42
|
}
|
44
43
|
end
|
45
44
|
|
45
|
+
def init_deleted_at_relations
|
46
|
+
instance_variable_get(:@relation_delegate_cache).each do |base, klass|
|
47
|
+
klass.send(:prepend, DeletedAt::Relation)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
46
51
|
end # End ClassMethods
|
47
52
|
|
48
53
|
end
|
data/lib/deleted_at/relation.rb
CHANGED
@@ -1,5 +1,4 @@
|
|
1
1
|
module DeletedAt
|
2
|
-
|
3
2
|
module Relation
|
4
3
|
|
5
4
|
def self.prepended(subclass)
|
@@ -15,58 +14,45 @@ module DeletedAt
|
|
15
14
|
def deleted_at_select
|
16
15
|
scoped_arel = case deleted_at_scope
|
17
16
|
when :Deleted
|
18
|
-
|
17
|
+
vanilla.dup.where(table[klass.deleted_at[:column]].not_eq(nil))
|
19
18
|
when :Present
|
20
|
-
|
19
|
+
vanilla.dup.where(table[klass.deleted_at[:column]].eq(nil))
|
21
20
|
end
|
22
21
|
end
|
23
22
|
|
23
|
+
def vanilla
|
24
|
+
# @vanilla ||= klass.const_get(:All).unscope(:where).freeze
|
25
|
+
@vanilla ||= klass.unscoped.tap do |rel|
|
26
|
+
rel.deleted_at_scope = :All
|
27
|
+
end.freeze
|
28
|
+
end
|
24
29
|
|
25
|
-
|
30
|
+
# Rails 4.x
|
31
|
+
def from_value
|
26
32
|
if (subselect = deleted_at_select)
|
27
|
-
subselect
|
28
|
-
|
33
|
+
[subselect, table_name]
|
34
|
+
else
|
35
|
+
super
|
29
36
|
end
|
30
37
|
end
|
31
38
|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
39
|
+
# Rails 5.x
|
40
|
+
def from_clause
|
41
|
+
if (subselect = deleted_at_select)
|
42
|
+
::ActiveRecord::Relation::FromClause.new(subselect, table_name)
|
43
|
+
else
|
44
|
+
super
|
38
45
|
end
|
39
46
|
end
|
40
47
|
|
41
|
-
# Deletes the records matching +conditions+ without instantiating the records
|
42
|
-
# first, and hence not calling the +destroy+ method nor invoking callbacks. This
|
43
|
-
# is a single SQL DELETE statement that goes straight to the database, much more
|
44
|
-
# efficient than +destroy_all+. Be careful with relations though, in particular
|
45
|
-
# <tt>:dependent</tt> rules defined on associations are not honored. Returns the
|
46
|
-
# number of rows affected.
|
47
|
-
#
|
48
|
-
# Post.delete_all("person_id = 5 AND (category = 'Something' OR category = 'Else')")
|
49
|
-
# Post.delete_all(["person_id = ? AND (category = ? OR category = ?)", 5, 'Something', 'Else'])
|
50
|
-
# Post.where(person_id: 5).where(category: ['Something', 'Else']).delete_all
|
51
|
-
#
|
52
|
-
# Both calls delete the affected posts all at once with a single DELETE statement.
|
53
|
-
# If you need to destroy dependent associations or call your <tt>before_*</tt> or
|
54
|
-
# +after_destroy+ callbacks, use the +destroy_all+ method instead.
|
55
|
-
#
|
56
|
-
# If an invalid method is supplied, +delete_all+ raises an ActiveRecord error:
|
57
|
-
#
|
58
|
-
# Post.limit(100).delete_all
|
59
|
-
# # => ActiveRecord::ActiveRecordError: delete_all doesn't support limit
|
60
48
|
def delete_all(*args)
|
61
|
-
|
62
|
-
|
63
|
-
ActiveSupport::Deprecation.warn(<<-MESSAGE.squish)
|
49
|
+
if args.pop
|
50
|
+
ActiveSupport::Deprecation.warn(<<~STR)
|
64
51
|
Passing conditions to delete_all is not supported in DeletedAt
|
65
52
|
To achieve the same use where(conditions).delete_all.
|
66
|
-
|
53
|
+
STR
|
67
54
|
end
|
68
55
|
update_all(klass.deleted_at_attributes)
|
69
56
|
end
|
70
57
|
end
|
71
|
-
|
72
58
|
end
|
data/lib/deleted_at/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: deleted_at
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.6.0.pre.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Dale Stevens
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-
|
11
|
+
date: 2018-09-04 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
@@ -16,7 +16,7 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '4.
|
19
|
+
version: '4.2'
|
20
20
|
- - "<"
|
21
21
|
- !ruby/object:Gem::Version
|
22
22
|
version: '6'
|
@@ -26,7 +26,7 @@ dependencies:
|
|
26
26
|
requirements:
|
27
27
|
- - ">="
|
28
28
|
- !ruby/object:Gem::Version
|
29
|
-
version: '4.
|
29
|
+
version: '4.2'
|
30
30
|
- - "<"
|
31
31
|
- !ruby/object:Gem::Version
|
32
32
|
version: '6'
|
@@ -136,12 +136,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
136
136
|
version: '2.3'
|
137
137
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
138
138
|
requirements:
|
139
|
-
- - "
|
139
|
+
- - ">"
|
140
140
|
- !ruby/object:Gem::Version
|
141
|
-
version:
|
141
|
+
version: 1.3.1
|
142
142
|
requirements: []
|
143
143
|
rubyforge_project:
|
144
|
-
rubygems_version: 2.
|
144
|
+
rubygems_version: 2.7.6
|
145
145
|
signing_key:
|
146
146
|
specification_version: 4
|
147
147
|
summary: Soft delete your data, but keep it clean.
|