From dfdd984b37bf3d646b276d68e47f7f998c6aaad9 Mon Sep 17 00:00:00 2001 From: Gustavo Bazan Date: Wed, 18 Apr 2018 10:33:53 +0100 Subject: [PATCH] General improvements Simplify `discard` and `undiscard` methods - remove with_transaction_returning_status, run_callbacks shoudl return the result of the block - use update_attribute as no validation should be performed to discard (same as with destroy) Scope `discard_all` to only kept records, `#discard` will not change them and this can save some ierations and help to return only affected records at the end of the query (more like `destroy_all`) Scope `discard_all` to only discarded records, `#undiscard` will not change them and this can save some iterations and help to return only affected records at the end of the query (more like `destroy_all`) Update README to clarify that save and update callbacks are run when discarding/undiscarding Update travis ruby versions Add .yardopts --- .travis.yml | 8 ++--- .yardopts | 8 +++++ README.md | 2 ++ discard.gemspec | 2 +- lib/discard/model.rb | 73 ++++++++++++++++++++++++++++++------------ lib/discard/version.rb | 3 +- 6 files changed, 70 insertions(+), 26 deletions(-) create mode 100644 .yardopts diff --git a/.travis.yml b/.travis.yml index 09b4f47..e58c999 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,10 +1,10 @@ sudo: false language: ruby rvm: - - 2.2.9 - - 2.3.6 - - 2.4.3 - - 2.5.0 + - 2.2.10 + - 2.3.7 + - 2.4.4 + - 2.5.1 env: matrix: - RAILS_VERSION='~> 4.2.0' diff --git a/.yardopts b/.yardopts new file mode 100644 index 0000000..30fa311 --- /dev/null +++ b/.yardopts @@ -0,0 +1,8 @@ +--protected +--no-private +--embed-mixin ClassMethods +- +README.md +CHANGELOG.md +CODE_OF_CONDUCT.md +LICENSE.txt diff --git a/README.md b/README.md index 0d979ab..268f645 100644 --- a/README.md +++ b/README.md @@ -186,6 +186,8 @@ class Post < ActiveRecord::Base end ``` +*Warning:* Please note that callbacks for save and update are run when discarding/undiscarding a record + **Working with Devise** A common use case is to apply discard to a User record. Even though a user has been discarded they can still login and continue their session. diff --git a/discard.gemspec b/discard.gemspec index e166e7c..5cd286d 100644 --- a/discard.gemspec +++ b/discard.gemspec @@ -21,7 +21,7 @@ Gem::Specification.new do |spec| spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) } spec.require_paths = ["lib"] - spec.add_dependency "activerecord", '>= 4.2', '< 6' + spec.add_dependency "activerecord", ">= 4.2", "< 6" spec.add_development_dependency "bundler", "~> 1.14" spec.add_development_dependency "rake", "~> 10.0" spec.add_development_dependency "rspec", "~> 3.5.0" diff --git a/lib/discard/model.rb b/lib/discard/model.rb index a057de6..c34a2b0 100644 --- a/lib/discard/model.rb +++ b/lib/discard/model.rb @@ -1,4 +1,9 @@ module Discard + # Handles soft deletes of records. + # + # Options: + # + # - :discard_column - The columns used to track soft delete, defaults to `:discarded_at`. module Model extend ActiveSupport::Concern @@ -15,41 +20,69 @@ module Model define_model_callbacks :undiscard end + # :nodoc: module ClassMethods + # Discards the records by instantiating each + # record and calling its {#discard} method. + # Each object's callbacks are executed. + # Returns the collection of objects that were discarded. + # + # Note: Instantiation, callback execution, and update of each + # record can be time consuming when you're discarding many records at + # once. It generates at least one SQL +UPDATE+ query per record (or + # possibly more, to enforce your callbacks). If you want to discard many + # rows quickly, without concern for their associations or callbacks, use + # #update_all(discarded_at: Time.current) instead. + # + # ==== Examples + # + # Person.where(age: 0..18).discard_all def discard_all - all.each(&:discard) + kept.each(&:discard) end + + # Undiscards the records by instantiating each + # record and calling its {#undiscard} method. + # Each object's callbacks are executed. + # Returns the collection of objects that were undiscarded. + # + # Note: Instantiation, callback execution, and update of each + # record can be time consuming when you're undiscarding many records at + # once. It generates at least one SQL +UPDATE+ query per record (or + # possibly more, to enforce your callbacks). If you want to undiscard many + # rows quickly, without concern for their associations or callbacks, use + # #update_all(discarded_at: nil) instead. + # + # ==== Examples + # + # Person.where(age: 0..18).undiscard_all def undiscard_all - all.each(&:undiscard) + discarded.each(&:undiscard) end end - # @return [true,false] true if this record has been discarded, otherwise false + # @return [Boolean] true if this record has been discarded, otherwise false def discarded? - !!self[self.class.discard_column] + self[self.class.discard_column].present? end - # @return [true,false] true if successful, otherwise false + # Discard record + # + # @return [Boolean] true if successful, otherwise false def discard - unless discarded? - with_transaction_returning_status do - run_callbacks(:discard) do - self[self.class.discard_column] = Time.current - save - end - end + return if discarded? + run_callbacks(:discard) do + update_attribute(self.class.discard_column, Time.current) end end - # @return [true,false] true if successful, otherwise false + # Undiscard record + # + # @return [Boolean] true if successful, otherwise false def undiscard - if discarded? - with_transaction_returning_status do - run_callbacks(:undiscard) do - self[self.class.discard_column] = nil - save - end - end + return unless discarded? + run_callbacks(:undiscard) do + update_attribute(self.class.discard_column, nil) end end end diff --git a/lib/discard/version.rb b/lib/discard/version.rb index 5ad39ce..e6c928f 100644 --- a/lib/discard/version.rb +++ b/lib/discard/version.rb @@ -1,3 +1,4 @@ module Discard - VERSION = "1.0.0" + # Discard version + VERSION = "1.0.0".freeze end