From 4db588ffac74186c2c46d282e8e904539934e302 Mon Sep 17 00:00:00 2001 From: Dale Stevens Date: Thu, 6 Sep 2018 12:15:02 -0600 Subject: [PATCH 01/12] Forward table alias name --- lib/deleted_at/relation.rb | 19 ++++++++++++++++--- spec/deleted_at/active_record_spec.rb | 9 +++++++++ 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/lib/deleted_at/relation.rb b/lib/deleted_at/relation.rb index a2f81ed..0a102dc 100644 --- a/lib/deleted_at/relation.rb +++ b/lib/deleted_at/relation.rb @@ -4,6 +4,7 @@ module Relation def self.prepended(subclass) subclass.class_eval do attr_writer :deleted_at_scope + attr_reader :table_alias_name end end @@ -27,10 +28,20 @@ def vanilla end.freeze end + def as(other) + @table_alias_name = Arel::Nodes::SqlLiteral.new(other) + super + end + + def table_name_literal + table_alias_name || ::ActiveRecord::Base.connection.quote_table_name(table_name) + end + # Rails 4.x def from_value + @table_alias_name ||= super&.first&.name if (subselect = deleted_at_select) - [subselect, ::ActiveRecord::Base.connection.quote_table_name(table_name)] + [subselect, table_name_literal] else super end @@ -38,10 +49,12 @@ def from_value # Rails 5.x def from_clause + super_from_clause = super + @table_alias_name ||= super_from_clause&.name || super_from_clause&.value&.right if (subselect = deleted_at_select) - ::ActiveRecord::Relation::FromClause.new(subselect, ::ActiveRecord::Base.connection.quote_table_name(table_name)) + ::ActiveRecord::Relation::FromClause.new(subselect, table_name_literal) else - super + super_from_clause end end diff --git a/spec/deleted_at/active_record_spec.rb b/spec/deleted_at/active_record_spec.rb index 9bb4bcf..1ec17f5 100644 --- a/spec/deleted_at/active_record_spec.rb +++ b/spec/deleted_at/active_record_spec.rb @@ -6,4 +6,13 @@ expect{ Admin::Blarg }.to raise_error(NameError) end + it 'should use the table_alias if given' do + inner_query = User.where(name: 'bob').as('bobs') + sql = User.select(inner_query[:name]).from(inner_query).to_sql + + expect(sql).to eql(<<~SQL.squish) + SELECT bobs."name" FROM (SELECT "users".* FROM "users" WHERE "users"."deleted_at" IS NULL) bobs + SQL + end + end From a5d5cd4f5cf8061e6d33ee56662e731685ee3d42 Mon Sep 17 00:00:00 2001 From: Dale Stevens Date: Thu, 6 Sep 2018 12:15:24 -0600 Subject: [PATCH 02/12] Advance version --- lib/deleted_at/version.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/deleted_at/version.rb b/lib/deleted_at/version.rb index c9fc23e..28408e3 100644 --- a/lib/deleted_at/version.rb +++ b/lib/deleted_at/version.rb @@ -1,3 +1,3 @@ module DeletedAt - VERSION = "0.5.0-2" + VERSION = "0.6.0-2" end From 8cfbb9b9eaac0519f070740c717e3ab66dccd3f0 Mon Sep 17 00:00:00 2001 From: Dale Stevens Date: Sat, 25 May 2019 08:47:25 -0400 Subject: [PATCH 03/12] Ditch unneeded assets --- spec/support/rails/log/.gitignore | 1 - spec/support/rails/public/favicon.ico | 0 2 files changed, 1 deletion(-) delete mode 100644 spec/support/rails/log/.gitignore delete mode 100644 spec/support/rails/public/favicon.ico diff --git a/spec/support/rails/log/.gitignore b/spec/support/rails/log/.gitignore deleted file mode 100644 index bf0824e..0000000 --- a/spec/support/rails/log/.gitignore +++ /dev/null @@ -1 +0,0 @@ -*.log \ No newline at end of file diff --git a/spec/support/rails/public/favicon.ico b/spec/support/rails/public/favicon.ico deleted file mode 100644 index e69de29..0000000 From 68e99cd5569181c82f06b594f6a16a6e19467cf0 Mon Sep 17 00:00:00 2001 From: Dale Stevens Date: Sat, 25 May 2019 09:11:56 -0400 Subject: [PATCH 04/12] Update dependencies and gem specifications --- .travis.yml | 12 +++++++++++- Gemfile | 13 ------------- README.md | 2 +- deleted_at.gemspec | 14 ++++++++------ gemfiles/activerecord-4.2.Gemfile | 1 + gemfiles/activerecord-edge.Gemfile | 3 +++ spec/support/rails/config/database.yml | 2 ++ 7 files changed, 26 insertions(+), 21 deletions(-) create mode 100644 gemfiles/activerecord-edge.Gemfile diff --git a/.travis.yml b/.travis.yml index af3de38..7c11b70 100644 --- a/.travis.yml +++ b/.travis.yml @@ -20,15 +20,25 @@ after_script: - ./cc-test-reporter after-build --exit-code $TRAVIS_TEST_RESULT addons: - postgresql: 9.3 + postgresql: 9.5 rvm: + - 2.6 - 2.5 - 2.4 - 2.3 gemfile: + - gemfiles/activerecord-edge.Gemfile - gemfiles/activerecord-5.2.Gemfile - gemfiles/activerecord-5.1.Gemfile - gemfiles/activerecord-5.0.Gemfile - gemfiles/activerecord-4.2.Gemfile + +matrix: + allow_failures: + - gemfile: gemfiles/activerecord-edge.Gemfile + + exclude: + - rvm: 2.6 + gemfile: gemfiles/activerecord-4.2.Gemfile diff --git a/Gemfile b/Gemfile index 61bfac7..fa75df1 100644 --- a/Gemfile +++ b/Gemfile @@ -1,16 +1,3 @@ source 'https://rubygems.org' gemspec - -group :test do - - # Generates coverage stats of specs - gem 'simplecov' - - gem 'rspec' - - gem 'database_cleaner' - - gem 'combustion' - -end diff --git a/README.md b/README.md index dd889f8..bc71b16 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ Hide your "deleted" data (unless specifically asked for) [without resorting to]( ## Requirements - Ruby 2.3+ -- ActiveRecord 4.1+ +- ActiveRecord 4.2+ ## Installation diff --git a/deleted_at.gemspec b/deleted_at.gemspec index fb629dc..4b61faa 100644 --- a/deleted_at.gemspec +++ b/deleted_at.gemspec @@ -28,11 +28,13 @@ Gem::Specification.new do |spec| spec.required_ruby_version = '>= 2.3' spec.add_runtime_dependency 'activerecord', rails_versions - - spec.add_development_dependency 'pg', '~> 0' - spec.add_development_dependency 'pry-byebug', '~> 3' - spec.add_development_dependency 'bundler', '~> 1.3' - spec.add_development_dependency 'rake', '~> 12.0' - spec.add_development_dependency 'combustion', '~> 0.7' + spec.add_development_dependency 'pg' + spec.add_development_dependency 'bundler' + spec.add_development_dependency 'rspec' + spec.add_development_dependency 'combustion' + spec.add_development_dependency 'pry-byebug' + spec.add_development_dependency 'rake' + spec.add_development_dependency 'database_cleaner' + spec.add_development_dependency 'simplecov' end diff --git a/gemfiles/activerecord-4.2.Gemfile b/gemfiles/activerecord-4.2.Gemfile index 0c94061..88c864d 100644 --- a/gemfiles/activerecord-4.2.Gemfile +++ b/gemfiles/activerecord-4.2.Gemfile @@ -1,3 +1,4 @@ eval_gemfile File.join(File.dirname(__FILE__), "../Gemfile") +gem 'pg', '~> 0.20' gem 'activerecord', '~> 4.2.0' diff --git a/gemfiles/activerecord-edge.Gemfile b/gemfiles/activerecord-edge.Gemfile new file mode 100644 index 0000000..6930d58 --- /dev/null +++ b/gemfiles/activerecord-edge.Gemfile @@ -0,0 +1,3 @@ +eval_gemfile File.join(File.dirname(__FILE__), "../Gemfile") + +gem 'activerecord', github: 'rails/rails', require: 'active_record' diff --git a/spec/support/rails/config/database.yml b/spec/support/rails/config/database.yml index 9e828b4..1442568 100644 --- a/spec/support/rails/config/database.yml +++ b/spec/support/rails/config/database.yml @@ -1,4 +1,6 @@ test: adapter: postgresql + host: localhost encoding: unicode database: deleted_at-test + prepared_statements: false From afabc52b68fe99d40e765b93b5eb37f91ea6bfa2 Mon Sep 17 00:00:00 2001 From: Dale Stevens Date: Sat, 25 May 2019 09:14:47 -0400 Subject: [PATCH 05/12] Update copyright --- LICENSE | 2 +- lib/deleted_at/relation.rb | 58 -------------------------------------- 2 files changed, 1 insertion(+), 59 deletions(-) diff --git a/LICENSE b/LICENSE index ad8b568..9e5927b 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2017 Dale Stevens +Copyright (c) 2019 Dale Stevens Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/lib/deleted_at/relation.rb b/lib/deleted_at/relation.rb index 0a102dc..5f67943 100644 --- a/lib/deleted_at/relation.rb +++ b/lib/deleted_at/relation.rb @@ -1,63 +1,5 @@ module DeletedAt module Relation - - def self.prepended(subclass) - subclass.class_eval do - attr_writer :deleted_at_scope - attr_reader :table_alias_name - end - end - - def deleted_at_scope - @deleted_at_scope ||= :Present - end - - def deleted_at_select - scoped_arel = case deleted_at_scope - when :Deleted - vanilla.dup.where(table[klass.deleted_at[:column]].not_eq(nil)) - when :Present - vanilla.dup.where(table[klass.deleted_at[:column]].eq(nil)) - end - end - - def vanilla - # @vanilla ||= klass.const_get(:All).unscope(:where).freeze - @vanilla ||= klass.unscoped.tap do |rel| - rel.deleted_at_scope = :All - end.freeze - end - - def as(other) - @table_alias_name = Arel::Nodes::SqlLiteral.new(other) - super - end - - def table_name_literal - table_alias_name || ::ActiveRecord::Base.connection.quote_table_name(table_name) - end - - # Rails 4.x - def from_value - @table_alias_name ||= super&.first&.name - if (subselect = deleted_at_select) - [subselect, table_name_literal] - else - super - end - end - - # Rails 5.x - def from_clause - super_from_clause = super - @table_alias_name ||= super_from_clause&.name || super_from_clause&.value&.right - if (subselect = deleted_at_select) - ::ActiveRecord::Relation::FromClause.new(subselect, table_name_literal) - else - super_from_clause - end - end - def delete_all(*args) if args.pop ActiveSupport::Deprecation.warn(<<~STR) From c8c8bd54adfdb90546662b563aa75d196122955d Mon Sep 17 00:00:00 2001 From: Dale Stevens Date: Sat, 25 May 2019 09:17:19 -0400 Subject: [PATCH 06/12] Replace core functionality with ActiveRecord::Frames --- README.md | 5 +- deleted_at.gemspec | 4 +- lib/deleted_at.rb | 7 ++- lib/deleted_at/active_record.rb | 57 +++++++++++------ lib/deleted_at/core.rb | 29 ++++----- lib/deleted_at/railtie.rb | 2 - lib/deleted_at/version.rb | 2 +- spec/deleted_at/active_record_spec.rb | 18 ------ spec/deleted_at/core_spec.rb | 29 ++++----- spec/deleted_at/relation_spec.rb | 84 ++++++++++++++++++-------- spec/support/rails/app/models/admin.rb | 2 + spec/support/rails/app/models/user.rb | 8 ++- spec/support/rails/db/schema.rb | 12 +--- 13 files changed, 145 insertions(+), 114 deletions(-) delete mode 100644 spec/deleted_at/active_record_spec.rb diff --git a/README.md b/README.md index bc71b16..2a610f1 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,8 @@ Hide your "deleted" data (unless specifically asked for) [without resorting to]( - Ruby 2.3+ - ActiveRecord 4.2+ +_Note: Be sure to check the builds to be sure your version is in-fact supported. The requirements are left unbounded on the upper constraint for posterity, but may not be gaurenteed to work._ + ## Installation Add this line to your application's Gemfile: @@ -102,10 +104,9 @@ class IndexDeletedAtColumns < ActiveRecord::Migration end ``` - ## [Upgrading](#upgrading) -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. +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 common table expression (CTE) 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). Here is an example of a migration for upgrading ```ruby diff --git a/deleted_at.gemspec b/deleted_at.gemspec index 4b61faa..813cc61 100644 --- a/deleted_at.gemspec +++ b/deleted_at.gemspec @@ -24,10 +24,12 @@ Gem::Specification.new do |spec| spec.test_files = spec.files.grep(%r{^(test|spec|features)/}) spec.require_paths = ['lib'] - rails_versions = ['>= 4.2', '< 6'] + rails_versions = ['>= 4.2'] spec.required_ruby_version = '>= 2.3' spec.add_runtime_dependency 'activerecord', rails_versions + spec.add_runtime_dependency 'active_record-framing', '~> 0.1.0-6' + spec.add_development_dependency 'pg' spec.add_development_dependency 'bundler' spec.add_development_dependency 'rspec' diff --git a/lib/deleted_at.rb b/lib/deleted_at.rb index 10a8818..7630be5 100644 --- a/lib/deleted_at.rb +++ b/lib/deleted_at.rb @@ -1,9 +1,14 @@ +require 'active_record/framing' + require 'deleted_at/version' +require 'deleted_at/relation' +require 'deleted_at/core' +require 'deleted_at/table_definition' require 'deleted_at/railtie' if defined?(Rails::Railtie) module DeletedAt - MissingColumn = Class.new(StandardError) + MissingColumnError = Class.new(StandardError) DEFAULT_OPTIONS = { column: :deleted_at, diff --git a/lib/deleted_at/active_record.rb b/lib/deleted_at/active_record.rb index b9367ca..cd077e4 100644 --- a/lib/deleted_at/active_record.rb +++ b/lib/deleted_at/active_record.rb @@ -1,50 +1,73 @@ -require 'active_record' -require 'deleted_at/relation' - module DeletedAt module ActiveRecord def self.prepended(subclass) - subclass.init_deleted_at_relations subclass.extend(ClassMethods) + + subclass.class_eval do + init_deleted_at_relations + default_frame { where(deleted_at[:column] => nil) } + frame :all, -> {} + frame :deleted, -> { where.not(deleted_at[:column] => nil) } + end end def initialize(*args) - super - @destroyed = !deleted_at.nil? + super.tap do + @destroyed = deleted_at_nil? + end end def destroy - soft_delete - super + run_callbacks(:destroy) do + soft_delete + end end def delete soft_delete - super + end + + def destroy! + run_callbacks(:destroy) do + soft_delete + end + end + + def delete! + soft_delete end private def soft_delete + return if destroyed? update_columns(self.class.deleted_at_attributes) @destroyed = true + freeze + self + end + + def deleted_at_nil? + !read_attribute(self.class.deleted_at[:column]).nil? end module ClassMethods def inherited(subclass) super - subclass.init_deleted_at_relations + # subclass.init_deleted_at_relations if deleted_at[:inherit] + end + + def deleted_at_attributes + attributes = { + deleted_at[:column] => deleted_at[:proc].call + } end - def const_missing(const) - case const - when :All, :Deleted - all.tap do |_query| - _query.deleted_at_scope = const - end - else super + def init_deleted_at_relations + instance_variable_get(:@relation_delegate_cache).each do |base, klass| + klass.send(:prepend, DeletedAt::Relation) end end diff --git a/lib/deleted_at/core.rb b/lib/deleted_at/core.rb index 6ec5bf2..1bd3aab 100644 --- a/lib/deleted_at/core.rb +++ b/lib/deleted_at/core.rb @@ -1,5 +1,4 @@ require 'deleted_at/active_record' - module DeletedAt module Core @@ -15,39 +14,33 @@ class << subclass def self.raise_missing(klass) message = "Missing `#{klass.deleted_at[:column]}` in `#{klass.name}` when trying to employ `deleted_at`" - raise(DeletedAt::MissingColumn, message) + raise(DeletedAt::MissingColumnError, message) end def self.has_deleted_at_column?(klass) klass.columns.map(&:name).include?(klass.deleted_at.dig(:column).to_s) end + def self.deleted_at_ready?(klass) + !::DeletedAt.disabled? && + klass != ::ActiveRecord::Base && + !klass.abstract_class? && + klass.connected? && + klass.table_exists? && + !(klass < DeletedAt::ActiveRecord) + end + module ClassMethods def with_deleted_at(options={}, &block) self.deleted_at = DeletedAt::DEFAULT_OPTIONS.merge(options) self.deleted_at[:proc] = block if block_given? - return if ::DeletedAt.disabled? - + return unless Core.deleted_at_ready?(self) DeletedAt::Core.raise_missing(self) unless Core.has_deleted_at_column?(self) self.prepend(DeletedAt::ActiveRecord) - end - - def deleted_at_attributes - attributes = { - deleted_at[:column] => deleted_at[:proc].call - } - end - - def init_deleted_at_relations - instance_variable_get(:@relation_delegate_cache).each do |base, klass| - klass.send(:prepend, DeletedAt::Relation) - end - end - end # End ClassMethods end diff --git a/lib/deleted_at/railtie.rb b/lib/deleted_at/railtie.rb index acddc96..dbfb9aa 100644 --- a/lib/deleted_at/railtie.rb +++ b/lib/deleted_at/railtie.rb @@ -1,6 +1,4 @@ require 'rails/railtie' -require 'deleted_at/core' -require 'deleted_at/table_definition' module DeletedAt class Railtie < Rails::Railtie diff --git a/lib/deleted_at/version.rb b/lib/deleted_at/version.rb index 28408e3..f061ecd 100644 --- a/lib/deleted_at/version.rb +++ b/lib/deleted_at/version.rb @@ -1,3 +1,3 @@ module DeletedAt - VERSION = "0.6.0-2" + VERSION = "0.6.0-4" end diff --git a/spec/deleted_at/active_record_spec.rb b/spec/deleted_at/active_record_spec.rb deleted file mode 100644 index 1ec17f5..0000000 --- a/spec/deleted_at/active_record_spec.rb +++ /dev/null @@ -1,18 +0,0 @@ -require "spec_helper" - -describe DeletedAt::ActiveRecord do - - it 'should let other missing consts through' do - expect{ Admin::Blarg }.to raise_error(NameError) - end - - it 'should use the table_alias if given' do - inner_query = User.where(name: 'bob').as('bobs') - sql = User.select(inner_query[:name]).from(inner_query).to_sql - - expect(sql).to eql(<<~SQL.squish) - SELECT bobs."name" FROM (SELECT "users".* FROM "users" WHERE "users"."deleted_at" IS NULL) bobs - SQL - end - -end diff --git a/spec/deleted_at/core_spec.rb b/spec/deleted_at/core_spec.rb index 4ae3e6b..c909d7d 100644 --- a/spec/deleted_at/core_spec.rb +++ b/spec/deleted_at/core_spec.rb @@ -7,7 +7,7 @@ it "raises exception when using with_deleted_at" do expected_stderr = "Missing `deleted_at` in `Comment` when trying to employ `deleted_at`" allow(Comment).to receive(:has_deleted_at_views?).and_return(true) - expect{ Comment.with_deleted_at }.to raise_exception(DeletedAt::MissingColumn) + expect{ Comment.with_deleted_at }.to raise_exception(DeletedAt::MissingColumnError) end end @@ -25,11 +25,21 @@ User.create(name: 'john') User.create(name: 'sally') - User.first.destroy + u = User.first + u.destroy expect(User::Deleted.first.class).to eq(User) end + it "doesn't obstruct destroy callbacks" do + User.create(name: 'sally') + + u = User.first + expect_any_instance_of(User).to receive(:say_something) + + u.destroy + end + it 'works with complex eager loading' do bob = User.create(name: 'bob') (1..5).each do |i| @@ -42,19 +52,4 @@ expect(User.eager_load(posts: :comments).find_by(name: 'bob')).to eq(bob) end - context 'with default_scope' do - it 'should have the default scope in the subquery' do - Admin.create(name: 'bob', kind: 1) - Admin.create(name: 'john', kind: 1) - Admin.create(name: 'sally', kind: 0) - - Admin.first.destroy - - User.first - - # SELECT "users".* FROM (SELECT "users".* FROM "users" WHERE "users"."kind" = $1 AND "users"."deleted_at" IS NULL) "users" WHERE "users"."kind" = 1 - expect(Admin::Deleted.first.class).to eq(Admin) - end - end - end diff --git a/spec/deleted_at/relation_spec.rb b/spec/deleted_at/relation_spec.rb index 1f8022d..9e1093e 100644 --- a/spec/deleted_at/relation_spec.rb +++ b/spec/deleted_at/relation_spec.rb @@ -2,6 +2,18 @@ describe DeletedAt::Core do + context 'models with dependent: :destroy' do + it 'should also destroy dependents' do + user = User.create(name: 'bob') + + 4.times do + Post.create(user: user) + end + + expect{user.destroy}.to_not raise_exception + end + end + context "models using deleted_at" do it "#destroy should set deleted_at" do @@ -16,33 +28,54 @@ expect(User::Deleted.count).to eq(1) end - it "#delete should set deleted_at" do + it "#delete! should set deleted_at" do User.create(name: 'bob') User.create(name: 'john') User.create(name: 'sally') - User.first.delete + User.first.delete! expect(User.count).to eq(2) expect(User::All.count).to eq(3) expect(User::Deleted.count).to eq(1) end - context 'associations' do + it "#destroy! should set deleted_at" do + User.create(name: 'bob') + User.create(name: 'john') + User.create(name: 'sally') - it 'should scope properly' do + User.first.destroy! - user = User.create(name: 'bob') - (1..4).each do - Post.create(user: user) - end + expect(User.count).to eq(2) + expect(User::All.count).to eq(3) + expect(User::Deleted.count).to eq(1) + end - post = user.posts.first.delete + it "#delete should set deleted_at" do + User.create(name: 'bob') + User.create(name: 'john') + User.create(name: 'sally') - expect(user.posts.count).to eq(3) + User.first.delete - end + expect(User.count).to eq(2) + expect(User::All.count).to eq(3) + expect(User::Deleted.count).to eq(1) + end + + it "#destroy twice should set deleted_at and not fail" do + User.create(name: 'bob') + User.create(name: 'john') + User.create(name: 'sally') + u = User.first + u.destroy! + u.destroy! + + expect(User.count).to eq(2) + expect(User::All.count).to eq(3) + expect(User::Deleted.count).to eq(1) end context '#destroy_all' do @@ -65,6 +98,7 @@ User.where(name: 'bob').destroy_all + expect(User.count).to eq(2) expect(User::All.count).to eq(3) expect(User::Deleted.count).to eq(1) @@ -73,28 +107,28 @@ context '#delete_all' do it "should set deleted_at" do - Animals::Dog.create(name: 'bob') - Animals::Dog.create(name: 'john') - Animals::Dog.create(name: 'sally') + User.create(name: 'bob') + User.create(name: 'john') + User.create(name: 'sally') # conditions should not matter - Animals::Dog.all.delete_all(name: 'bob') + User.all.delete_all(name: 'bob') - expect(Animals::Dog.count).to eq(0) - expect(Animals::Dog::All.count).to eq(3) - expect(Animals::Dog::Deleted.count).to eq(3) + expect(User.count).to eq(0) + expect(User::All.count).to eq(3) + expect(User::Deleted.count).to eq(3) end it "with conditions should set deleted_at" do - Animals::Dog.create(name: 'bob') - Animals::Dog.create(name: 'john') - Animals::Dog.create(name: 'sally') + User.create(name: 'bob') + User.create(name: 'john') + User.create(name: 'sally') - Animals::Dog.where(name: 'bob').delete_all + User.where(name: 'bob').delete_all - expect(Animals::Dog.count).to eq(2) - expect(Animals::Dog::All.count).to eq(3) - expect(Animals::Dog::Deleted.count).to eq(1) + expect(User.count).to eq(2) + expect(User::All.count).to eq(3) + expect(User::Deleted.count).to eq(1) end end diff --git a/spec/support/rails/app/models/admin.rb b/spec/support/rails/app/models/admin.rb index 220699c..d005da8 100644 --- a/spec/support/rails/app/models/admin.rb +++ b/spec/support/rails/app/models/admin.rb @@ -1,5 +1,7 @@ class Admin < User + with_deleted_at + default_scope { # select(arel_table[Arel.star], arel_table[:tableoid])# select(arel_table[:id], arel_table[:kind]).where(kind: 1) diff --git a/spec/support/rails/app/models/user.rb b/spec/support/rails/app/models/user.rb index a2be2e7..0738380 100644 --- a/spec/support/rails/app/models/user.rb +++ b/spec/support/rails/app/models/user.rb @@ -1,7 +1,7 @@ class User < ::ActiveRecord::Base with_deleted_at - has_many :posts + has_many :posts, dependent: :destroy has_many :comments scope :admins, -> { @@ -9,4 +9,10 @@ class User < ::ActiveRecord::Base where(kind: 1) } + after_destroy :say_something + + def say_something + # Doesn't need to do anything + end + end diff --git a/spec/support/rails/db/schema.rb b/spec/support/rails/db/schema.rb index f9f168d..c90ad5f 100644 --- a/spec/support/rails/db/schema.rb +++ b/spec/support/rails/db/schema.rb @@ -11,6 +11,7 @@ create_table :documents, force: true do |t| t.integer :user_id t.string :title + t.integer :scope t.timestamps null: false, deleted_at: true end @@ -21,15 +22,4 @@ t.timestamps null: false end - create_table 'animal/dogs', force: true do |t| - t.string :name - t.timestamps null: false, deleted_at: true - end - - create_table :cats, force: true do |t| - t.string :name - # t.string :type - t.timestamps null: false, deleted_at: true - end - end From 8d1c449084ebcffeb20089a05400e8c46f070303 Mon Sep 17 00:00:00 2001 From: Dale Stevens Date: Sat, 25 May 2019 12:33:27 -0400 Subject: [PATCH 07/12] Update readme for 0.6.0 release --- CHANGELOG.md | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6f94a63..d740e01 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,13 +1,22 @@ # DeletedAt +## 0.6.0 _(May 25, 2019)_ +- Major overhaul of functionality, extracted to [`ActiveRecord::Framing`](https://github.com/TwilightCoders/active_record-framing) and refined into gem + - Consumes `ActiveRecord::Framing` +- Simplified gem and distilled to only domain specific functionality +- Adds official support for ActiveSupport up to 5.2 +- Adds official support for Ruby 2.6 +- Unbound upper constraint for ActiveSupport +- 100% test coverage + ## 0.5.0 _(June 25, 2018)_ - Removed use of invasive views in preference of sub-selects - Dropped support for Ruby 2.0, 2.1, 2.2 -- Dropped support for Rails 4.1 +- Dropped support for ActiveSupport 4.1 - Default `deleted_at` options using `Proc` ## 0.4.0 _(Never Released)_ -- Specs for Rails 4.0-5.1 +- Specs for ActiveSupport 4.0-5.1 - Uses `combustion` gem for cleaner and more comprehensive testing - Added badges to ReadMe - Using `:prepend` to leverage ancestry chain From 2c751a9e649a52ae0833d76027912f6ffec7c23c Mon Sep 17 00:00:00 2001 From: Dale Stevens Date: Mon, 10 Jun 2019 21:18:00 -0600 Subject: [PATCH 08/12] Ditch .rspec file. Configs will go in rspec_helper.rb Developers can define a .rspec file if they wish to override anything. --- .rspec | 2 -- 1 file changed, 2 deletions(-) delete mode 100644 .rspec diff --git a/.rspec b/.rspec deleted file mode 100644 index 8c18f1a..0000000 --- a/.rspec +++ /dev/null @@ -1,2 +0,0 @@ ---format documentation ---color From 20139f6fee6595f2c667fa1429f0627965e08408 Mon Sep 17 00:00:00 2001 From: Dale Stevens Date: Mon, 10 Jun 2019 21:18:47 -0600 Subject: [PATCH 09/12] Bump to latest pre-release of AR::Framing This version allows for globally disabling frames. --- deleted_at.gemspec | 2 +- lib/deleted_at.rb | 2 +- lib/deleted_at/legacy.rb | 6 ++++-- lib/deleted_at/version.rb | 2 +- 4 files changed, 7 insertions(+), 5 deletions(-) diff --git a/deleted_at.gemspec b/deleted_at.gemspec index 813cc61..2fc5ee6 100644 --- a/deleted_at.gemspec +++ b/deleted_at.gemspec @@ -28,7 +28,7 @@ Gem::Specification.new do |spec| spec.required_ruby_version = '>= 2.3' spec.add_runtime_dependency 'activerecord', rails_versions - spec.add_runtime_dependency 'active_record-framing', '~> 0.1.0-6' + spec.add_runtime_dependency 'active_record-framing', '~> 0.1.0-10' spec.add_development_dependency 'pg' spec.add_development_dependency 'bundler' diff --git a/lib/deleted_at.rb b/lib/deleted_at.rb index 7630be5..73f720b 100644 --- a/lib/deleted_at.rb +++ b/lib/deleted_at.rb @@ -1,4 +1,4 @@ -require 'active_record/framing' +require 'active_record-framing' require 'deleted_at/version' require 'deleted_at/relation' diff --git a/lib/deleted_at/legacy.rb b/lib/deleted_at/legacy.rb index 626f6fe..b1ab2d6 100644 --- a/lib/deleted_at/legacy.rb +++ b/lib/deleted_at/legacy.rb @@ -10,8 +10,10 @@ def self.uninstall(model) def self.install(model) return false unless Core.has_deleted_at_column?(model) - install_present_view(model) - install_deleted_view(model) + model.unframed do + install_present_view(model) + install_deleted_view(model) + end end private diff --git a/lib/deleted_at/version.rb b/lib/deleted_at/version.rb index f061ecd..d2e1baa 100644 --- a/lib/deleted_at/version.rb +++ b/lib/deleted_at/version.rb @@ -1,3 +1,3 @@ module DeletedAt - VERSION = "0.6.0-4" + VERSION = "0.6.0-7" end From 6eb463edb5fa90d2a0b0b105e7187c7c64670a40 Mon Sep 17 00:00:00 2001 From: Dale Stevens Date: Wed, 12 Jun 2019 08:44:22 -0600 Subject: [PATCH 10/12] Fix bug for legacy rollback --- lib/deleted_at/legacy.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/deleted_at/legacy.rb b/lib/deleted_at/legacy.rb index b1ab2d6..8c5045c 100644 --- a/lib/deleted_at/legacy.rb +++ b/lib/deleted_at/legacy.rb @@ -26,7 +26,7 @@ def self.install_present_view(model) model.connection.execute("ALTER TABLE \"#{present_table_name}\" RENAME TO \"#{model.table_name}\"") model.connection.execute <<-SQL CREATE OR REPLACE VIEW "#{present_table_name}" - AS #{ model.select('*').where(model.deleted_at_column => nil).to_sql } + AS #{ model.select('*').where(model.deleted_at[:column] => nil).to_sql } SQL end end @@ -38,7 +38,7 @@ def self.install_deleted_view(model) while_spoofing_table_name(model, all_table(model)) do model.connection.execute <<-SQL CREATE OR REPLACE VIEW "#{table_name}" - AS #{ model.select('*').where.not(model.deleted_at_column => nil).to_sql } + AS #{ model.select('*').where.not(model.deleted_at[:column] => nil).to_sql } SQL end end From e82c12aee4b38756c0155f18bf55c6a15961ce47 Mon Sep 17 00:00:00 2001 From: Dale Stevens Date: Mon, 23 Dec 2019 18:01:10 -0700 Subject: [PATCH 11/12] Support Rails 6.0 and allow edge testing --- .travis.yml | 20 ++++++++++++++++++-- deleted_at.gemspec | 2 +- gemfiles/activerecord-6.0.Gemfile | 3 +++ 3 files changed, 22 insertions(+), 3 deletions(-) create mode 100644 gemfiles/activerecord-6.0.Gemfile diff --git a/.travis.yml b/.travis.yml index 7c11b70..38d0671 100644 --- a/.travis.yml +++ b/.travis.yml @@ -29,16 +29,32 @@ rvm: - 2.3 gemfile: - - gemfiles/activerecord-edge.Gemfile + - gemfiles/activerecord-6.0.Gemfile - gemfiles/activerecord-5.2.Gemfile - gemfiles/activerecord-5.1.Gemfile - gemfiles/activerecord-5.0.Gemfile - gemfiles/activerecord-4.2.Gemfile -matrix: +jobs: + include: + - gemfile: gemfiles/activerecord-edge.Gemfile + rvm: 2.5 + env: EDGE_TESTING=true + - gemfile: gemfiles/activerecord-edge.Gemfile + rvm: 2.6 + env: EDGE_TESTING=true + allow_failures: - gemfile: gemfiles/activerecord-edge.Gemfile exclude: - rvm: 2.6 gemfile: gemfiles/activerecord-4.2.Gemfile + - rvm: 2.3 + gemfile: gemfiles/activerecord-6.0.Gemfile + - rvm: 2.4 + gemfile: gemfiles/activerecord-6.0.Gemfile + - rvm: 2.3 + gemfile: gemfiles/activerecord-edge.Gemfile + - rvm: 2.4 + gemfile: gemfiles/activerecord-edge.Gemfile diff --git a/deleted_at.gemspec b/deleted_at.gemspec index 2fc5ee6..838bbf2 100644 --- a/deleted_at.gemspec +++ b/deleted_at.gemspec @@ -24,7 +24,7 @@ Gem::Specification.new do |spec| spec.test_files = spec.files.grep(%r{^(test|spec|features)/}) spec.require_paths = ['lib'] - rails_versions = ['>= 4.2'] + rails_versions = ['>= 4.2', '< 6.1'] spec.required_ruby_version = '>= 2.3' spec.add_runtime_dependency 'activerecord', rails_versions diff --git a/gemfiles/activerecord-6.0.Gemfile b/gemfiles/activerecord-6.0.Gemfile new file mode 100644 index 0000000..f32ff01 --- /dev/null +++ b/gemfiles/activerecord-6.0.Gemfile @@ -0,0 +1,3 @@ +eval_gemfile File.join(File.dirname(__FILE__), "../Gemfile") + +gem 'activerecord', '~> 6.0.0' From 92c904f20dc6005538ce7422a7b4b9a73f51bd6c Mon Sep 17 00:00:00 2001 From: Dale Stevens Date: Mon, 23 Dec 2019 18:02:56 -0700 Subject: [PATCH 12/12] Use any? predicate for argument detection in delete_all --- lib/deleted_at/relation.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/deleted_at/relation.rb b/lib/deleted_at/relation.rb index 5f67943..a20f8f2 100644 --- a/lib/deleted_at/relation.rb +++ b/lib/deleted_at/relation.rb @@ -1,7 +1,7 @@ module DeletedAt module Relation def delete_all(*args) - if args.pop + if args.any? ActiveSupport::Deprecation.warn(<<~STR) Passing conditions to delete_all is not supported in DeletedAt To achieve the same use where(conditions).delete_all.