deleted_at 0.3.0 → 0.4.0rc1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 8a972a99558a55757fd3a8246f87b5ac0bc94308
4
- data.tar.gz: 82771e5aea1cb90ec9d97bc1c7855c17f34d755e
2
+ SHA256:
3
+ metadata.gz: c164168eb496804835ab5f48676d72a12fb549dccb649b0249355403db9b5b7e
4
+ data.tar.gz: 6e684b4ef6a4146f40b6a0684b5aa18df975894df8da62ec62907d34bece3ec9
5
5
  SHA512:
6
- metadata.gz: 929ab80f479d1a37400d45232c357474038e2ffb0d55599c761ecee6f327104695bd00ae47bd93ddb41c41104d99a5de5384069900a57b8c7e7b311b60047f22
7
- data.tar.gz: f7f73d1d179a03e468cd458bf3404b7e1c2b1116ac9e12ed4183725035d00696d0739457bee0fb865072b5cc18c5a3e7439928e016892b697612def031a31598
6
+ metadata.gz: f16daa013ef9ba2c06a42dea4ed2cd1d3e4008d419daa987aa01224408c1a11dd2d38ad93c5685119acfc28b46db4de240ff66ab93a629a7feec2dc632ddf905
7
+ data.tar.gz: 916c6f5c3e8cf4ebabcb628b23e4015fb16f3c83eb57ef5c393bdfafdb16973149dbedafcf3cfba593bd68f7da6f6dd39200c527ce3c9555fec88d303081bcd2
data/.gitignore CHANGED
@@ -1,16 +1,78 @@
1
- /.bundle/
2
- /.yardoc
3
- /Gemfile.lock
4
- /_yardoc/
5
- /coverage/
6
- /doc/
7
- /pkg/
8
- /spec/reports/
9
- /tmp/
10
- *.bundle
11
- *.so
1
+ # See http://help.github.com/ignore-files/ for more about ignoring files.
2
+ #
3
+ # If you find yourself ignoring temporary files generated by your text editor
4
+ # or operating system, you probably want to add a global ignore instead:
5
+ # git config --global core.excludesfile ~/.gitignore_global
6
+
7
+ # Database config and secrets
8
+ /config/database.yml
9
+ /config/secrets.yml
10
+
11
+ # Ignore bundler config
12
+ /.bundle
13
+
14
+ # Ignore client credentials
15
+ /config/client_api_credentials.yml
16
+
17
+ # Ignore the default SQLite database.
18
+ /db/*.sqlite3
19
+
20
+ # Ignore all logfiles and tempfiles.
21
+ /log/*.log
22
+ /tmp
23
+ /db/structure.sql
24
+ /doc/app/*
25
+ /vendor/cldr/*
26
+ /public/uploads/*
27
+ /public/photo/*
28
+ /public/test/*
29
+ /test/assets/*
30
+ /spec/assets/*
31
+ /public/assets/**
32
+ .powenv
33
+ .rvmrc
34
+ .env
35
+ .ruby-version
36
+
37
+ # Compiled source #
38
+ ###################
39
+ /build/
40
+ *.com
41
+ *.class
42
+ *.dll
43
+ *.exe
12
44
  *.o
13
- *.a
14
- *.DS_Store
15
- .editorconfig
16
- mkmf.log
45
+ *.so
46
+
47
+ # Packages #
48
+ ############
49
+ # it's better to unpack these files and commit the raw source
50
+ # git has its own built in compression methods
51
+ *.7z
52
+ *.dmg
53
+ *.gz
54
+ *.iso
55
+ *.jar
56
+ *.rar
57
+ *.tar
58
+ *.zip
59
+
60
+ # Logs and databases #
61
+ ######################
62
+ *.log
63
+ *.sql
64
+ *.sqlite
65
+
66
+ # OS generated files #
67
+ ######################
68
+ .DS_Store
69
+ .DS_Store?
70
+ ._*
71
+ .Spotlight-V100
72
+ .Trashes
73
+ Icon?
74
+ ehthumbs.db
75
+ Thumbs.db
76
+ /Gemfile.lock
77
+ /coverage
78
+ /.editorconfig
@@ -1,19 +1,43 @@
1
1
  language: ruby
2
2
  sudo: false
3
- rvm:
4
- - 2.0
5
- - 2.1
6
- - 2.2
7
- - 2.3.1
8
- - 2.4.0
3
+
9
4
  cache: bundler
10
5
  script:
11
6
  - bundle exec rspec
12
- services:
13
- - postgresql
7
+
8
+ after_success:
9
+ - bundle exec codeclimate-test-reporter
10
+
14
11
  addons:
15
- postgresql: "9.1"
12
+ postgresql: "9.3"
13
+
14
+ rvm:
15
+ - 2.4
16
+ - 2.3
17
+ - 2.2
18
+ - 2.1
19
+ - 2.0
20
+
21
+ gemfile:
22
+ - gemfiles/activerecord-5.1.Gemfile
23
+ - gemfiles/activerecord-5.0.Gemfile
24
+ - gemfiles/activerecord-4.2.Gemfile
25
+ - gemfiles/activerecord-4.1.Gemfile
26
+ - gemfiles/activerecord-4.0.Gemfile
27
+
28
+ matrix:
29
+ exclude:
30
+ - rvm: 2.0
31
+ gemfile: gemfiles/activerecord-5.0.Gemfile
32
+ - rvm: 2.0
33
+ gemfile: gemfiles/activerecord-5.1.Gemfile
34
+
35
+ - rvm: 2.1
36
+ gemfile: gemfiles/activerecord-5.0.Gemfile
37
+ - rvm: 2.1
38
+ gemfile: gemfiles/activerecord-5.1.Gemfile
16
39
 
17
- env:
18
- - RSPEC_VERSION="<2.99"
19
- - RSPEC_VERSION="~>3.0
40
+ - rvm: 2.4
41
+ gemfile: gemfiles/activerecord-4.0.Gemfile
42
+ - rvm: 2.4
43
+ gemfile: gemfiles/activerecord-4.1.Gemfile
data/Gemfile CHANGED
@@ -1,4 +1,19 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
- # Specify your gem's dependencies in deleted_at.gemspec
4
3
  gemspec
4
+
5
+ group :test do
6
+
7
+ # Generates coverage stats of specs
8
+ gem 'simplecov'
9
+
10
+ # Publishes coverage to codeclimate
11
+ gem 'codeclimate-test-reporter'
12
+
13
+ gem 'rspec'
14
+
15
+ gem 'database_cleaner'
16
+
17
+ gem 'combustion'
18
+
19
+ end
data/README.md CHANGED
@@ -1,4 +1,9 @@
1
- # DeletedAt [![Build Status](https://travis-ci.org/TwilightCoders/deleted_at.svg?branch=master)](https://travis-ci.org/TwilightCoders/deleted_at) [![Code Climate](https://codeclimate.com/github/TwilightCoders/deleted_at/badges/gpa.svg)](https://codeclimate.com/github/TwilightCoders/deleted_at) [![Test Coverage](https://codeclimate.com/github/TwilightCoders/deleted_at/badges/coverage.svg)](https://codeclimate.com/github/TwilightCoders/deleted_at/coverage)
1
+ [![Version ](https://img.shields.io/gem/v/deleted_at.svg?maxAge=2592000)](https://rubygems.org/gems/deleted_at)
2
+ [![Build Status ](https://travis-ci.org/TwilightCoders/deleted_at.svg)](https://travis-ci.org/TwilightCoders/deleted_at)
3
+ [![Code Climate ](https://api.codeclimate.com/v1/badges/762cdcd63990efa768b0/maintainability)](https://codeclimate.com/github/TwilightCoders/deleted_at)
4
+ [![Test Coverage](https://codeclimate.com/github/TwilightCoders/deleted_at/badges/coverage.svg)](https://codeclimate.com/github/TwilightCoders/deleted_at/coverage)
5
+
6
+ # DeletedAt
2
7
 
3
8
  Deleting data is never good. A common solution is to use `default_scope`, but conventional wisdom (and for good reason) deams this a bad practice. So how do we achieve the same effect with minimal intervention. What we're looking for is the cliche "clean" solution.
4
9
 
data/Rakefile CHANGED
@@ -1,6 +1,6 @@
1
1
  require "bundler/gem_tasks"
2
- require "rspec/core/rake_task"
2
+ require 'rspec/core/rake_task'
3
3
 
4
- RSpec::Core::RakeTask.new(:spec)
4
+ RSpec::Core::RakeTask.new
5
5
 
6
- task :default => :spec
6
+ task default: :spec
@@ -22,24 +22,21 @@ Gem::Specification.new do |spec|
22
22
  raise 'RubyGems 2.0 or newer is required to protect against public gem pushes.'
23
23
  end
24
24
 
25
- spec.files = `git ls-files -z`.split("\x0").reject do |f|
26
- f.match(%r{^(test|spec|features)/})
27
- end
28
-
29
- spec.bindir = "exe"
30
- spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
31
- spec.require_paths = ["lib"]
25
+ spec.files = `git ls-files -z`.split("\x0")
26
+ spec.bindir = 'bin'
27
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
28
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
29
+ spec.require_paths = ['lib', 'spec']
32
30
 
33
- rails_versions = ['>= 4.1', '< 5']
34
- spec.required_ruby_version = '>= 2.0.0'
31
+ rails_versions = ['>= 4', '< 6']
32
+ spec.required_ruby_version = '>= 2.0'
35
33
 
36
34
  spec.add_runtime_dependency 'pg', '~> 0'
37
- spec.add_runtime_dependency "activerecord", rails_versions
38
-
39
- spec.add_development_dependency "bundler", "~> 1.3"
40
- spec.add_development_dependency "rake", "~> 10.0"
41
- spec.add_development_dependency "rspec", "~> 3.0"
42
- spec.add_development_dependency "pry", "~> 0.10"
43
- spec.add_development_dependency "simplecov", ['>= 0.9.0', '<1.0.0']
44
- spec.add_development_dependency "codeclimate-test-reporter", "~> 1.0"
35
+ spec.add_runtime_dependency 'activerecord', rails_versions
36
+
37
+ spec.add_development_dependency 'pry-byebug', '~> 3'
38
+ spec.add_development_dependency 'bundler', '~> 1.3'
39
+ spec.add_development_dependency 'rake', '~> 10.0'
40
+ spec.add_development_dependency 'combustion', '~> 0.7'
41
+
45
42
  end
@@ -0,0 +1,3 @@
1
+ eval_gemfile File.join(File.dirname(__FILE__), "../Gemfile")
2
+
3
+ gem 'activerecord', '~> 4.0.0'
@@ -0,0 +1,3 @@
1
+ eval_gemfile File.join(File.dirname(__FILE__), "../Gemfile")
2
+
3
+ gem 'activerecord', '~> 4.1.0'
@@ -0,0 +1,3 @@
1
+ eval_gemfile File.join(File.dirname(__FILE__), "../Gemfile")
2
+
3
+ gem 'activerecord', '~> 4.2.0'
@@ -0,0 +1,3 @@
1
+ eval_gemfile File.join(File.dirname(__FILE__), "../Gemfile")
2
+
3
+ gem 'activerecord', '~> 5.0.0'
@@ -0,0 +1,3 @@
1
+ eval_gemfile File.join(File.dirname(__FILE__), "../Gemfile")
2
+
3
+ gem 'activerecord', '~> 5.1.0'
@@ -2,17 +2,32 @@ require "deleted_at/version"
2
2
  require 'deleted_at/views'
3
3
  require 'deleted_at/active_record/base'
4
4
  require 'deleted_at/active_record/relation'
5
+ require 'deleted_at/active_record/connection_adapters/abstract/schema_definition'
5
6
 
6
7
  require 'deleted_at/railtie' if defined?(Rails::Railtie)
7
8
 
8
9
  module DeletedAt
9
10
 
11
+ class << self
12
+ attr_writer :logger
13
+
14
+ def logger
15
+ @logger ||= Logger.new($stdout).tap do |log|
16
+ log.progname = self.name
17
+ log.level = Logger::INFO
18
+ end
19
+ end
20
+ end
21
+
10
22
  def self.load
11
- ::ActiveRecord::Relation.send :include, DeletedAt::ActiveRecord::Relation
23
+ ::ActiveRecord::Relation.send :prepend, DeletedAt::ActiveRecord::Relation
12
24
  ::ActiveRecord::Base.send :include, DeletedAt::ActiveRecord::Base
25
+ ::ActiveRecord::ConnectionAdapters::TableDefinition.send :prepend, DeletedAt::ActiveRecord::ConnectionAdapters::TableDefinition
13
26
  end
14
27
 
15
28
  def self.install(model)
29
+ return false unless model.has_deleted_at_column?
30
+
16
31
  DeletedAt::Views.install_present_view(model)
17
32
  DeletedAt::Views.install_deleted_view(model)
18
33
 
@@ -22,11 +37,17 @@ module DeletedAt
22
37
  end
23
38
 
24
39
  def self.uninstall(model)
40
+ return false unless model.has_deleted_at_column?
41
+
25
42
  DeletedAt::Views.uninstall_deleted_view(model)
26
43
  DeletedAt::Views.uninstall_present_view(model)
27
44
 
28
45
  # We've removed the database views, now remove the class extensions
29
- model.remove_class_views
46
+ DeletedAt::ActiveRecord::Base.remove_class_views(model)
47
+ end
48
+
49
+ def self.testify(value)
50
+ value == true || value == 't' || value == 1 || value == '1'
30
51
  end
31
52
 
32
53
  private
@@ -7,125 +7,61 @@ module DeletedAt
7
7
  extend ActiveSupport::Concern
8
8
 
9
9
  included do
10
- class_attribute :deleted_at_column, :original_table_name,
11
- :deleted_by_column, :deleted_by_class, :deleted_by_primary_key
12
-
13
- class << self
14
- [:archive_with_deleted_at?, :archive_with_deleted_by?].each do |sym|
15
- define_method(sym) do
16
- false
17
- end
18
- end
19
- end
10
+ class_attribute :archive_with_deleted_at
11
+ class_attribute :deleted_at_column
20
12
 
13
+ self.archive_with_deleted_at = false
21
14
  end
22
15
 
23
16
  module ClassMethods
24
17
 
25
18
  def with_deleted_at(options={})
26
19
 
27
- return warn("No DB connection found; skipping deleted_at initialization") unless ::ActiveRecord::Base.connected?
20
+ DeletedAt::ActiveRecord::Base.parse_options(self, options)
28
21
 
29
- parse_options(options)
30
-
31
- unless ::DeletedAt::Views.all_table_exists?(self) && ::DeletedAt::Views.deleted_view_exists?(self)
32
- return warn("You're trying to use `with_deleted_at` on #{name} but you have not installed the views, yet.")
33
- end
34
-
35
- unless columns.map(&:name).include?(deleted_at_column)
36
- return warn("Missing `#{deleted_at_column}` in `#{name}` when trying to employ `deleted_at`")
37
- end
38
-
39
- [:archive_with_deleted_at?, :archive_with_deleted_by?].each do |sym|
40
- class_eval <<-BBB
41
- def self.#{sym}
42
- true
43
- end
44
- BBB
45
- end
22
+ return DeletedAt.logger.warn("You're trying to use `with_deleted_at` on #{name} but you have not installed the views, yet.") unless
23
+ has_deleted_at_views?
46
24
 
25
+ return DeletedAt.logger.warn("Missing `#{deleted_at_column}` in `#{name}` when trying to employ `deleted_at`") unless
26
+ has_deleted_at_column?
47
27
 
48
28
  # We are confident at this point that the tables and views have been setup.
49
29
  # We need to do a bit of wizardy by setting the table name to the actual table
50
30
  # (at this point: model/all), such that the model has all the information
51
- # regarding its structure and intended behavior. Calling primary_key loads the
52
- # table data into the class.
53
- self.original_table_name = self.table_name
54
- self.table_name = ::DeletedAt::Views.all_table(self)
55
- primary_key = self.primary_key
56
- self.table_name = self.original_table_name
57
-
58
- setup_class_views
59
- with_deleted_by
60
- end
31
+ # regarding its structure and intended behavior. (e.g. setting primary key)
32
+ DeletedAt::Views.while_spoofing_table_name(self, ::DeletedAt::Views.all_table(self)) do
33
+ reset_primary_key
34
+ end
61
35
 
62
- def remove_class_views
63
- self.send(:remove_const, :All) if self.const_defined?(:All)
64
- self.send(:remove_const, :Deleted) if self.const_defined?(:Deleted)
36
+ DeletedAt::ActiveRecord::Base.setup_class_views(self)
65
37
  end
66
38
 
67
- private
68
39
 
69
- def parse_options(options)
70
- self.deleted_at_column = (options.try(:[], :deleted_at).try(:[], :column) || :deleted_at).to_s
71
- self.deleted_by_column = (options.try(:[], :deleted_by).try(:[], :column) || :deleted_by).to_s
72
- self.deleted_by_class = (options.try(:[], :deleted_by).try(:[], :class) || User)
73
- self.deleted_by_primary_key = (options.try(:[], :deleted_by).try(:[], :primary_key) || deleted_by_class.try(:primary_key)).to_s
74
- end
75
40
 
76
- def deleted_by_class_is_delete_at(klass)
77
- klass && (klass.archive_with_deleted_at? || self == klass)
41
+ def has_deleted_at_column?
42
+ columns.map(&:name).include?(deleted_at_column)
78
43
  end
79
44
 
80
- def with_deleted_by
81
- return unless (deleted_by_column && columns.map(&:name).include?(deleted_by_column) && deleted_by_class < ActiveRecord::Base)
82
- self.deleted_by_class = self.deleted_by_class.const_get(:All) if deleted_by_class_is_delete_at(self.deleted_by_class)
83
-
84
- unless reflect_on_association(:destroyer)
85
- class_eval do
86
- belongs_to :destroyer, foreign_key: deleted_by_column, primary_key: deleted_by_primary_key, class_name: deleted_by_class.name
87
- end
88
- end
45
+ def has_deleted_at_views?
46
+ ::DeletedAt::Views.all_table_exists?(self) && ::DeletedAt::Views.deleted_view_exists?(self)
89
47
  end
90
48
 
91
- def refactor_validators
92
- validators.each do |validator|
93
- case validator
94
- when ActiveRecord::Validations::UniquenessValidator
49
+ def deleted_at_attributes
50
+ attributes = {
51
+ deleted_at_column => Time.now.utc
52
+ }
95
53
 
96
- end
97
- end
98
- end
99
54
 
100
- def setup_class_views
101
- self.const_set(:All, Class.new(self) do |klass|
102
- class_eval <<-AAA
103
- self.table_name = '#{::DeletedAt::Views.all_table(klass)}'
104
- AAA
105
- end)
106
-
107
- self.const_set(:Deleted, Class.new(self) do |klass|
108
- class_eval <<-AAA
109
- self.table_name = '#{::DeletedAt::Views.deleted_view(klass)}'
110
- AAA
111
- end)
55
+ attributes
112
56
  end
113
57
 
114
- end
115
-
116
- [:archive_with_deleted_at?, :archive_with_deleted_by?].each do |sym|
117
- class_eval <<-BBB
118
- def #{sym}
119
- self.class.#{sym}
120
- end
121
- BBB
122
- end
58
+ end # End ClassMethods
123
59
 
124
60
  def destroy
125
- if archive_with_deleted_at?
61
+ if self.archive_with_deleted_at?
126
62
  with_transaction_returning_status do
127
63
  run_callbacks :destroy do
128
- update_columns(deleted_at_attributes)
64
+ update_columns(self.class.deleted_at_attributes)
129
65
  self
130
66
  end
131
67
  end
@@ -134,28 +70,33 @@ module DeletedAt
134
70
  end
135
71
  end
136
72
 
137
- private
138
-
139
- def deleted_at_attributes
140
- attributes = {
141
- deleted_at_column => Time.now.utc
142
- }
143
-
144
- # attributes.merge({
145
- # deleted_by_column => DeletedAt::who_by
146
- # }) if by_who?
147
-
148
- attributes
73
+ def self.remove_class_views(model)
74
+ model.archive_with_deleted_at = false
75
+ model.send(:remove_const, :All) if model.const_defined?(:All)
76
+ model.send(:remove_const, :Deleted) if model.const_defined?(:Deleted)
149
77
  end
150
78
 
151
- def deleted_at_column
152
- self.class.deleted_at_column
79
+ def self.parse_options(model, options)
80
+ model.deleted_at_column = (options.try(:[], :deleted_at).try(:[], :column) || :deleted_at).to_s
153
81
  end
154
82
 
155
- def deleted_by_column
156
- self.class.deleted_by_column
83
+
84
+ def self.setup_class_views(model)
85
+ model.archive_with_deleted_at = true
86
+ model.const_set(:All, Class.new(model) do |klass|
87
+ class_eval <<-AAA
88
+ self.table_name = '#{::DeletedAt::Views.all_table(klass)}'
89
+ AAA
90
+ end)
91
+
92
+ model.const_set(:Deleted, Class.new(model) do |klass|
93
+ class_eval <<-AAA
94
+ self.table_name = '#{::DeletedAt::Views.deleted_view(klass)}'
95
+ AAA
96
+ end)
157
97
  end
158
98
 
159
99
  end
100
+
160
101
  end
161
102
  end