railties 8.0.3 → 8.1.0.beta1
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 +4 -4
- data/CHANGELOG.md +72 -232
- data/lib/minitest/rails_plugin.rb +48 -12
- data/lib/rails/application/bootstrap.rb +5 -0
- data/lib/rails/application/configuration.rb +26 -0
- data/lib/rails/application/default_middleware_stack.rb +1 -1
- data/lib/rails/application/finisher.rb +2 -1
- data/lib/rails/application/routes_reloader.rb +0 -1
- data/lib/rails/application.rb +1 -3
- data/lib/rails/command/base.rb +0 -2
- data/lib/rails/command/environment_argument.rb +0 -1
- data/lib/rails/command.rb +1 -1
- data/lib/rails/commands/console/irb_console.rb +4 -4
- data/lib/rails/commands/credentials/credentials_command.rb +25 -5
- data/lib/rails/commands/encrypted/encrypted_command.rb +0 -1
- data/lib/rails/engine.rb +0 -1
- data/lib/rails/gem_version.rb +3 -3
- data/lib/rails/generators/actions.rb +2 -3
- data/lib/rails/generators/app_base.rb +37 -28
- data/lib/rails/generators/database.rb +1 -1
- data/lib/rails/generators/erb/authentication/authentication_generator.rb +2 -0
- data/lib/rails/generators/erb/scaffold/templates/partial.html.erb.tt +2 -2
- data/lib/rails/generators/generated_attribute.rb +1 -1
- data/lib/rails/generators/migration.rb +0 -1
- data/lib/rails/generators/rails/app/app_generator.rb +12 -2
- data/lib/rails/generators/rails/app/templates/Dockerfile.tt +14 -12
- data/lib/rails/generators/rails/app/templates/Gemfile.tt +3 -0
- data/lib/rails/generators/rails/app/templates/app/controllers/application_controller.rb.tt +5 -0
- data/lib/rails/generators/rails/app/templates/app/views/layouts/application.html.erb.tt +1 -0
- data/lib/rails/generators/rails/app/templates/bin/bundler-audit.tt +5 -0
- data/lib/rails/generators/rails/app/templates/bin/ci.tt +5 -0
- data/lib/rails/generators/rails/app/templates/bin/rubocop.tt +1 -1
- data/lib/rails/generators/rails/app/templates/bin/setup.tt +1 -0
- data/lib/rails/generators/rails/app/templates/config/bundler-audit.yml.tt +5 -0
- data/lib/rails/generators/rails/app/templates/config/ci.rb.tt +34 -0
- data/lib/rails/generators/rails/app/templates/config/databases/mysql.yml.tt +9 -1
- data/lib/rails/generators/rails/app/templates/config/databases/postgresql.yml.tt +10 -2
- data/lib/rails/generators/rails/app/templates/config/databases/sqlite3.yml.tt +1 -1
- data/lib/rails/generators/rails/app/templates/config/databases/trilogy.yml.tt +9 -1
- data/lib/rails/generators/rails/app/templates/config/deploy.yml.tt +5 -5
- data/lib/rails/generators/rails/app/templates/config/environments/development.rb.tt +5 -0
- data/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt +16 -4
- data/lib/rails/generators/rails/app/templates/config/initializers/content_security_policy.rb.tt +4 -0
- data/lib/rails/generators/rails/app/templates/config/initializers/new_framework_defaults_8_1.rb.tt +66 -0
- data/lib/rails/generators/rails/app/templates/config/puma.rb.tt +3 -2
- data/lib/rails/generators/rails/app/templates/config/storage.yml.tt +0 -7
- data/lib/rails/generators/rails/app/templates/docker-entrypoint.tt +0 -6
- data/lib/rails/generators/rails/app/templates/github/ci.yml.tt +101 -19
- data/lib/rails/generators/rails/app/templates/github/dependabot.yml +2 -2
- data/lib/rails/generators/rails/app/templates/kamal-secrets.tt +3 -0
- data/lib/rails/generators/rails/app/templates/public/400.html +1 -1
- data/lib/rails/generators/rails/app/templates/public/404.html +2 -2
- data/lib/rails/generators/rails/app/templates/public/422.html +1 -1
- data/lib/rails/generators/rails/app/templates/public/500.html +2 -2
- data/lib/rails/generators/rails/authentication/authentication_generator.rb +17 -6
- data/lib/rails/generators/rails/authentication/templates/app/controllers/passwords_controller.rb.tt +6 -0
- data/lib/rails/generators/rails/authentication/templates/app/controllers/sessions_controller.rb.tt +2 -2
- data/lib/rails/generators/rails/authentication/templates/test/test_helpers/session_test_helper.rb.tt +15 -0
- data/lib/rails/generators/rails/benchmark/USAGE +1 -1
- data/lib/rails/generators/rails/benchmark/templates/benchmark.rb.tt +0 -2
- data/lib/rails/generators/rails/devcontainer/templates/devcontainer/Dockerfile.tt +4 -0
- data/lib/rails/generators/rails/devcontainer/templates/devcontainer/compose.yaml.tt +2 -2
- data/lib/rails/generators/rails/encryption_key_file/encryption_key_file_generator.rb +17 -5
- data/lib/rails/generators/rails/master_key/master_key_generator.rb +0 -12
- data/lib/rails/generators/rails/plugin/templates/github/ci.yml.tt +20 -9
- data/lib/rails/generators/rails/plugin/templates/github/dependabot.yml +2 -2
- data/lib/rails/generators/rails/script/USAGE +1 -1
- data/lib/rails/generators/test_unit/authentication/authentication_generator.rb +3 -2
- data/lib/rails/generators/test_unit/authentication/templates/test/controllers/passwords_controller_test.rb.tt +67 -0
- data/lib/rails/generators/test_unit/authentication/templates/test/controllers/sessions_controller_test.rb +33 -0
- data/lib/rails/generators/test_unit/authentication/templates/test/models/user_test.rb.tt +4 -3
- data/lib/rails/generators/test_unit/model/templates/fixtures.yml.tt +1 -1
- data/lib/rails/generators/testing/behavior.rb +0 -3
- data/lib/rails/generators.rb +3 -1
- data/lib/rails/health_controller.rb +8 -2
- data/lib/rails/info.rb +4 -5
- data/lib/rails/info_controller.rb +2 -3
- data/lib/rails/initializable.rb +63 -19
- data/lib/rails/rack/silence_request.rb +5 -2
- data/lib/rails/railtie/configurable.rb +0 -1
- data/lib/rails/railtie.rb +0 -1
- data/lib/rails/templates/rails/info/notes.html.erb +23 -0
- data/lib/rails/templates/rails/mailers/email.html.erb +3 -2
- data/lib/rails/templates/rails/welcome/index.html.erb +17 -1
- data/lib/rails/test_unit/reporter.rb +5 -4
- data/lib/rails/test_unit/runner.rb +8 -5
- data/lib/rails.rb +9 -2
- metadata +19 -15
- data/lib/rails/generators/rails/app/templates/config/initializers/new_framework_defaults_8_0.rb.tt +0 -30
- data/lib/rails/generators/test_unit/plugin/plugin_generator.rb +0 -15
- data/lib/rails/generators/test_unit/plugin/templates/%file_name%_test.rb.tt +0 -7
- data/lib/rails/generators/test_unit/plugin/templates/test_helper.rb +0 -2
- /data/lib/rails/generators/{test_unit → rails}/authentication/templates/test/mailers/previews/passwords_mailer_preview.rb.tt +0 -0
@@ -7,7 +7,7 @@ services:
|
|
7
7
|
dockerfile: .devcontainer/Dockerfile
|
8
8
|
|
9
9
|
volumes:
|
10
|
-
-
|
10
|
+
- ../../<%= options[:app_name] %>:/workspaces/<%= options[:app_name] %>:cached
|
11
11
|
|
12
12
|
# Overrides default command so things don't shut down after the process ends.
|
13
13
|
command: sleep infinity
|
@@ -32,7 +32,7 @@ services:
|
|
32
32
|
|
33
33
|
<%- if options[:redis] -%>
|
34
34
|
redis:
|
35
|
-
image:
|
35
|
+
image: valkey/valkey:8
|
36
36
|
restart: unless-stopped
|
37
37
|
volumes:
|
38
38
|
- redis-data:/data
|
@@ -21,18 +21,20 @@ module Rails
|
|
21
21
|
|
22
22
|
log ""
|
23
23
|
add_key_file_silently(key_path, key)
|
24
|
+
ensure_key_files_are_ignored(key_path)
|
24
25
|
log ""
|
25
26
|
end
|
26
27
|
end
|
27
28
|
|
28
29
|
def add_key_file_silently(key_path, key = nil)
|
29
30
|
create_file key_path, key || ActiveSupport::EncryptedFile.generate_key, perm: 0600
|
31
|
+
ensure_key_files_are_ignored_silently(key_path)
|
30
32
|
end
|
31
33
|
|
32
|
-
def
|
34
|
+
def ensure_key_files_are_ignored(key_path, ignore: key_ignore(key_path))
|
33
35
|
if File.exist?(".gitignore")
|
34
36
|
unless File.read(".gitignore").include?(ignore)
|
35
|
-
log "Ignoring #{
|
37
|
+
log "Ignoring #{ignore} so it won't end up in Git history:"
|
36
38
|
log ""
|
37
39
|
append_to_file ".gitignore", ignore
|
38
40
|
log ""
|
@@ -44,13 +46,23 @@ module Rails
|
|
44
46
|
end
|
45
47
|
end
|
46
48
|
|
47
|
-
def
|
48
|
-
|
49
|
+
def ensure_key_files_are_ignored_silently(key_path, ignore: key_ignore(key_path))
|
50
|
+
if File.exist?(".gitignore")
|
51
|
+
unless File.read(".gitignore").include?(ignore)
|
52
|
+
append_to_file ".gitignore", ignore
|
53
|
+
end
|
54
|
+
end
|
49
55
|
end
|
50
56
|
|
51
57
|
private
|
52
58
|
def key_ignore(key_path)
|
53
|
-
|
59
|
+
key_path = Pathname.new(key_path) unless key_path.is_a?(Pathname)
|
60
|
+
<<~IGNORE
|
61
|
+
|
62
|
+
# Ignore key files for decrypting credentials and more.
|
63
|
+
/#{key_path.dirname.join("*.key")}
|
64
|
+
|
65
|
+
IGNORE
|
54
66
|
end
|
55
67
|
end
|
56
68
|
end
|
@@ -32,22 +32,10 @@ module Rails
|
|
32
32
|
end
|
33
33
|
end
|
34
34
|
|
35
|
-
def ignore_master_key_file
|
36
|
-
key_file_generator.ignore_key_file(MASTER_KEY_PATH, ignore: key_ignore)
|
37
|
-
end
|
38
|
-
|
39
|
-
def ignore_master_key_file_silently
|
40
|
-
key_file_generator.ignore_key_file_silently(MASTER_KEY_PATH, ignore: key_ignore)
|
41
|
-
end
|
42
|
-
|
43
35
|
private
|
44
36
|
def key_file_generator
|
45
37
|
EncryptionKeyFileGenerator.new([], options)
|
46
38
|
end
|
47
|
-
|
48
|
-
def key_ignore
|
49
|
-
[ "", "# Ignore master key for decrypting credentials and more.", "/#{MASTER_KEY_PATH}", "" ].join("\n")
|
50
|
-
end
|
51
39
|
end
|
52
40
|
end
|
53
41
|
end
|
@@ -3,22 +3,35 @@ name: CI
|
|
3
3
|
on:
|
4
4
|
pull_request:
|
5
5
|
push:
|
6
|
-
branches: [
|
6
|
+
branches: [ <%= user_default_branch %> ]
|
7
7
|
|
8
8
|
jobs:
|
9
9
|
<%- unless skip_rubocop? -%>
|
10
10
|
lint:
|
11
11
|
runs-on: ubuntu-latest
|
12
|
+
env:
|
13
|
+
RUBY_VERSION: <%= ENV["RBENV_VERSION"] || ENV["rvm_ruby_string"] || "#{RUBY_ENGINE}-#{RUBY_ENGINE_VERSION}" %>
|
14
|
+
RUBOCOP_CACHE_ROOT: tmp/rubocop
|
12
15
|
steps:
|
13
16
|
- name: Checkout code
|
14
|
-
uses: actions/checkout@
|
17
|
+
uses: actions/checkout@v5
|
15
18
|
|
16
19
|
- name: Set up Ruby
|
17
20
|
uses: ruby/setup-ruby@v1
|
18
21
|
with:
|
19
|
-
ruby-version:
|
22
|
+
ruby-version: ${{ env.RUBY_VERSION }}
|
20
23
|
bundler-cache: true
|
21
24
|
|
25
|
+
- name: Prepare RuboCop cache
|
26
|
+
uses: actions/cache@v4
|
27
|
+
env:
|
28
|
+
DEPENDENCIES_HASH: ${{ hashFiles('**/.rubocop.yml', '**/.rubocop_todo.yml', 'Gemfile.lock') }}
|
29
|
+
with:
|
30
|
+
path: ${{ env.RUBOCOP_CACHE_ROOT }}
|
31
|
+
key: rubocop-${{ runner.os }}-${{ env.RUBY_VERSION }}-${{ env.DEPENDENCIES_HASH }}-${{ github.ref_name == github.event.repository.default_branch && github.run_id || 'default' }}
|
32
|
+
restore-keys: |
|
33
|
+
rubocop-${{ runner.os }}-${{ env.RUBY_VERSION }}-${{ env.DEPENDENCIES_HASH }}-
|
34
|
+
|
22
35
|
- name: Lint code for consistent style
|
23
36
|
run: bin/rubocop -f github
|
24
37
|
|
@@ -30,7 +43,7 @@ jobs:
|
|
30
43
|
<%- if options[:database] == "sqlite3" -%>
|
31
44
|
# services:
|
32
45
|
# redis:
|
33
|
-
# image:
|
46
|
+
# image: valkey/valkey:8
|
34
47
|
# ports:
|
35
48
|
# - 6379:6379
|
36
49
|
# options: --health-cmd "redis-cli ping" --health-interval 10s --health-timeout 5s --health-retries 5
|
@@ -56,18 +69,15 @@ jobs:
|
|
56
69
|
<%- end -%>
|
57
70
|
|
58
71
|
# redis:
|
59
|
-
# image:
|
72
|
+
# image: valkey/valkey:8
|
60
73
|
# ports:
|
61
74
|
# - 6379:6379
|
62
75
|
# options: --health-cmd "redis-cli ping" --health-interval 10s --health-timeout 5s --health-retries 5
|
63
76
|
|
64
77
|
<%- end -%>
|
65
78
|
steps:
|
66
|
-
- name: Install packages
|
67
|
-
run: sudo apt-get update && sudo apt-get install --no-install-recommends -y <%= ci_packages.join(" ") %>
|
68
|
-
|
69
79
|
- name: Checkout code
|
70
|
-
uses: actions/checkout@
|
80
|
+
uses: actions/checkout@v5
|
71
81
|
|
72
82
|
- name: Set up Ruby
|
73
83
|
uses: ruby/setup-ruby@v1
|
@@ -91,6 +101,7 @@ jobs:
|
|
91
101
|
<%- elsif options[:database] == "postgresql" -%>
|
92
102
|
DATABASE_URL: postgres://postgres:postgres@localhost:5432
|
93
103
|
<%- end -%>
|
104
|
+
# RAILS_MASTER_KEY: ${{ secrets.RAILS_MASTER_KEY }}
|
94
105
|
# REDIS_URL: redis://localhost:6379/0
|
95
106
|
run: <%= test_command %>
|
96
107
|
|
@@ -3,10 +3,10 @@ updates:
|
|
3
3
|
- package-ecosystem: bundler
|
4
4
|
directory: "/"
|
5
5
|
schedule:
|
6
|
-
interval:
|
6
|
+
interval: weekly
|
7
7
|
open-pull-requests-limit: 10
|
8
8
|
- package-ecosystem: github-actions
|
9
9
|
directory: "/"
|
10
10
|
schedule:
|
11
|
-
interval:
|
11
|
+
interval: weekly
|
12
12
|
open-pull-requests-limit: 10
|
@@ -10,8 +10,9 @@ module TestUnit # :nodoc:
|
|
10
10
|
template "test/models/user_test.rb"
|
11
11
|
end
|
12
12
|
|
13
|
-
def
|
14
|
-
template "test/
|
13
|
+
def create_controller_test_files
|
14
|
+
template "test/controllers/sessions_controller_test.rb"
|
15
|
+
template "test/controllers/passwords_controller_test.rb"
|
15
16
|
end
|
16
17
|
end
|
17
18
|
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
require "test_helper"
|
2
|
+
|
3
|
+
class PasswordsControllerTest < ActionDispatch::IntegrationTest
|
4
|
+
setup { @user = User.take }
|
5
|
+
|
6
|
+
test "new" do
|
7
|
+
get new_password_path
|
8
|
+
assert_response :success
|
9
|
+
end
|
10
|
+
|
11
|
+
test "create" do
|
12
|
+
post passwords_path, params: { email_address: @user.email_address }
|
13
|
+
assert_enqueued_email_with PasswordsMailer, :reset, args: [ @user ]
|
14
|
+
assert_redirected_to new_session_path
|
15
|
+
|
16
|
+
follow_redirect!
|
17
|
+
assert_notice "reset instructions sent"
|
18
|
+
end
|
19
|
+
|
20
|
+
test "create for an unknown user redirects but sends no mail" do
|
21
|
+
post passwords_path, params: { email_address: "missing-user@example.com" }
|
22
|
+
assert_enqueued_emails 0
|
23
|
+
assert_redirected_to new_session_path
|
24
|
+
|
25
|
+
follow_redirect!
|
26
|
+
assert_notice "reset instructions sent"
|
27
|
+
end
|
28
|
+
|
29
|
+
test "edit" do
|
30
|
+
get edit_password_path(@user.password_reset_token)
|
31
|
+
assert_response :success
|
32
|
+
end
|
33
|
+
|
34
|
+
test "edit with invalid password reset token" do
|
35
|
+
get edit_password_path("invalid token")
|
36
|
+
assert_redirected_to new_password_path
|
37
|
+
|
38
|
+
follow_redirect!
|
39
|
+
assert_notice "reset link is invalid"
|
40
|
+
end
|
41
|
+
|
42
|
+
test "update" do
|
43
|
+
assert_changes -> { @user.reload.password_digest } do
|
44
|
+
put password_path(@user.password_reset_token), params: { password: "new", password_confirmation: "new" }
|
45
|
+
assert_redirected_to new_session_path
|
46
|
+
end
|
47
|
+
|
48
|
+
follow_redirect!
|
49
|
+
assert_notice "Password has been reset"
|
50
|
+
end
|
51
|
+
|
52
|
+
test "update with non matching passwords" do
|
53
|
+
token = @user.password_reset_token
|
54
|
+
assert_no_changes -> { @user.reload.password_digest } do
|
55
|
+
put password_path(token), params: { password: "no", password_confirmation: "match" }
|
56
|
+
assert_redirected_to edit_password_path(token)
|
57
|
+
end
|
58
|
+
|
59
|
+
follow_redirect!
|
60
|
+
assert_notice "Passwords did not match"
|
61
|
+
end
|
62
|
+
|
63
|
+
private
|
64
|
+
def assert_notice(text)
|
65
|
+
assert_select "div", /#{text}/
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require "test_helper"
|
2
|
+
|
3
|
+
class SessionsControllerTest < ActionDispatch::IntegrationTest
|
4
|
+
setup { @user = User.take }
|
5
|
+
|
6
|
+
test "new" do
|
7
|
+
get new_session_path
|
8
|
+
assert_response :success
|
9
|
+
end
|
10
|
+
|
11
|
+
test "create with valid credentials" do
|
12
|
+
post session_path, params: { email_address: @user.email_address, password: "password" }
|
13
|
+
|
14
|
+
assert_redirected_to root_path
|
15
|
+
assert cookies[:session_id]
|
16
|
+
end
|
17
|
+
|
18
|
+
test "create with invalid credentials" do
|
19
|
+
post session_path, params: { email_address: @user.email_address, password: "wrong" }
|
20
|
+
|
21
|
+
assert_redirected_to new_session_path
|
22
|
+
assert_nil cookies[:session_id]
|
23
|
+
end
|
24
|
+
|
25
|
+
test "destroy" do
|
26
|
+
sign_in_as(User.take)
|
27
|
+
|
28
|
+
delete session_path
|
29
|
+
|
30
|
+
assert_redirected_to new_session_path
|
31
|
+
assert_empty cookies[:session_id]
|
32
|
+
end
|
33
|
+
end
|
@@ -1,7 +1,8 @@
|
|
1
1
|
require "test_helper"
|
2
2
|
|
3
3
|
class UserTest < ActiveSupport::TestCase
|
4
|
-
|
5
|
-
|
6
|
-
|
4
|
+
test "downcases and strips email_address" do
|
5
|
+
user = User.new(email_address: " DOWNCASED@EXAMPLE.COM ")
|
6
|
+
assert_equal("downcased@example.com", user.email_address)
|
7
|
+
end
|
7
8
|
end
|
@@ -4,7 +4,7 @@
|
|
4
4
|
<%= name %>:
|
5
5
|
<% attributes.each do |attribute| -%>
|
6
6
|
<%- if attribute.password_digest? -%>
|
7
|
-
password_digest:
|
7
|
+
password_digest: <%= BCrypt::Password.create("secret") %> # Generated with BCrypt::Password.create("secret")
|
8
8
|
<%- elsif attribute.reference? -%>
|
9
9
|
<%= yaml_key_value(attribute.column_name.delete_suffix("_id"), attribute.default || name) %>
|
10
10
|
<%- elsif !attribute.virtual? -%>
|
@@ -1,11 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "active_support/core_ext/class/attribute"
|
4
|
-
require "active_support/core_ext/module/delegation"
|
5
3
|
require "active_support/core_ext/hash/reverse_merge"
|
6
4
|
require "active_support/core_ext/kernel/reporting"
|
7
5
|
require "active_support/testing/stream"
|
8
|
-
require "active_support/concern"
|
9
6
|
require "rails/generators"
|
10
7
|
|
11
8
|
module Rails
|
data/lib/rails/generators.rb
CHANGED
@@ -43,11 +43,17 @@ module Rails
|
|
43
43
|
|
44
44
|
private
|
45
45
|
def render_up
|
46
|
-
|
46
|
+
respond_to do |format|
|
47
|
+
format.html { render html: html_status(color: "green") }
|
48
|
+
format.json { render json: { status: "up", timestamp: Time.current.iso8601 } }
|
49
|
+
end
|
47
50
|
end
|
48
51
|
|
49
52
|
def render_down
|
50
|
-
|
53
|
+
respond_to do |format|
|
54
|
+
format.html { render html: html_status(color: "red"), status: 500 }
|
55
|
+
format.json { render json: { status: "down", timestamp: Time.current.iso8601 }, status: 500 }
|
56
|
+
end
|
51
57
|
end
|
52
58
|
|
53
59
|
def html_status(color:)
|
data/lib/rails/info.rb
CHANGED
@@ -1,7 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "
|
4
|
-
require "cgi/util" if RUBY_VERSION < "3.5"
|
3
|
+
require "active_support/core_ext/erb/util"
|
5
4
|
|
6
5
|
module Rails
|
7
6
|
# This module helps build the runtime properties that are displayed in
|
@@ -44,11 +43,11 @@ module Rails
|
|
44
43
|
def to_html
|
45
44
|
(+"<table>").tap do |table|
|
46
45
|
properties.each do |(name, value)|
|
47
|
-
table << %(<tr><td class="name">#{
|
46
|
+
table << %(<tr><td class="name">#{ERB::Util.html_escape(name.to_s)}</td>)
|
48
47
|
formatted_value = if value.kind_of?(Array)
|
49
|
-
"<ul>" + value.map { |v| "<li>#{
|
48
|
+
"<ul>" + value.map { |v| "<li>#{ERB::Util.html_escape(v.to_s)}</li>" }.join + "</ul>"
|
50
49
|
else
|
51
|
-
|
50
|
+
ERB::Util.html_escape(value.to_s)
|
52
51
|
end
|
53
52
|
table << %(<td class="value">#{formatted_value}</td></tr>)
|
54
53
|
end
|
@@ -33,9 +33,8 @@ class Rails::InfoController < Rails::ApplicationController # :nodoc:
|
|
33
33
|
end
|
34
34
|
|
35
35
|
def notes
|
36
|
-
|
37
|
-
|
38
|
-
).find(
|
36
|
+
tags = params[:tag].presence || Rails::SourceAnnotationExtractor::Annotation.tags.join("|")
|
37
|
+
@annotations = Rails::SourceAnnotationExtractor.new(tags).find(
|
39
38
|
Rails::SourceAnnotationExtractor::Annotation.directories
|
40
39
|
)
|
41
40
|
end
|
data/lib/rails/initializable.rb
CHANGED
@@ -9,23 +9,15 @@ module Rails
|
|
9
9
|
end
|
10
10
|
|
11
11
|
class Initializer
|
12
|
-
attr_reader :name, :block
|
12
|
+
attr_reader :name, :block, :before, :after
|
13
13
|
|
14
|
-
def initialize(name, context,
|
15
|
-
|
16
|
-
@name, @
|
17
|
-
end
|
18
|
-
|
19
|
-
def before
|
20
|
-
@options[:before]
|
21
|
-
end
|
22
|
-
|
23
|
-
def after
|
24
|
-
@options[:after]
|
14
|
+
def initialize(name, context, before:, after:, group: nil, &block)
|
15
|
+
@group = group || :default
|
16
|
+
@name, @before, @after, @context, @block = name, before, after, context, block
|
25
17
|
end
|
26
18
|
|
27
19
|
def belongs_to?(group)
|
28
|
-
@
|
20
|
+
@group == group || @group == :all
|
29
21
|
end
|
30
22
|
|
31
23
|
def run(*args)
|
@@ -34,7 +26,7 @@ module Rails
|
|
34
26
|
|
35
27
|
def bind(context)
|
36
28
|
return self if @context
|
37
|
-
Initializer.new(@name, context, @
|
29
|
+
Initializer.new(@name, context, before:, after:, group: @group, &block)
|
38
30
|
end
|
39
31
|
|
40
32
|
def context_class
|
@@ -42,16 +34,66 @@ module Rails
|
|
42
34
|
end
|
43
35
|
end
|
44
36
|
|
45
|
-
class Collection
|
37
|
+
class Collection
|
38
|
+
include Enumerable
|
46
39
|
include TSort
|
47
40
|
|
41
|
+
delegate_missing_to :@collection
|
42
|
+
|
43
|
+
def initialize(initializers = nil)
|
44
|
+
@order = Hash.new { |hash, key| hash[key] = Set.new }
|
45
|
+
@resolve = Hash.new { |hash, key| hash[key] = Set.new }
|
46
|
+
@collection = []
|
47
|
+
concat(initializers) if initializers
|
48
|
+
end
|
49
|
+
|
50
|
+
def to_a
|
51
|
+
@collection
|
52
|
+
end
|
53
|
+
|
54
|
+
def last
|
55
|
+
@collection.last
|
56
|
+
end
|
57
|
+
|
58
|
+
def each(&block)
|
59
|
+
@collection.each(&block)
|
60
|
+
end
|
61
|
+
|
48
62
|
alias :tsort_each_node :each
|
49
63
|
def tsort_each_child(initializer, &block)
|
50
|
-
|
64
|
+
@order[initializer.name].each do |name|
|
65
|
+
@resolve[name].each(&block)
|
66
|
+
end
|
51
67
|
end
|
52
68
|
|
53
69
|
def +(other)
|
54
|
-
|
70
|
+
dup.concat(other.to_a)
|
71
|
+
end
|
72
|
+
|
73
|
+
def <<(initializer)
|
74
|
+
@collection << initializer
|
75
|
+
@order[initializer.before] << initializer.name if initializer.before
|
76
|
+
@order[initializer.name] << initializer.after if initializer.after
|
77
|
+
@resolve[initializer.name] << initializer
|
78
|
+
self
|
79
|
+
end
|
80
|
+
|
81
|
+
def push(*initializers)
|
82
|
+
initializers.each(&method(:<<))
|
83
|
+
self
|
84
|
+
end
|
85
|
+
|
86
|
+
alias_method(:append, :push)
|
87
|
+
|
88
|
+
def concat(*initializer_collections)
|
89
|
+
initializer_collections.each do |initializers|
|
90
|
+
initializers.each(&method(:<<))
|
91
|
+
end
|
92
|
+
self
|
93
|
+
end
|
94
|
+
|
95
|
+
def has?(name)
|
96
|
+
@resolve.key?(name)
|
55
97
|
end
|
56
98
|
end
|
57
99
|
|
@@ -87,8 +129,10 @@ module Rails
|
|
87
129
|
|
88
130
|
def initializer(name, opts = {}, &blk)
|
89
131
|
raise ArgumentError, "A block must be passed when defining an initializer" unless blk
|
90
|
-
opts[:after] ||= initializers.last
|
91
|
-
initializers << Initializer.new(
|
132
|
+
opts[:after] ||= initializers.last&.name unless initializers.has?(opts[:before])
|
133
|
+
initializers << Initializer.new(
|
134
|
+
name, nil, before: opts[:before], after: opts[:after], group: opts[:group], &blk
|
135
|
+
)
|
92
136
|
end
|
93
137
|
end
|
94
138
|
end
|
@@ -10,11 +10,14 @@ module Rails
|
|
10
10
|
# This is useful for preventing recurring requests like health checks from clogging the logging.
|
11
11
|
# This middleware is used to do just that against the path /up in production by default.
|
12
12
|
#
|
13
|
-
#
|
13
|
+
# Examples:
|
14
14
|
#
|
15
15
|
# config.middleware.insert_before \
|
16
16
|
# Rails::Rack::Logger, Rails::Rack::SilenceRequest, path: "/up"
|
17
17
|
#
|
18
|
+
# config.middleware.insert_before \
|
19
|
+
# Rails::Rack::Logger, Rails::Rack::SilenceRequest, path: /test$/
|
20
|
+
#
|
18
21
|
# This middleware can also be configured using `config.silence_healthcheck_path = "/up"` in Rails.
|
19
22
|
class SilenceRequest
|
20
23
|
def initialize(app, path:)
|
@@ -22,7 +25,7 @@ module Rails
|
|
22
25
|
end
|
23
26
|
|
24
27
|
def call(env)
|
25
|
-
if env["PATH_INFO"]
|
28
|
+
if @path === env["PATH_INFO"]
|
26
29
|
Rails.logger.silence { @app.call(env) }
|
27
30
|
else
|
28
31
|
@app.call(env)
|
data/lib/rails/railtie.rb
CHANGED
@@ -4,7 +4,6 @@ require "rails/initializable"
|
|
4
4
|
require "active_support/descendants_tracker"
|
5
5
|
require "active_support/inflector"
|
6
6
|
require "active_support/core_ext/module/introspection"
|
7
|
-
require "active_support/core_ext/module/delegation"
|
8
7
|
|
9
8
|
module Rails
|
10
9
|
# +Rails::Railtie+ is the core of the \Rails framework and provides
|
@@ -33,12 +33,35 @@
|
|
33
33
|
background: #282828;
|
34
34
|
}
|
35
35
|
}
|
36
|
+
|
37
|
+
.filter {
|
38
|
+
display: flex;
|
39
|
+
width: 100%;
|
40
|
+
justify-content: flex-end;
|
41
|
+
align-items: center;
|
42
|
+
}
|
43
|
+
|
44
|
+
.filter label[for="tag"] {
|
45
|
+
margin-right: 10px;
|
46
|
+
}
|
47
|
+
|
48
|
+
.filter select[name="tag"] {
|
49
|
+
border-radius: 8px;
|
50
|
+
padding: 0.25em;
|
51
|
+
}
|
36
52
|
</style>
|
37
53
|
|
38
54
|
<h2>
|
39
55
|
Notes
|
40
56
|
</h2>
|
41
57
|
|
58
|
+
<div class="filter">
|
59
|
+
<%= form_tag("/rails/info/notes", method: :get) do %>
|
60
|
+
<%= label_tag :tag, "Filter by Tag:" %>
|
61
|
+
<%= select_tag(:tag, options_for_select(Rails::SourceAnnotationExtractor::Annotation.tags, params[:tag]), { include_blank: "All", onchange: "this.form.submit();" }) %>
|
62
|
+
<% end %>
|
63
|
+
</div>
|
64
|
+
|
42
65
|
<table id="route_table" class="table">
|
43
66
|
<thead>
|
44
67
|
<th>File Name</th>
|
@@ -9,6 +9,8 @@
|
|
9
9
|
|
10
10
|
body {
|
11
11
|
margin: 0;
|
12
|
+
display: flex;
|
13
|
+
flex-direction: column;
|
12
14
|
}
|
13
15
|
|
14
16
|
header {
|
@@ -18,7 +20,6 @@
|
|
18
20
|
background: white;
|
19
21
|
font: 12px "Lucida Grande", sans-serif;
|
20
22
|
border-bottom: 1px solid #dedede;
|
21
|
-
overflow: hidden;
|
22
23
|
}
|
23
24
|
|
24
25
|
dl {
|
@@ -155,7 +156,7 @@
|
|
155
156
|
<% end %>
|
156
157
|
|
157
158
|
<dt>EML File:</dt>
|
158
|
-
<dd><%= link_to "Download", action: :download
|
159
|
+
<dd><%= link_to "Download", action: :download %></dd>
|
159
160
|
</dl>
|
160
161
|
</header>
|
161
162
|
|