strict-loading 1.0.0
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 +7 -0
- data/CHANGELOG.md +2 -0
- data/Gemfile +22 -0
- data/README.md +41 -0
- data/Rakefile +12 -0
- data/lib/strict-loading/abstract_reflection.rb +9 -0
- data/lib/strict-loading/association.rb +20 -0
- data/lib/strict-loading/core.rb +43 -0
- data/lib/strict-loading/query_methods.rb +34 -0
- data/lib/strict-loading/railtie.rb +21 -0
- data/lib/strict-loading/relation.rb +17 -0
- data/lib/strict-loading/version.rb +5 -0
- data/lib/strict-loading.rb +25 -0
- data/lib/strict_loading.rb +1 -0
- data/spec/internal/app/models/todo_item.rb +5 -0
- data/spec/internal/app/models/todo_list.rb +5 -0
- data/spec/internal/config/database.yml +6 -0
- data/spec/internal/db/combustion_test.sqlite +0 -0
- data/spec/internal/db/schema.rb +12 -0
- data/spec/internal/log/test.log +931 -0
- data/spec/spec_helper.rb +38 -0
- data/spec/strict_loading_spec.rb +60 -0
- data/strict-loading.gemspec +19 -0
- metadata +101 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: a2e19110075e341793904808b1faf3c6409d44f8bb4ac546810867cafc8ab3ea
|
|
4
|
+
data.tar.gz: d3afb64736eae88dd4c0676b3aff34a6e29139d1cf2bebc384cc274f98f9b565
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 5e59b8a982935eecbd347f2525a40d6aaf1c61eafd33060f050a38220d9249bf0e3645f3dd0e9a2302761fc8c092d13f7354b0071faa6d77e77ff77aa0032ee0
|
|
7
|
+
data.tar.gz: 4f04540ffe96ea74815953716a3cd1e2cb01a5633fd8947bc2e8aa764d653155499825ffb1671d90b8bb39da2e846271793d190620ceedc0070bea07df4f8fc9
|
data/CHANGELOG.md
ADDED
data/Gemfile
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
source "https://rubygems.org"
|
|
2
|
+
|
|
3
|
+
gemspec
|
|
4
|
+
|
|
5
|
+
gem "concurrent-ruby", "< 1.3.5"
|
|
6
|
+
|
|
7
|
+
group :development, :test do
|
|
8
|
+
gem "rake"
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
group :development do
|
|
12
|
+
gem "appraisal"
|
|
13
|
+
gem "appraisal-run", "~> 1.0"
|
|
14
|
+
gem "pry-byebug"
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
group :test do
|
|
18
|
+
gem "combustion"
|
|
19
|
+
gem "database_cleaner"
|
|
20
|
+
gem "rspec-rails"
|
|
21
|
+
gem "sqlite3"
|
|
22
|
+
end
|
data/README.md
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# strict-loading
|
|
2
|
+
|
|
3
|
+
Backport of Rails 6.1's [strict loading](https://guides.rubyonrails.org/active_record_querying.html#strict-loading) feature for earlier versions of Rails.
|
|
4
|
+
|
|
5
|
+
## Usage
|
|
6
|
+
|
|
7
|
+
Add this line to your Gemfile:
|
|
8
|
+
|
|
9
|
+
```ruby
|
|
10
|
+
gem "strict-loading"
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Then execute:
|
|
14
|
+
```ruby
|
|
15
|
+
bundle install
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
This backport is designed to mimic the Rails 6.1 feature in both behavior and API (although it is currently not a complete implementation). Please see the official Rails [documentation](https://guides.rubyonrails.org/active_record_querying.html#strict-loading) for additional usage information.
|
|
19
|
+
|
|
20
|
+
### Violation Modes
|
|
21
|
+
|
|
22
|
+
Strict loading can report violations in two ways:
|
|
23
|
+
|
|
24
|
+
1. `:raise`: Violations will raise errors indicating which association on which model was accessed.
|
|
25
|
+
2. `:log`: Violations use the `ActiveSupport::Notifications` system and log violation messages under the notification name `strict_loading_violation.active_record`.
|
|
26
|
+
|
|
27
|
+
The default violation mode is `:raise`. To set the violation mode, add the following line to application.rb or one of your environments (eg. config/development.rb):
|
|
28
|
+
|
|
29
|
+
```ruby
|
|
30
|
+
config.active_record.action_on_strict_loading_violation = :log
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Setting up a subscriber to listen for violations can be done like so:
|
|
34
|
+
|
|
35
|
+
```ruby
|
|
36
|
+
ActiveSupport::Notifications.subscribe("strict_loading_violation.active_record") do |name, start, finish, id, payload|
|
|
37
|
+
# payload is a hash of the form { reflection:, owner: } where the reflection is the
|
|
38
|
+
# association, eg. ActiveRecord::Reflection::HasManyReflection, and `owner:` is the
|
|
39
|
+
# ActiveRecord model class.
|
|
40
|
+
end
|
|
41
|
+
```
|
data/Rakefile
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
module StrictLoading
|
|
2
|
+
module AbstractReflection
|
|
3
|
+
def strict_loading_violation_message(owner)
|
|
4
|
+
message = "`#{owner}` is marked for strict_loading."
|
|
5
|
+
message << " The #{polymorphic? ? "polymorphic association" : "#{klass} association"}"
|
|
6
|
+
message << " named `:#{name}` cannot be lazily loaded."
|
|
7
|
+
end
|
|
8
|
+
end
|
|
9
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module StrictLoading
|
|
4
|
+
module Association
|
|
5
|
+
private
|
|
6
|
+
|
|
7
|
+
def find_target
|
|
8
|
+
if violates_strict_loading?
|
|
9
|
+
::ActiveRecord::Base.strict_loading_violation!(owner: owner.class, reflection: reflection)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
super
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def violates_strict_loading?
|
|
16
|
+
return unless owner.validation_context.nil?
|
|
17
|
+
owner.strict_loading?
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module StrictLoading
|
|
4
|
+
module Core
|
|
5
|
+
def self.included(base)
|
|
6
|
+
base.include(InstanceMethods)
|
|
7
|
+
base.extend(ClassMethods)
|
|
8
|
+
|
|
9
|
+
base.delegate :strict_loading, to: :all
|
|
10
|
+
base.mattr_accessor(:action_on_strict_loading_violation, instance_writer: false)
|
|
11
|
+
base.action_on_strict_loading_violation = :raise
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
module InstanceMethods
|
|
15
|
+
def strict_loading!
|
|
16
|
+
@strict_loading = true
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def strict_loading?
|
|
20
|
+
@strict_loading
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def strict_loading #(value = true)
|
|
24
|
+
spawn.strict_loading! #(value)
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
module ClassMethods
|
|
29
|
+
delegate :strict_loading, to: :all
|
|
30
|
+
|
|
31
|
+
def strict_loading_violation!(owner:, reflection:)
|
|
32
|
+
case ActiveRecord::Base.action_on_strict_loading_violation
|
|
33
|
+
when :raise
|
|
34
|
+
message = reflection.strict_loading_violation_message(owner)
|
|
35
|
+
raise ActiveRecord::StrictLoadingViolationError.new(message)
|
|
36
|
+
when :log
|
|
37
|
+
name = "strict_loading_violation.active_record"
|
|
38
|
+
ActiveSupport::Notifications.instrument(name, owner: owner, reflection: reflection)
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module StrictLoading
|
|
4
|
+
module QueryMethods
|
|
5
|
+
def strict_loading
|
|
6
|
+
spawn.strict_loading!
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def strict_loading!
|
|
10
|
+
self.strict_loading_value = true
|
|
11
|
+
self
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def strict_loading_value
|
|
15
|
+
@values.fetch(:strict_loading, nil)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def strict_loading_value=(value)
|
|
19
|
+
raise ImmutableRelation if @loaded
|
|
20
|
+
__check_relation
|
|
21
|
+
@values[:strict_loading] = value
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
if ActiveRecord::VERSION::STRING >= "5.0"
|
|
25
|
+
def __check_relation
|
|
26
|
+
assert_mutability!
|
|
27
|
+
end
|
|
28
|
+
else
|
|
29
|
+
def __check_relation
|
|
30
|
+
check_cached_relation
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module StrictLoading
|
|
4
|
+
class Railtie < Rails::Railtie
|
|
5
|
+
initializer "strict_loading.initialize" do
|
|
6
|
+
ActiveSupport.on_load(:active_record) do
|
|
7
|
+
::ActiveRecord::Relation.prepend(::StrictLoading::Relation)
|
|
8
|
+
::ActiveRecord::Relation.include(::StrictLoading::QueryMethods)
|
|
9
|
+
::ActiveRecord::Associations::HasManyAssociation.prepend(::StrictLoading::Association)
|
|
10
|
+
::ActiveRecord::Associations::SingularAssociation.prepend(::StrictLoading::Association)
|
|
11
|
+
::ActiveRecord::Associations::HasManyThroughAssociation.prepend(::StrictLoading::Association)
|
|
12
|
+
::ActiveRecord::Associations::CollectionAssociation.prepend(::StrictLoading::Association)
|
|
13
|
+
::ActiveRecord::Reflection::AbstractReflection.include(::StrictLoading::AbstractReflection)
|
|
14
|
+
|
|
15
|
+
if (action = Rails.application.config.active_record.action_on_strict_loading_violation)
|
|
16
|
+
self.action_on_strict_loading_violation = action
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module StrictLoading
|
|
4
|
+
module Relation
|
|
5
|
+
private
|
|
6
|
+
|
|
7
|
+
def exec_queries
|
|
8
|
+
super.tap do |records|
|
|
9
|
+
unless strict_loading_value.nil?
|
|
10
|
+
records.each do |record|
|
|
11
|
+
record.strict_loading!
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module StrictLoading
|
|
4
|
+
autoload :AbstractReflection, "strict-loading/abstract_reflection"
|
|
5
|
+
autoload :Association, "strict-loading/association"
|
|
6
|
+
autoload :Core, "strict-loading/core"
|
|
7
|
+
autoload :QueryMethods, "strict-loading/query_methods"
|
|
8
|
+
autoload :Relation, "strict-loading/relation"
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
require "active_record"
|
|
12
|
+
|
|
13
|
+
module ActiveRecord
|
|
14
|
+
class StrictLoadingViolationError < ::ActiveRecord::ActiveRecordError; end
|
|
15
|
+
|
|
16
|
+
class Base
|
|
17
|
+
# we can't do this in the railtie's initializer because we need to load it
|
|
18
|
+
# earlier than ActiveRecord's own initializer
|
|
19
|
+
include ::StrictLoading::Core
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
if defined?(Rails)
|
|
24
|
+
require "strict-loading/railtie"
|
|
25
|
+
end
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
require "strict-loading"
|
|
Binary file
|