dependent-auto-rails 0.1.6 → 0.1.8
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
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f413fd93d4790779d9b0376755b188e1e62f5130bed767c0ff89dbb14a8a07cc
|
4
|
+
data.tar.gz: 34fdbdfc0246bc176827767b0273442edc4d49d64c3adbdefb2f11fc410aedee
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0f80bffdcfc4ad25719648bbdb3626e1a9e8c66b06819ff31c62eba80c260c71bf40bdf8b03eaf54132077caba29eaf9514d943bbf2c642dac319d6e96c6d187
|
7
|
+
data.tar.gz: 40801ab7610aaa5c837b0a1eeda0ef9591bcc87e70476c9bf3d1f632ad8be92f10f499a59d86dd25daab028b3f38a3b086657a6a4a52429c234ca1322824cf45
|
data/README.md
CHANGED
@@ -1,24 +1,47 @@
|
|
1
|
-
|
1
|
+
[![Version](https://img.shields.io/gem/v/dependent-auto-rails)][badges:0-gem]
|
2
|
+
[![Build](https://img.shields.io/github/actions/workflow/status/joshuay03/dependent-auto-rails/.github/workflows/main.yml?branch=main)][badges:1-workflow]
|
2
3
|
|
3
|
-
|
4
|
+
# dependent-auto-rails
|
4
5
|
|
5
|
-
|
6
|
+
This gem provides a new `dependent` option for ActiveRecord associations, `:auto`. Using this option will automatically select between `:destroy` and `:delete` / `:delete_all` during runtime based on whether or not the associated model has any destroy callbacks defined. This is useful since `dependent: :destroy` always initialises the associated records in order to execute their destroy callbacks regardless of whether or not there are any defined, but is often the go-to option since it is the safest. This can be expensive if there are many records to destroy.
|
6
7
|
|
7
|
-
|
8
|
+
It is also useful since a model's associations are rarely updated, but it's business logic can change frequently. This means that if destroy callbacks are added or removed on the associated model, the `dependent` option on the parent model's association may need to be updated to reflect this. Using `dependent: :auto` will automatically select the appropriate `dependent` option based on the current state of the model.
|
9
|
+
|
10
|
+
**NOTE**: The `:auto` option **ONLY** decides between `:destroy` and `:delete` / `:delete_all`. It does not support any other `dependent` option, such as:
|
11
|
+
- `:nullify`
|
12
|
+
- `:destroy_async`
|
13
|
+
- `:restrict_with_error`
|
14
|
+
- `:restrict_with_exception`
|
8
15
|
|
9
|
-
|
16
|
+
**NOTE**: If for some reason the `:auto` option is unable to decide between `:destroy` and `:delete` / `:delete_all`, it will default to `:destroy`.
|
10
17
|
|
11
|
-
|
18
|
+
## Installation
|
12
19
|
|
13
|
-
|
20
|
+
Install the gem and add it to the application's Gemfile by executing:
|
21
|
+
|
22
|
+
$ bundle add dependent-auto-rails
|
14
23
|
|
15
24
|
If bundler is not being used to manage dependencies, install the gem by executing:
|
16
25
|
|
17
|
-
$ gem
|
26
|
+
$ gem installdependent-auto-rails
|
18
27
|
|
19
28
|
## Usage
|
20
29
|
|
21
|
-
|
30
|
+
To use this gem, all you need to do is add `dependent: :auto` to your model associations where you would usually use one of:
|
31
|
+
- `dependent: :destroy` (`belongs_to`, `has_one`, `has_many`)
|
32
|
+
- `dependent: :delete` (`belongs_to`, `has_one`)
|
33
|
+
- `dependent: :delete_all` (`has_many`).
|
34
|
+
|
35
|
+
```ruby
|
36
|
+
class Post < ApplicationRecord
|
37
|
+
belongs_to :author, dependent: :auto
|
38
|
+
|
39
|
+
has_one :pinned_comment, dependent: :auto
|
40
|
+
|
41
|
+
has_many :comments, dependent: :auto
|
42
|
+
end
|
43
|
+
|
44
|
+
```
|
22
45
|
|
23
46
|
## Development
|
24
47
|
|
@@ -28,7 +51,7 @@ To install this gem onto your local machine, run `bundle exec rake install`. To
|
|
28
51
|
|
29
52
|
## Contributing
|
30
53
|
|
31
|
-
Bug reports and pull requests are welcome on GitHub at https://github.com/
|
54
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/joshuay03/dependent-auto-rails. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/[USERNAME]/dependent-auto-rails/blob/main/CODE_OF_CONDUCT.md).
|
32
55
|
|
33
56
|
## License
|
34
57
|
|
@@ -37,3 +60,6 @@ The gem is available as open source under the terms of the [MIT License](https:/
|
|
37
60
|
## Code of Conduct
|
38
61
|
|
39
62
|
Everyone interacting in the Dependent::Auto::Rails project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/[USERNAME]/dependent-auto-rails/blob/main/CODE_OF_CONDUCT.md).
|
63
|
+
|
64
|
+
[badges:0-gem]: https://rubygems.org/gems/dependent-auto-rails
|
65
|
+
[badges:1-workflow]: https://github.com/joshuay03/dependent-auto-rails/blob/main/.github/workflows/main.yml
|
@@ -8,56 +8,3 @@ module ActiveRecord::Associations::Builder
|
|
8
8
|
private_class_method :macro, :valid_options, :valid_dependent_options
|
9
9
|
end
|
10
10
|
end
|
11
|
-
|
12
|
-
module ActiveRecord
|
13
|
-
module Associations
|
14
|
-
class HasManyAssociation < CollectionAssociation
|
15
|
-
def handle_dependency
|
16
|
-
case options[:dependent]
|
17
|
-
when :restrict_with_exception
|
18
|
-
raise ActiveRecord::DeleteRestrictionError.new(reflection.name) unless empty?
|
19
|
-
|
20
|
-
when :restrict_with_error
|
21
|
-
unless empty?
|
22
|
-
record = owner.class.human_attribute_name(reflection.name).downcase
|
23
|
-
owner.errors.add(:base, :"restrict_dependent_destroy.has_many", record: record)
|
24
|
-
throw(:abort)
|
25
|
-
end
|
26
|
-
|
27
|
-
when :destroy
|
28
|
-
# No point in executing the counter update since we're going to destroy the parent anyway
|
29
|
-
load_target.each { |t| t.destroyed_by_association = reflection }
|
30
|
-
destroy_all
|
31
|
-
when :destroy_async
|
32
|
-
load_target.each do |t|
|
33
|
-
t.destroyed_by_association = reflection
|
34
|
-
end
|
35
|
-
|
36
|
-
unless target.empty?
|
37
|
-
association_class = target.first.class
|
38
|
-
if association_class.query_constraints_list
|
39
|
-
primary_key_column = association_class.query_constraints_list.map(&:to_sym)
|
40
|
-
ids = target.collect { |assoc| primary_key_column.map { |col| assoc.public_send(col) } }
|
41
|
-
else
|
42
|
-
primary_key_column = association_class.primary_key.to_sym
|
43
|
-
ids = target.collect { |assoc| assoc.public_send(primary_key_column) }
|
44
|
-
end
|
45
|
-
|
46
|
-
ids.each_slice(owner.class.destroy_association_async_batch_size || ids.size) do |ids_batch|
|
47
|
-
enqueue_destroy_association(
|
48
|
-
owner_model_name: owner.class.to_s,
|
49
|
-
owner_id: owner.id,
|
50
|
-
association_class: reflection.klass.to_s,
|
51
|
-
association_ids: ids_batch,
|
52
|
-
association_primary_key_column: primary_key_column,
|
53
|
-
ensuring_owner_was_method: options.fetch(:ensuring_owner_was, nil)
|
54
|
-
)
|
55
|
-
end
|
56
|
-
end
|
57
|
-
else
|
58
|
-
delete_all
|
59
|
-
end
|
60
|
-
end
|
61
|
-
end
|
62
|
-
end
|
63
|
-
end
|
@@ -18,34 +18,38 @@ module ActiveRecord
|
|
18
18
|
class DynamicReflectionOptionsHash < Hash
|
19
19
|
def [](key)
|
20
20
|
return super unless key == :dependent && super(:dependent) == :auto
|
21
|
+
|
22
|
+
return @dependent_auto if defined?(@dependent_auto)
|
23
|
+
# The method returned here is only used for defining an after_commit callback
|
24
|
+
# for :destroy_async, so it doesn't really matter what we return here.
|
25
|
+
# This helps us cause we can't yet determine the correct method as
|
26
|
+
# the associated model might not have been evaluated.
|
21
27
|
return fallback_method if defining_dependent_callbacks?
|
22
28
|
|
23
|
-
|
24
|
-
|
29
|
+
@dependent_auto = begin
|
30
|
+
model = super(:association_model_name).constantize
|
25
31
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
32
|
+
if model._destroy_callbacks.empty?
|
33
|
+
case super(:association_type)
|
34
|
+
when :singular then :delete
|
35
|
+
when :collection then :delete_all
|
36
|
+
else fallback_method
|
37
|
+
end
|
38
|
+
else
|
39
|
+
:destroy
|
40
|
+
end
|
30
41
|
end
|
31
42
|
end
|
32
43
|
|
33
44
|
private
|
34
45
|
|
35
46
|
def fallback_method
|
36
|
-
:destroy
|
47
|
+
:destroy # The safest, also common to all supported associations
|
37
48
|
end
|
38
49
|
|
39
50
|
def defining_dependent_callbacks?
|
40
51
|
caller.any? { |line| line.include?("active_record/associations/builder/association.rb") }
|
41
52
|
end
|
42
|
-
|
43
|
-
def valid_destroy_callbacks(model)
|
44
|
-
model._destroy_callbacks.reject do |callback|
|
45
|
-
# ignore #handle_dependency callback
|
46
|
-
callback.filter.to_s.include?("active_record/associations/builder/association.rb")
|
47
|
-
end
|
48
|
-
end
|
49
53
|
end
|
50
54
|
end
|
51
55
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: dependent-auto-rails
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.8
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Joshua Young
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-02-
|
11
|
+
date: 2024-02-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
@@ -80,6 +80,6 @@ requirements: []
|
|
80
80
|
rubygems_version: 3.5.3
|
81
81
|
signing_key:
|
82
82
|
specification_version: 4
|
83
|
-
summary: Automatically
|
84
|
-
|
83
|
+
summary: Automatically decides between :destroy and :delete / :delete_all for your
|
84
|
+
Rails associations.
|
85
85
|
test_files: []
|