a-nti_manner_kick_course 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +121 -0
- data/Rakefile +3 -0
- data/lib/a/nti_manner_kick_course/railtie.rb +16 -0
- data/lib/a/nti_manner_kick_course/version.rb +5 -0
- data/lib/a/nti_manner_kick_course.rb +92 -0
- data/lib/tasks/a/nti_manner_kick_course_tasks.rake +4 -0
- metadata +69 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 4dc6a3d6c4947ef0ed61f061101a08fbce40cb114e6a8e27f10445d3c3d77ba9
|
4
|
+
data.tar.gz: ad23ea7057ba5e40f4a4830c363aab4b73c18678292e83dd06894c049c803da1
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 5e43b59506830ae8320db2ea37c5a87d28967f43399982492196b14bc4fc10b51aa23058875c04b269769a9d96048071ef2d6d79d86c43904234256d12e8662b
|
7
|
+
data.tar.gz: aa4d12b64c793bf21480abd45364f54ad2d2c881846cd4493ca23d2617f35f84844a8109b8d78d95980c3d5746025bedeba7493dc0c2e0df0b47134e098dc02d
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright Shinichi Maeshima
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,121 @@
|
|
1
|
+
# A::NtiMannerKickCourse
|
2
|
+
|
3
|
+
Rails speeds up the startup process by lazily loading classes for components like ActiveRecord::Base and ActionController::Base. Additionally, the behavior of lazy loading is essential for applying configuration settings to these components. Without lazy loading, some configurations might not be applied as expected.
|
4
|
+
|
5
|
+
For example, consider the following scenario:
|
6
|
+
|
7
|
+
When upgrading from Rails 7.0 to Rails 7.1, running rails app:upgrade generates a file named `config/initializers/new_framework_defaults_7_1.rb`. This file helps incrementally enable new default settings for Rails 7.1. Initially, all settings in this file are commented out. Uncommenting the following setting will enable it:
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
###
|
11
|
+
# Do not treat an `ActionController::Parameters` instance
|
12
|
+
# as equal to an equivalent `Hash` by default.
|
13
|
+
#++
|
14
|
+
Rails.application.config.action_controller.allow_deprecated_parameters_hash_equality = false
|
15
|
+
````
|
16
|
+
|
17
|
+
As the comment suggests, this setting ensures that ActionController::Parameters instances are no longer treated as equivalent to Hash. However, if ActionController::Base is eager-loaded, this configuration will not behave as expected. Why does this happen?
|
18
|
+
|
19
|
+
Configuration settings like `Rails.application.config.action_controller.allow_deprecated_parameters_hash_equality` are not automatically effective. These settings are applied to components like ActionController only during the Rails initialization process.
|
20
|
+
|
21
|
+
In this case, the value of `Rails.application.config.action_controller.allow_deprecated_parameters_hash_equality` is assigned to `ActionController::Parameters.allow_deprecated_parameters_hash_equality` during initialization, as seen in the following code:
|
22
|
+
|
23
|
+
```ruby
|
24
|
+
ActionController::Parameters.allow_deprecated_parameters_hash_equality = Rails.application.config.action_controller.allow_deprecated_parameters_hash_equality
|
25
|
+
```
|
26
|
+
|
27
|
+
Source: https://github.com/rails/rails/blob/36c1591bcb5e0ee3084759c7f42a706fe5bb7ca7/actionpack/lib/action_controller/railtie.rb#L51-L52
|
28
|
+
|
29
|
+
This assignment is wrapped in an `ActiveSupport.on_load(:action_controller, run_once: true) do ... end` block, ensuring that it runs only when ActionController::Base is loaded:
|
30
|
+
|
31
|
+
```ruby
|
32
|
+
ActiveSupport.on_load(:action_controller, run_once: true) do
|
33
|
+
# Configuration assignment logic
|
34
|
+
end
|
35
|
+
````
|
36
|
+
|
37
|
+
Now, consider a gem "add_some_function_to_controller" with the following code:
|
38
|
+
|
39
|
+
```ruby
|
40
|
+
module AddSomeFunctionToController
|
41
|
+
# snip
|
42
|
+
end
|
43
|
+
|
44
|
+
ActionController::Base.include(AddSomeFunctionToController)
|
45
|
+
```
|
46
|
+
|
47
|
+
Since all gems listed in the Gemfile are required in config/application.rb, the above code causes ActionController::Base to be loaded during Rails initialization. The order of initialization typically looks like this:
|
48
|
+
|
49
|
+
1. config/application.rb
|
50
|
+
2. Component configuration logic (e.g., applying settings)
|
51
|
+
3. Initializer files in config/initializers/*.rb
|
52
|
+
|
53
|
+
As a result, the configuration logic for ActionController is executed before the initializer file `config/initializers/new_framework_defaults_7_1.rb`. This means that the setting `Rails.application.config.action_controller.allow_deprecated_parameters_hash_equality = false` is not applied in time.
|
54
|
+
|
55
|
+
Fixing the Issue
|
56
|
+
|
57
|
+
To solve this, modify the gem code as follows:
|
58
|
+
|
59
|
+
```ruby
|
60
|
+
module AddSomeFunctionToController
|
61
|
+
# snip
|
62
|
+
end
|
63
|
+
|
64
|
+
ActiveSupport.on_load(:action_controller) do
|
65
|
+
ActionController::Base.include(AddSomeFunctionToController)
|
66
|
+
end
|
67
|
+
```
|
68
|
+
|
69
|
+
This ensures that ActionController::Base is loaded lazily, delaying the execution of the configuration logic to the correct timing. The updated order of initialization becomes:
|
70
|
+
|
71
|
+
1. config/application.rb
|
72
|
+
2. Initializer files in config/initializers/*.rb
|
73
|
+
3. Component configuration logic
|
74
|
+
|
75
|
+
This resolves the issue, as the setting in config/initializers/new_framework_defaults_7_1.rb is now applied correctly.
|
76
|
+
|
77
|
+
While this specific case is likely a common issue, other problems may also arise from changes to the initialization order. To ensure reliable behavior, it is critical to keep all component loading deferred during Rails initialization. However, manually checking for potential issues with lazy loading is impractical.
|
78
|
+
|
79
|
+
Using a-nti_manner_kick_course can help detect libraries or application code (like add_some_function_to_controller) that interfere with lazy loading, allowing you to maintain proper initialization behavior.
|
80
|
+
|
81
|
+
## Installation
|
82
|
+
|
83
|
+
Add this line **at the top of your Gemfile**.
|
84
|
+
|
85
|
+
```ruby
|
86
|
+
gem "a-nti_manner_kick_course"
|
87
|
+
```
|
88
|
+
|
89
|
+
> [!IMPORTANT]
|
90
|
+
> To detect gems that fail to defer execution, you need to add this gem at the top of your Gemfile.
|
91
|
+
|
92
|
+
And then execute:
|
93
|
+
```bash
|
94
|
+
$ bundle
|
95
|
+
```
|
96
|
+
|
97
|
+
## Usage
|
98
|
+
|
99
|
+
Start your Rails application with the ANTI_MANNER environment variable as follows.
|
100
|
+
|
101
|
+
```bash
|
102
|
+
$ ANTI_MANNER=1 rails boot
|
103
|
+
```
|
104
|
+
|
105
|
+
If you are using Rails 7.1 or below, start the application as follows.
|
106
|
+
|
107
|
+
```bash
|
108
|
+
$ ANTI_MANNER=1 rails runner 1
|
109
|
+
```
|
110
|
+
|
111
|
+
If any code fails to lazy loading, the process will exit with status code 1. This command suggests which lines are eager loading Rails code. It is a good idea to regularly check in CI if lazy loading is working correctly.
|
112
|
+
|
113
|
+
You can fix the issue by wrapping the relevant code in an `ActiveSupport.on_load` block.
|
114
|
+
|
115
|
+
For more details about ActiveSupport.on_load, check [the official Rails documentation]((https://api.rubyonrails.org/classes/ActiveSupport/LazyLoadHooks.html).
|
116
|
+
|
117
|
+
If the ANTI_MANNER environment variable is not set, this gem does nothing.
|
118
|
+
|
119
|
+
|
120
|
+
## License
|
121
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
data/Rakefile
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
require "rails"
|
2
|
+
|
3
|
+
module A
|
4
|
+
module NtiMannerKickCourse
|
5
|
+
class Railtie < ::Rails::Railtie
|
6
|
+
initializer "anti_manner", before: :eager_load! do
|
7
|
+
if A::NtiMannerKickCourse.enabled?
|
8
|
+
A::NtiMannerKickCourse.finish_monitoring
|
9
|
+
|
10
|
+
puts "Congratulations! No code was found that fails to defer execution!"
|
11
|
+
exit
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
require "a/nti_manner_kick_course/version"
|
2
|
+
require "a/nti_manner_kick_course/railtie"
|
3
|
+
|
4
|
+
module A
|
5
|
+
module NtiMannerKickCourse
|
6
|
+
MONITORED_HOOKS = %i[
|
7
|
+
action_controller action_controller_base action_controller_api action_controller_test_case action_dispatch_response action_dispatch_integration_test
|
8
|
+
message_pack active_model active_model_translation active_job active_job_test_case active_record_fixtures
|
9
|
+
action_cable_connection action_cable_connection_test_case action_cable action_cable_channel action_cable_channel_test_case
|
10
|
+
action_text_encrypted_rich_text action_text_record action_text_rich_text action_text_content active_record active_record_fixture_set
|
11
|
+
active_record_sqlite3adapter active_record_mysql2adapter active_record_trilogyadapter active_record_postgresqladapter active_record_encryption
|
12
|
+
action_view action_view_test_case action_mailer action_mailer_test_case active_storage_blog active_storage_record active_storage_variant_record
|
13
|
+
active_storage_attachment action_mailbox_inbound_email action_mailbox_record action_mailbox action_mailbox_test_case
|
14
|
+
].freeze
|
15
|
+
|
16
|
+
class << self
|
17
|
+
def enabled?
|
18
|
+
ENV["ANTI_MANNER"]
|
19
|
+
end
|
20
|
+
|
21
|
+
def debug?
|
22
|
+
ENV["ANTI_MANNER_DEBUG"]
|
23
|
+
end
|
24
|
+
|
25
|
+
def monitor
|
26
|
+
require "active_support/lazy_load_hooks"
|
27
|
+
|
28
|
+
start_monitoring
|
29
|
+
|
30
|
+
MONITORED_HOOKS.each do |framework|
|
31
|
+
ActiveSupport.on_load(framework) do
|
32
|
+
if A::NtiMannerKickCourse.monitoring? && !A::NtiMannerKickCourse.already_checked?
|
33
|
+
A::NtiMannerKickCourse.already_checked
|
34
|
+
message = if A::NtiMannerKickCourse.debug?
|
35
|
+
<<~"MESSAGE"
|
36
|
+
During Rails startup, the block inside ActiveSupport.on_load(#{framework}) was executed.
|
37
|
+
There is code that is not being deferred as expected.
|
38
|
+
|
39
|
+
Currently, debug mode is enabled, so the full stack trace is being displayed.
|
40
|
+
To show only the suspicious code line, remove the ANTI_MANNER_DEBUG environment variable and rerun.
|
41
|
+
|
42
|
+
#{caller}
|
43
|
+
MESSAGE
|
44
|
+
else
|
45
|
+
suspect = caller.find { |c| !A::NtiMannerKickCourse.filtering.match?(c) }
|
46
|
+
<<~"MESSAGE"
|
47
|
+
During Rails startup, the block inside ActiveSupport.on_load(#{framework}) was executed.
|
48
|
+
There is code that is not being deferred as expected. The suspicious part is here.
|
49
|
+
|
50
|
+
#{suspect}
|
51
|
+
|
52
|
+
If you want to check the entire stack trace, set the ANTI_MANNER_DEBUG environment variable.
|
53
|
+
MESSAGE
|
54
|
+
end
|
55
|
+
|
56
|
+
abort(message)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def monitoring?
|
63
|
+
@monitoring
|
64
|
+
end
|
65
|
+
|
66
|
+
def finish_monitoring
|
67
|
+
@monitoring = false
|
68
|
+
end
|
69
|
+
|
70
|
+
# TODO: We need to make this list more comprehensive.
|
71
|
+
def filtering
|
72
|
+
%r{<internal:|/bundled_gems.rb|/(activesupport|actionpack|activerecord|bootsnap|bundler|zeitwerk)-[0-9a-z\.]+/}
|
73
|
+
end
|
74
|
+
|
75
|
+
def already_checked?
|
76
|
+
@already_checked
|
77
|
+
end
|
78
|
+
|
79
|
+
def already_checked
|
80
|
+
@already_checked = true
|
81
|
+
end
|
82
|
+
|
83
|
+
private
|
84
|
+
|
85
|
+
def start_monitoring
|
86
|
+
@monitoring = true
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
monitor if enabled?
|
91
|
+
end
|
92
|
+
end
|
metadata
ADDED
@@ -0,0 +1,69 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: a-nti_manner_kick_course
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Shinichi Maeshima
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2025-01-16 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rails
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 7.0.0
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 7.0.0
|
27
|
+
description: This library detects code or gems that violate lazy loading conventions
|
28
|
+
during Rails initialization.
|
29
|
+
email:
|
30
|
+
- netwillnet@gmail.com
|
31
|
+
executables: []
|
32
|
+
extensions: []
|
33
|
+
extra_rdoc_files: []
|
34
|
+
files:
|
35
|
+
- MIT-LICENSE
|
36
|
+
- README.md
|
37
|
+
- Rakefile
|
38
|
+
- lib/a/nti_manner_kick_course.rb
|
39
|
+
- lib/a/nti_manner_kick_course/railtie.rb
|
40
|
+
- lib/a/nti_manner_kick_course/version.rb
|
41
|
+
- lib/tasks/a/nti_manner_kick_course_tasks.rake
|
42
|
+
homepage: https://github.com/willnet/a-nti_manner_kick_course
|
43
|
+
licenses:
|
44
|
+
- MIT
|
45
|
+
metadata:
|
46
|
+
homepage_uri: https://github.com/willnet/a-nti_manner_kick_course
|
47
|
+
source_code_uri: https://github.com/willnet/a-nti_manner_kick_course
|
48
|
+
changelog_uri: https://github.com/willnet/a-nti_manner_kick_course/releases
|
49
|
+
post_install_message:
|
50
|
+
rdoc_options: []
|
51
|
+
require_paths:
|
52
|
+
- lib
|
53
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
54
|
+
requirements:
|
55
|
+
- - ">="
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
version: '0'
|
58
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
59
|
+
requirements:
|
60
|
+
- - ">="
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: '0'
|
63
|
+
requirements: []
|
64
|
+
rubygems_version: 3.5.22
|
65
|
+
signing_key:
|
66
|
+
specification_version: 4
|
67
|
+
summary: This library detects code or gems that violate lazy loading conventions during
|
68
|
+
Rails initialization.
|
69
|
+
test_files: []
|