railties 7.2.1 → 8.0.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.
Files changed (104) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +111 -287
  3. data/lib/minitest/rails_plugin.rb +1 -1
  4. data/lib/rails/application/configuration.rb +15 -2
  5. data/lib/rails/application/default_middleware_stack.rb +4 -0
  6. data/lib/rails/application/finisher.rb +2 -2
  7. data/lib/rails/application/routes_reloader.rb +11 -1
  8. data/lib/rails/application.rb +5 -0
  9. data/lib/rails/code_statistics.rb +128 -86
  10. data/lib/rails/code_statistics_calculator.rb +78 -76
  11. data/lib/rails/command/helpers/editor.rb +1 -1
  12. data/lib/rails/commands/app/update_command.rb +1 -9
  13. data/lib/rails/commands/credentials/USAGE +4 -4
  14. data/lib/rails/commands/credentials/credentials_command.rb +5 -1
  15. data/lib/rails/commands/dev/dev_command.rb +1 -1
  16. data/lib/rails/commands/devcontainer/devcontainer_command.rb +1 -1
  17. data/lib/rails/commands/stats/stats_command.rb +19 -0
  18. data/lib/rails/dev_caching.rb +2 -2
  19. data/lib/rails/engine/configuration.rb +3 -1
  20. data/lib/rails/engine/lazy_route_set.rb +109 -0
  21. data/lib/rails/engine.rb +10 -5
  22. data/lib/rails/gem_version.rb +4 -4
  23. data/lib/rails/generators/app_base.rb +46 -24
  24. data/lib/rails/generators/database.rb +101 -67
  25. data/lib/rails/generators/erb/authentication/authentication_generator.rb +15 -0
  26. data/lib/rails/generators/erb/authentication/templates/views/passwords/edit.html.erb +9 -0
  27. data/lib/rails/generators/erb/authentication/templates/views/passwords/new.html.erb +8 -0
  28. data/lib/rails/generators/erb/authentication/templates/views/sessions/new.html.erb +11 -0
  29. data/lib/rails/generators/generated_attribute.rb +16 -11
  30. data/lib/rails/generators/rails/app/app_generator.rb +19 -32
  31. data/lib/rails/generators/rails/app/templates/Dockerfile.tt +12 -3
  32. data/lib/rails/generators/rails/app/templates/Gemfile.tt +23 -8
  33. data/lib/rails/generators/rails/app/templates/app/assets/stylesheets/application.css.tt +6 -11
  34. data/lib/rails/generators/rails/app/templates/app/views/layouts/application.html.erb.tt +10 -3
  35. data/lib/rails/generators/rails/app/templates/bin/dev.tt +1 -0
  36. data/lib/rails/generators/rails/app/templates/bin/setup.tt +5 -7
  37. data/lib/rails/generators/rails/app/templates/bin/thrust.tt +4 -0
  38. data/lib/rails/generators/rails/app/templates/config/databases/mysql.yml.tt +23 -0
  39. data/lib/rails/generators/rails/app/templates/config/databases/postgresql.yml.tt +23 -0
  40. data/lib/rails/generators/rails/app/templates/config/databases/sqlite3.yml.tt +40 -0
  41. data/lib/rails/generators/rails/app/templates/config/databases/trilogy.yml.tt +23 -0
  42. data/lib/rails/generators/rails/app/templates/config/deploy.yml.tt +124 -0
  43. data/lib/rails/generators/rails/app/templates/config/environments/development.rb.tt +12 -23
  44. data/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt +34 -51
  45. data/lib/rails/generators/rails/app/templates/config/environments/test.rb.tt +5 -19
  46. data/lib/rails/generators/rails/app/templates/config/initializers/assets.rb.tt +0 -7
  47. data/lib/rails/generators/rails/app/templates/config/initializers/filter_parameter_logging.rb.tt +1 -1
  48. data/lib/rails/generators/rails/app/templates/config/initializers/new_framework_defaults_8_0.rb.tt +25 -0
  49. data/lib/rails/generators/rails/app/templates/config/puma.rb.tt +11 -2
  50. data/lib/rails/generators/rails/app/templates/config/routes.rb.tt +3 -3
  51. data/lib/rails/generators/rails/app/templates/docker-entrypoint.tt +4 -3
  52. data/lib/rails/generators/rails/app/templates/dockerignore.tt +1 -2
  53. data/lib/rails/generators/rails/app/templates/github/ci.yml.tt +1 -1
  54. data/lib/rails/generators/rails/app/templates/gitignore.tt +1 -2
  55. data/lib/rails/generators/rails/app/templates/kamal-secrets.tt +17 -0
  56. data/lib/rails/generators/rails/app/templates/public/400.html +114 -0
  57. data/lib/rails/generators/rails/app/templates/public/404.html +113 -66
  58. data/lib/rails/generators/rails/app/templates/public/406-unsupported-browser.html +113 -65
  59. data/lib/rails/generators/rails/app/templates/public/422.html +113 -66
  60. data/lib/rails/generators/rails/app/templates/public/500.html +113 -65
  61. data/lib/rails/generators/rails/app/templates/public/icon.png +0 -0
  62. data/lib/rails/generators/rails/app/templates/public/icon.svg +2 -2
  63. data/lib/rails/generators/rails/authentication/USAGE +6 -0
  64. data/lib/rails/generators/rails/authentication/authentication_generator.rb +54 -0
  65. data/lib/rails/generators/rails/authentication/templates/controllers/concerns/authentication.rb +55 -0
  66. data/lib/rails/generators/rails/authentication/templates/controllers/passwords_controller.rb +33 -0
  67. data/lib/rails/generators/rails/authentication/templates/controllers/sessions_controller.rb +21 -0
  68. data/lib/rails/generators/rails/authentication/templates/mailers/passwords_mailer.rb +6 -0
  69. data/lib/rails/generators/rails/authentication/templates/models/current.rb +4 -0
  70. data/lib/rails/generators/rails/authentication/templates/models/session.rb +3 -0
  71. data/lib/rails/generators/rails/authentication/templates/models/user.rb +6 -0
  72. data/lib/rails/generators/rails/authentication/templates/test/mailers/previews/passwords_mailer_preview.rb +7 -0
  73. data/lib/rails/generators/rails/authentication/templates/views/passwords_mailer/reset.html.erb +4 -0
  74. data/lib/rails/generators/rails/authentication/templates/views/passwords_mailer/reset.text.erb +2 -0
  75. data/lib/rails/generators/rails/credentials/templates/credentials.yml.tt +4 -0
  76. data/lib/rails/generators/rails/db/system/change/change_generator.rb +1 -1
  77. data/lib/rails/generators/rails/devcontainer/devcontainer_generator.rb +5 -3
  78. data/lib/rails/generators/rails/devcontainer/templates/devcontainer/devcontainer.json.tt +1 -1
  79. data/lib/rails/generators/rails/plugin/plugin_generator.rb +11 -11
  80. data/lib/rails/generators/rails/plugin/templates/github/ci.yml.tt +1 -1
  81. data/lib/rails/generators/rails/plugin/templates/test/test_helper.rb.tt +2 -2
  82. data/lib/rails/generators/rails/scaffold_controller/templates/api_controller.rb.tt +2 -2
  83. data/lib/rails/generators/rails/scaffold_controller/templates/controller.rb.tt +3 -3
  84. data/lib/rails/generators/rails/script/USAGE +18 -0
  85. data/lib/rails/generators/rails/script/script_generator.rb +18 -0
  86. data/lib/rails/generators/rails/script/templates/script.rb.tt +3 -0
  87. data/lib/rails/generators.rb +7 -2
  88. data/lib/rails/info_controller.rb +10 -2
  89. data/lib/rails/rack/silence_request.rb +33 -0
  90. data/lib/rails/rack.rb +1 -0
  91. data/lib/rails/railtie.rb +13 -13
  92. data/lib/rails/source_annotation_extractor.rb +31 -14
  93. data/lib/rails/tasks/statistics.rake +13 -28
  94. data/lib/rails/templates/rails/info/notes.html.erb +65 -0
  95. metadata +45 -25
  96. data/lib/rails/generators/rails/app/templates/app/assets/config/manifest.js.tt +0 -2
  97. data/lib/rails/generators/rails/app/templates/app/channels/application_cable/channel.rb.tt +0 -4
  98. data/lib/rails/generators/rails/app/templates/app/channels/application_cable/connection.rb.tt +0 -4
  99. data/lib/rails/generators/rails/app/templates/config/initializers/new_framework_defaults_7_2.rb.tt +0 -70
  100. data/lib/rails/generators/rails/app/templates/config/initializers/permissions_policy.rb.tt +0 -13
  101. data/lib/rails/generators/rails/app/templates/test/channels/application_cable/connection_test.rb.tt +0 -13
  102. data/lib/rails/generators/rails/plugin/templates/rails/dummy_manifest.js.tt +0 -10
  103. data/lib/rails/generators/rails/plugin/templates/rails/engine_manifest.js.tt +0 -6
  104. data/lib/rails/generators/rails/plugin/templates/rails/javascripts.js.tt +0 -17
@@ -1,66 +1,114 @@
1
- <!DOCTYPE html>
2
- <html>
3
- <head>
4
- <title>We're sorry, but something went wrong (500)</title>
5
- <meta name="viewport" content="width=device-width,initial-scale=1">
6
- <style>
7
- .rails-default-error-page {
8
- background-color: #EFEFEF;
9
- color: #2E2F30;
10
- text-align: center;
11
- font-family: arial, sans-serif;
12
- margin: 0;
13
- }
14
-
15
- .rails-default-error-page div.dialog {
16
- width: 95%;
17
- max-width: 33em;
18
- margin: 4em auto 0;
19
- }
20
-
21
- .rails-default-error-page div.dialog > div {
22
- border: 1px solid #CCC;
23
- border-right-color: #999;
24
- border-left-color: #999;
25
- border-bottom-color: #BBB;
26
- border-top: #B00100 solid 4px;
27
- border-top-left-radius: 9px;
28
- border-top-right-radius: 9px;
29
- background-color: white;
30
- padding: 7px 12% 0;
31
- box-shadow: 0 3px 8px rgba(50, 50, 50, 0.17);
32
- }
33
-
34
- .rails-default-error-page h1 {
35
- font-size: 100%;
36
- color: #730E15;
37
- line-height: 1.5em;
38
- }
39
-
40
- .rails-default-error-page div.dialog > p {
41
- margin: 0 0 1em;
42
- padding: 1em;
43
- background-color: #F7F7F7;
44
- border: 1px solid #CCC;
45
- border-right-color: #999;
46
- border-left-color: #999;
47
- border-bottom-color: #999;
48
- border-bottom-left-radius: 4px;
49
- border-bottom-right-radius: 4px;
50
- border-top-color: #DADADA;
51
- color: #666;
52
- box-shadow: 0 3px 8px rgba(50, 50, 50, 0.17);
53
- }
54
- </style>
55
- </head>
56
-
57
- <body class="rails-default-error-page">
58
- <!-- This file lives in public/500.html -->
59
- <div class="dialog">
60
- <div>
61
- <h1>We're sorry, but something went wrong.</h1>
62
- </div>
63
- <p>If you are the application owner check the logs for more information.</p>
64
- </div>
65
- </body>
1
+ <!doctype html>
2
+
3
+ <html lang="en">
4
+
5
+ <head>
6
+
7
+ <title>We’re sorry, but something went wrong (500 Internal Server Error)</title>
8
+
9
+ <meta charset="utf-8">
10
+ <meta name="viewport" content="initial-scale=1, width=device-width">
11
+ <meta name="robots" content="noindex, nofollow">
12
+
13
+ <style>
14
+
15
+ *, *::before, *::after {
16
+ box-sizing: border-box;
17
+ }
18
+
19
+ * {
20
+ margin: 0;
21
+ }
22
+
23
+ html {
24
+ font-size: 16px;
25
+ }
26
+
27
+ body {
28
+ background: #FFF;
29
+ color: #261B23;
30
+ display: grid;
31
+ font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, Aptos, Roboto, "Segoe UI", "Helvetica Neue", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
32
+ font-size: clamp(1rem, 2.5vw, 2rem);
33
+ -webkit-font-smoothing: antialiased;
34
+ font-style: normal;
35
+ font-weight: 400;
36
+ letter-spacing: -0.0025em;
37
+ line-height: 1.4;
38
+ min-height: 100vh;
39
+ place-items: center;
40
+ text-rendering: optimizeLegibility;
41
+ -webkit-text-size-adjust: 100%;
42
+ }
43
+
44
+ a {
45
+ color: inherit;
46
+ font-weight: 700;
47
+ text-decoration: underline;
48
+ text-underline-offset: 0.0925em;
49
+ }
50
+
51
+ b, strong {
52
+ font-weight: 700;
53
+ }
54
+
55
+ i, em {
56
+ font-style: italic;
57
+ }
58
+
59
+ main {
60
+ display: grid;
61
+ gap: 1em;
62
+ padding: 2em;
63
+ place-items: center;
64
+ text-align: center;
65
+ }
66
+
67
+ main header {
68
+ width: min(100%, 12em);
69
+ }
70
+
71
+ main header svg {
72
+ height: auto;
73
+ max-width: 100%;
74
+ width: 100%;
75
+ }
76
+
77
+ main article {
78
+ width: min(100%, 30em);
79
+ }
80
+
81
+ main article p {
82
+ font-size: 75%;
83
+ }
84
+
85
+ main article br {
86
+
87
+ display: none;
88
+
89
+ @media(min-width: 48em) {
90
+ display: inline;
91
+ }
92
+
93
+ }
94
+
95
+ </style>
96
+
97
+ </head>
98
+
99
+ <body>
100
+
101
+ <!-- This file lives in public/500.html -->
102
+
103
+ <main>
104
+ <header>
105
+ <svg height="172" viewBox="0 0 480 172" width="480" xmlns="http://www.w3.org/2000/svg"><path d="m101.23 93.8427c-8.1103 0-15.4098 3.7849-19.7354 8.3813h-36.2269v-99.21891h103.8143v37.03791h-68.3984v24.8722c5.1366-2.7035 15.1396-5.9477 24.6014-5.9477 35.146 0 56.233 22.7094 56.233 55.4215 0 34.605-23.791 57.315-60.558 57.315-37.8492 0-61.64-22.169-63.8028-55.963h42.9857c1.0814 10.814 9.1919 19.195 21.6281 19.195 11.355 0 19.465-8.381 19.465-20.547 0-11.625-7.299-20.5463-20.006-20.5463zm138.833 77.8613c-40.822 0-64.884-35.146-64.884-85.7015 0-50.5554 24.062-85.700907 64.884-85.700907 40.823 0 64.884 35.145507 64.884 85.700907 0 50.5555-24.061 85.7015-64.884 85.7015zm0-133.2831c-17.572 0-22.709 21.8984-22.709 47.5816 0 25.6835 5.137 47.5815 22.709 47.5815 17.303 0 22.71-21.898 22.71-47.5815 0-25.6832-5.407-47.5816-22.71-47.5816zm140.456 133.2831c-40.823 0-64.884-35.146-64.884-85.7015 0-50.5554 24.061-85.700907 64.884-85.700907 40.822 0 64.884 35.145507 64.884 85.700907 0 50.5555-24.062 85.7015-64.884 85.7015zm0-133.2831c-17.573 0-22.71 21.8984-22.71 47.5816 0 25.6835 5.137 47.5815 22.71 47.5815 17.302 0 22.709-21.898 22.709-47.5815 0-25.6832-5.407-47.5816-22.709-47.5816z" fill="#f0eff0"/><path d="m23.1377 68.9967v34.0033h-8.9162v-34.0033zm4.3157 34.0033v-24.921h8.6947v2.1598c1.3845-1.5506 3.8212-2.7136 6.701-2.7136 5.538 0 8.8054 3.5997 8.8054 9.1377v16.3371h-8.6393v-14.2327c0-2.049-1.0522-3.5443-3.2674-3.5443-1.7168 0-3.1567.9969-3.5997 2.7136v15.0634zm29.9913-8.5839v-9.5807h-3.655v-6.7564h3.655v-6.8671h8.5839v6.8671h5.2058v6.7564h-5.2058v8.307c0 1.9383.9415 2.769 2.6583 2.769.9414 0 1.9937-.2216 2.769-.5538v7.3654c-.9969.443-2.8798.775-4.8181.775-5.8703 0-9.1931-2.769-9.1931-9.0819zm32.3666-.1108h8.0301c-.8861 5.7597-5.2057 9.2487-11.6852 9.2487-7.6424 0-12.682-5.2613-12.682-13.0145 0-7.6978 5.3165-13.0143 12.5159-13.0143 7.6424 0 11.9621 5.095 11.9621 12.5159v2.1598h-16.1156c.2769 2.9905 1.8275 4.5965 4.3196 4.5965 1.7722 0 3.1567-.7753 3.6551-2.4921zm-3.8212-10.0237c-2.0491 0-3.4336 1.2737-3.9874 3.5997h7.5317c-.1107-2.0491-1.3845-3.5997-3.5443-3.5997zm31.4299-6.3134v8.3624c-1.052-.5538-2.215-.7753-3.599-.7753-2.382 0-3.988 1.0522-4.431 2.8244v14.6203h-8.694v-24.921h8.694v2.2152c1.219-1.6614 3.157-2.769 5.649-2.769 1.108 0 1.994.2215 2.381.443zm2.949 25.0318v-24.921h8.694v2.1598c1.385-1.5506 3.821-2.7136 6.701-2.7136 5.538 0 8.806 3.5997 8.806 9.1377v16.3371h-8.64v-14.2327c0-2.049-1.052-3.5443-3.267-3.5443-1.717 0-3.157.9969-3.6 2.7136v15.0634zm50.371 0h-8.363v-1.274c-.83.831-3.323 1.717-5.981 1.717-4.929 0-9.082-2.769-9.082-8.0301 0-4.818 4.153-7.9193 9.581-7.9193 2.049 0 4.485.6646 5.482 1.3845v-1.606c0-1.606-.941-2.9905-3.046-2.9905-1.606 0-2.547.7199-2.935 1.8275h-8.196c.72-4.8181 4.984-8.6393 11.408-8.6393 7.089 0 11.132 3.7659 11.132 10.2453zm-8.363-6.9779v-1.4399c-.554-1.0522-2.049-1.7167-3.655-1.7167-1.717 0-3.433.7199-3.433 2.3813 0 1.7168 1.716 2.4367 3.433 2.4367 1.606 0 3.101-.6645 3.655-1.6614zm20.742-29.0191v35.997h-8.694v-35.997zm13.036 25.9178h9.248c.72 2.326 2.714 3.489 5.483 3.489 2.713 0 4.596-1.163 4.596-3.2674 0-1.6061-1.052-2.326-3.212-2.8244l-6.534-1.3845c-4.985-1.1076-8.751-3.7105-8.751-9.47 0-6.6456 5.538-11.0206 13.07-11.0206 8.307 0 13.014 4.5411 13.956 10.4114h-8.695c-.72-1.8829-2.27-3.3228-5.205-3.3228-2.548 0-4.265 1.1076-4.265 2.9905 0 1.4953 1.052 2.326 2.825 2.7137l6.645 1.5506c5.815 1.3845 9.027 4.5412 9.027 9.8023 0 6.9778-5.87 10.9654-13.291 10.9654-8.141 0-13.679-3.9322-14.897-10.6332zm46.509 1.3845h8.031c-.887 5.7597-5.206 9.2487-11.686 9.2487-7.642 0-12.682-5.2613-12.682-13.0145 0-7.6978 5.317-13.0143 12.516-13.0143 7.643 0 11.962 5.095 11.962 12.5159v2.1598h-16.115c.277 2.9905 1.827 4.5965 4.319 4.5965 1.773 0 3.157-.7753 3.655-2.4921zm-3.821-10.0237c-2.049 0-3.433 1.2737-3.987 3.5997h7.532c-.111-2.0491-1.385-3.5997-3.545-3.5997zm31.431-6.3134v8.3624c-1.053-.5538-2.216-.7753-3.6-.7753-2.381 0-3.988 1.0522-4.431 2.8244v14.6203h-8.694v-24.921h8.694v2.2152c1.219-1.6614 3.157-2.769 5.649-2.769 1.108 0 1.994.2215 2.382.443zm18.288 25.0318h-7.809l-9.47-24.921h8.861l4.763 14.288 4.652-14.288h8.528zm25.614-8.6947h8.03c-.886 5.7597-5.206 9.2487-11.685 9.2487-7.642 0-12.682-5.2613-12.682-13.0145 0-7.6978 5.316-13.0143 12.516-13.0143 7.642 0 11.962 5.095 11.962 12.5159v2.1598h-16.116c.277 2.9905 1.828 4.5965 4.32 4.5965 1.772 0 3.157-.7753 3.655-2.4921zm-3.821-10.0237c-2.049 0-3.434 1.2737-3.988 3.5997h7.532c-.111-2.0491-1.384-3.5997-3.544-3.5997zm31.43-6.3134v8.3624c-1.052-.5538-2.215-.7753-3.6-.7753-2.381 0-3.987 1.0522-4.43 2.8244v14.6203h-8.695v-24.921h8.695v2.2152c1.218-1.6614 3.157-2.769 5.649-2.769 1.107 0 1.993.2215 2.381.443zm13.703-8.9715h24.312v7.6424h-15.562v5.3165h14.232v7.4763h-14.232v5.8703h15.562v7.6978h-24.312zm44.667 8.9715v8.3624c-1.052-.5538-2.215-.7753-3.6-.7753-2.381 0-3.987 1.0522-4.43 2.8244v14.6203h-8.695v-24.921h8.695v2.2152c1.218-1.6614 3.156-2.769 5.648-2.769 1.108 0 1.994.2215 2.382.443zm19.673 0v8.3624c-1.053-.5538-2.216-.7753-3.6-.7753-2.381 0-3.987 1.0522-4.43 2.8244v14.6203h-8.695v-24.921h8.695v2.2152c1.218-1.6614 3.156-2.769 5.648-2.769 1.108 0 1.994.2215 2.382.443zm26.769 12.5713c0 7.6978-5.15 13.0145-12.737 13.0145-7.532 0-12.738-5.3167-12.738-13.0145s5.206-13.0143 12.738-13.0143c7.587 0 12.737 5.3165 12.737 13.0143zm-8.529 0c0-3.4336-1.495-5.8703-4.208-5.8703-2.659 0-4.154 2.4367-4.154 5.8703s1.495 5.8149 4.154 5.8149c2.713 0 4.208-2.3813 4.208-5.8149zm28.082-12.5713v8.3624c-1.052-.5538-2.215-.7753-3.6-.7753-2.381 0-3.987 1.0522-4.43 2.8244v14.6203h-8.695v-24.921h8.695v2.2152c1.218-1.6614 3.157-2.769 5.649-2.769 1.107 0 1.993.2215 2.381.443z" fill="#d30001"/></svg>
106
+ </header>
107
+ <article>
108
+ <p><strong>We’re sorry, but something went wrong.</strong><br> If you’re the application owner check the logs for more information.</p>
109
+ </article>
110
+ </main>
111
+
112
+ </body>
113
+
66
114
  </html>
@@ -1,3 +1,3 @@
1
- <svg width="100" height="100" xmlns="http://www.w3.org/2000/svg">
2
- <rect width="100%" height="100%" fill="red"/>
1
+ <svg width="512" height="512" xmlns="http://www.w3.org/2000/svg">
2
+ <circle cx="256" cy="256" r="256" fill="red"/>
3
3
  </svg>
@@ -0,0 +1,6 @@
1
+ Description:
2
+ Generates a basic authentication system with users, sessions, and password reset.
3
+
4
+ Example:
5
+ `bin/rails generate authentication`
6
+
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rails
4
+ module Generators
5
+ class AuthenticationGenerator < Base # :nodoc:
6
+ class_option :api, type: :boolean,
7
+ desc: "Generate API-only controllers and models, with no view templates"
8
+
9
+ hook_for :template_engine, as: :authentication do |template_engine|
10
+ invoke template_engine unless options.api?
11
+ end
12
+
13
+ def create_authentication_files
14
+ template "models/session.rb", File.join("app/models/session.rb")
15
+ template "models/user.rb", File.join("app/models/user.rb")
16
+ template "models/current.rb", File.join("app/models/current.rb")
17
+
18
+ template "controllers/sessions_controller.rb", File.join("app/controllers/sessions_controller.rb")
19
+ template "controllers/concerns/authentication.rb", File.join("app/controllers/concerns/authentication.rb")
20
+ template "controllers/passwords_controller.rb", File.join("app/controllers/passwords_controller.rb")
21
+
22
+ template "mailers/passwords_mailer.rb", File.join("app/mailers/passwords_mailer.rb")
23
+
24
+ template "views/passwords_mailer/reset.html.erb", File.join("app/views/passwords_mailer/reset.html.erb")
25
+ template "views/passwords_mailer/reset.text.erb", File.join("app/views/passwords_mailer/reset.text.erb")
26
+
27
+ template "test/mailers/previews/passwords_mailer_preview.rb", File.join("test/mailers/previews/passwords_mailer_preview.rb")
28
+ end
29
+
30
+ def configure_application_controller
31
+ gsub_file "app/controllers/application_controller.rb", /(class ApplicationController < ActionController::Base)/, "\\1\n include Authentication"
32
+ end
33
+
34
+ def configure_authentication_routes
35
+ route "resources :passwords, param: :token"
36
+ route "resource :session"
37
+ end
38
+
39
+ def enable_bcrypt
40
+ if File.read("Gemfile").include?('gem "bcrypt"')
41
+ uncomment_lines "Gemfile", /gem "bcrypt"/
42
+ Bundler.with_original_env { execute_command :bundle, "install --quiet" }
43
+ else
44
+ Bundler.with_original_env { execute_command :bundle, "add bcrypt --quiet" }
45
+ end
46
+ end
47
+
48
+ def add_migrations
49
+ generate "migration CreateUsers email_address:string!:uniq password_digest:string! --force"
50
+ generate "migration CreateSessions user:references ip_address:string user_agent:string --force"
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,55 @@
1
+ module Authentication
2
+ extend ActiveSupport::Concern
3
+
4
+ included do
5
+ before_action :require_authentication
6
+ helper_method :authenticated?
7
+ end
8
+
9
+ class_methods do
10
+ def allow_unauthenticated_access(**options)
11
+ skip_before_action :require_authentication, **options
12
+ end
13
+ end
14
+
15
+ private
16
+ def authenticated?
17
+ Current.session.present?
18
+ end
19
+
20
+ def require_authentication
21
+ resume_session || request_authentication
22
+ end
23
+
24
+
25
+ def resume_session
26
+ Current.session = find_session_by_cookie
27
+ end
28
+
29
+ def find_session_by_cookie
30
+ Session.find_by(id: cookies.signed[:session_id])
31
+ end
32
+
33
+
34
+ def request_authentication
35
+ session[:return_to_after_authenticating] = request.url
36
+ redirect_to new_session_url
37
+ end
38
+
39
+ def after_authentication_url
40
+ session.delete(:return_to_after_authenticating) || root_url
41
+ end
42
+
43
+
44
+ def start_new_session_for(user)
45
+ user.sessions.create!(user_agent: request.user_agent, ip_address: request.remote_ip).tap do |session|
46
+ Current.session = session
47
+ cookies.signed.permanent[:session_id] = { value: session.id, httponly: true, same_site: :lax }
48
+ end
49
+ end
50
+
51
+ def terminate_session
52
+ Current.session.destroy
53
+ cookies.delete(:session_id)
54
+ end
55
+ end
@@ -0,0 +1,33 @@
1
+ class PasswordsController < ApplicationController
2
+ allow_unauthenticated_access
3
+ before_action :set_user_by_token, only: %i[ edit update ]
4
+
5
+ def new
6
+ end
7
+
8
+ def create
9
+ if user = User.find_by(email_address: params[:email_address])
10
+ PasswordsMailer.reset(user).deliver_later
11
+ end
12
+
13
+ redirect_to new_session_url, notice: "Password reset instructions sent (if user with that email address exists)."
14
+ end
15
+
16
+ def edit
17
+ end
18
+
19
+ def update
20
+ if @user.update(params.permit(:password, :password_confirmation))
21
+ redirect_to new_session_url, notice: "Password has been reset."
22
+ else
23
+ redirect_to edit_password_url(params[:token]), alert: "Passwords did not match."
24
+ end
25
+ end
26
+
27
+ private
28
+ def set_user_by_token
29
+ @user = User.find_by_password_reset_token!(params[:token])
30
+ rescue ActiveSupport::MessageVerifier::InvalidSignature
31
+ redirect_to new_password_url, alert: "Password reset link is invalid or has expired."
32
+ end
33
+ end
@@ -0,0 +1,21 @@
1
+ class SessionsController < ApplicationController
2
+ allow_unauthenticated_access only: %i[ new create ]
3
+ rate_limit to: 10, within: 3.minutes, only: :create, with: -> { redirect_to new_session_url, alert: "Try again later." }
4
+
5
+ def new
6
+ end
7
+
8
+ def create
9
+ if user = User.authenticate_by(params.permit(:email_address, :password))
10
+ start_new_session_for user
11
+ redirect_to after_authentication_url
12
+ else
13
+ redirect_to new_session_url, alert: "Try another email address or password."
14
+ end
15
+ end
16
+
17
+ def destroy
18
+ terminate_session
19
+ redirect_to new_session_url
20
+ end
21
+ end
@@ -0,0 +1,6 @@
1
+ class PasswordsMailer < ApplicationMailer
2
+ def reset(user)
3
+ @user = user
4
+ mail subject: "Reset your password", to: user.email_address
5
+ end
6
+ end
@@ -0,0 +1,4 @@
1
+ class Current < ActiveSupport::CurrentAttributes
2
+ attribute :session
3
+ delegate :user, to: :session, allow_nil: true
4
+ end
@@ -0,0 +1,3 @@
1
+ class Session < ApplicationRecord
2
+ belongs_to :user
3
+ end
@@ -0,0 +1,6 @@
1
+ class User < ApplicationRecord
2
+ has_secure_password
3
+ has_many :sessions, dependent: :destroy
4
+
5
+ normalizes :email_address, with: -> e { e.strip.downcase }
6
+ end
@@ -0,0 +1,7 @@
1
+ # Preview all emails at http://localhost:3000/rails/mailers/passwords_mailer
2
+ class PasswordsMailerPreview < ActionMailer::Preview
3
+ # Preview this email at http://localhost:3000/rails/mailers/passwords_mailer/reset
4
+ def reset
5
+ PasswordsMailer.reset(User.take)
6
+ end
7
+ end
@@ -0,0 +1,4 @@
1
+ <p>
2
+ You can reset your password within the next 15 minutes on
3
+ <%%= link_to "this password reset page", edit_password_url(@user.password_reset_token) %>.
4
+ </p>
@@ -0,0 +1,2 @@
1
+ You can reset your password within the next 15 minutes on this password reset page:
2
+ <%%= edit_password_url(@user.password_reset_token) %>
@@ -1,3 +1,7 @@
1
+ # smtp:
2
+ # user_name: my-smtp-user
3
+ # password: my-smtp-password
4
+ #
1
5
  # aws:
2
6
  # access_key_id: 123
3
7
  # secret_access_key: 345
@@ -35,7 +35,7 @@ module Rails
35
35
  end
36
36
 
37
37
  def edit_database_config
38
- template("config/databases/#{options[:database]}.yml", "config/database.yml")
38
+ template(database.template, "config/database.yml")
39
39
  end
40
40
 
41
41
  def edit_gemfile
@@ -38,9 +38,11 @@ module Rails
38
38
 
39
39
  def update_application_system_test_case
40
40
  return unless options[:system_test]
41
- return unless File.exist?("test/application_system_test_case.rb")
42
41
 
43
- gsub_file("test/application_system_test_case.rb", /^\s*driven_by\b.*/, system_test_configuration)
42
+ system_test_case_path = File.expand_path "test/application_system_test_case.rb", destination_root
43
+ return unless File.exist? system_test_case_path
44
+
45
+ gsub_file(system_test_case_path, /^\s*driven_by\b.*/, system_test_configuration)
44
46
  end
45
47
 
46
48
  def update_database_yml
@@ -148,7 +150,7 @@ module Rails
148
150
  end
149
151
 
150
152
  def system_test_configuration
151
- optimize_indentation(<<-'RUBY', 2)
153
+ optimize_indentation(<<-'RUBY', 2).chomp
152
154
  if ENV["CAPYBARA_SERVER_PORT"]
153
155
  served_by host: "rails-app", port: ENV["CAPYBARA_SERVER_PORT"]
154
156
 
@@ -33,5 +33,5 @@
33
33
  <%- end -%>
34
34
 
35
35
  // Use 'postCreateCommand' to run commands after the container is created.
36
- "postCreateCommand": "bin/setup"
36
+ "postCreateCommand": "bin/setup --skip-server"
37
37
  }
@@ -122,9 +122,12 @@ module Rails
122
122
  def generate_test_dummy(force = false)
123
123
  opts = options.transform_keys(&:to_sym).except(*DUMMY_IGNORE_OPTIONS)
124
124
  opts[:force] = force
125
+ opts[:skip_thruster] = true
125
126
  opts[:skip_brakeman] = true
126
127
  opts[:skip_bundle] = true
127
128
  opts[:skip_ci] = true
129
+ opts[:skip_kamal] = true
130
+ opts[:skip_solid] = true
128
131
  opts[:skip_git] = true
129
132
  opts[:skip_hotwire] = true
130
133
  opts[:skip_rubocop] = true
@@ -149,9 +152,8 @@ module Rails
149
152
  end
150
153
  end
151
154
 
152
- def test_dummy_sprocket_assets
153
- template "rails/stylesheets.css", "#{dummy_path}/app/assets/stylesheets/application.css", force: true
154
- template "rails/dummy_manifest.js", "#{dummy_path}/app/assets/config/manifest.js", force: true
155
+ def test_dummy_assets
156
+ template "rails/stylesheets.css", "#{dummy_path}/app/assets/stylesheets/application.css", force: true
155
157
  end
156
158
 
157
159
  def test_dummy_clean
@@ -159,7 +161,7 @@ module Rails
159
161
  remove_file ".ruby-version"
160
162
  remove_dir "db"
161
163
  remove_file "Gemfile"
162
- remove_file "lib/tasks"
164
+ remove_dir "lib"
163
165
  remove_file "public/robots.txt"
164
166
  remove_file "README.md"
165
167
  remove_file "test"
@@ -167,10 +169,6 @@ module Rails
167
169
  end
168
170
  end
169
171
 
170
- def assets_manifest
171
- template "rails/engine_manifest.js", "app/assets/config/#{underscored_name}_manifest.js"
172
- end
173
-
174
172
  def stylesheets
175
173
  if mountable?
176
174
  copy_file "rails/stylesheets.css",
@@ -361,7 +359,7 @@ module Rails
361
359
  mute do
362
360
  build(:generate_test_dummy)
363
361
  build(:test_dummy_config)
364
- build(:test_dummy_sprocket_assets) unless skip_sprockets?
362
+ build(:test_dummy_assets) unless skip_asset_pipeline?
365
363
  build(:test_dummy_clean)
366
364
  # ensure that bin/rails has proper dummy_path
367
365
  build(:bin)
@@ -491,9 +489,11 @@ module Rails
491
489
 
492
490
  def test_command
493
491
  if engine? && !options[:skip_active_record] && with_dummy_app?
494
- "db:test:prepare test"
492
+ "bin/rails db:test:prepare test"
493
+ elsif engine?
494
+ "bin/rails test"
495
495
  else
496
- "test"
496
+ "bin/test"
497
497
  end
498
498
  end
499
499
  end
@@ -90,7 +90,7 @@ jobs:
90
90
  DATABASE_URL: postgres://postgres:postgres@localhost:5432
91
91
  <%- end -%>
92
92
  # REDIS_URL: redis://localhost:6379/0
93
- run: bin/rails <%= test_command %>
93
+ run: <%= test_command %>
94
94
 
95
95
  - name: Keep screenshots from failed system tests
96
96
  uses: actions/upload-artifact@v4
@@ -3,7 +3,7 @@ ENV["RAILS_ENV"] = "test"
3
3
 
4
4
  require_relative "<%= File.join("..", options[:dummy_path], "config/environment") -%>"
5
5
  <% unless options[:skip_active_record] -%>
6
- ActiveRecord::Migrator.migrations_paths = [File.expand_path("../<%= options[:dummy_path] -%>/db/migrate", __dir__)]
6
+ ActiveRecord::Migrator.migrations_paths = [ File.expand_path("../<%= options[:dummy_path] -%>/db/migrate", __dir__) ]
7
7
  <% if options[:mountable] -%>
8
8
  ActiveRecord::Migrator.migrations_paths << File.expand_path("../db/migrate", __dir__)
9
9
  <% end -%>
@@ -13,7 +13,7 @@ require "rails/test_help"
13
13
  <% unless options[:skip_active_record] -%>
14
14
  # Load fixtures from the engine
15
15
  if ActiveSupport::TestCase.respond_to?(:fixture_paths=)
16
- ActiveSupport::TestCase.fixture_paths = [File.expand_path("fixtures", __dir__)]
16
+ ActiveSupport::TestCase.fixture_paths = [ File.expand_path("fixtures", __dir__) ]
17
17
  ActionDispatch::IntegrationTest.fixture_paths = ActiveSupport::TestCase.fixture_paths
18
18
  ActiveSupport::TestCase.file_fixture_path = File.expand_path("fixtures", __dir__) + "/files"
19
19
  ActiveSupport::TestCase.fixtures :all
@@ -42,7 +42,7 @@ class <%= controller_class_name %>Controller < ApplicationController
42
42
  private
43
43
  # Use callbacks to share common setup or constraints between actions.
44
44
  def set_<%= singular_table_name %>
45
- @<%= singular_table_name %> = <%= orm_class.find(class_name, "params[:id]") %>
45
+ @<%= singular_table_name %> = <%= orm_class.find(class_name, "params.expect(:id)") %>
46
46
  end
47
47
 
48
48
  # Only allow a list of trusted parameters through.
@@ -50,7 +50,7 @@ class <%= controller_class_name %>Controller < ApplicationController
50
50
  <%- if attributes_names.empty? -%>
51
51
  params.fetch(:<%= singular_table_name %>, {})
52
52
  <%- else -%>
53
- params.require(:<%= singular_table_name %>).permit(<%= permitted_params %>)
53
+ params.expect(<%= singular_table_name %>: [ <%= permitted_params %> ])
54
54
  <%- end -%>
55
55
  end
56
56
  end
@@ -43,13 +43,13 @@ class <%= controller_class_name %>Controller < ApplicationController
43
43
  # DELETE <%= route_url %>/1
44
44
  def destroy
45
45
  @<%= orm_instance.destroy %>
46
- redirect_to <%= index_helper %>_url, notice: <%= %("#{human_name} was successfully destroyed.") %>, status: :see_other
46
+ redirect_to <%= index_helper %>_path, notice: <%= %("#{human_name} was successfully destroyed.") %>, status: :see_other
47
47
  end
48
48
 
49
49
  private
50
50
  # Use callbacks to share common setup or constraints between actions.
51
51
  def set_<%= singular_table_name %>
52
- @<%= singular_table_name %> = <%= orm_class.find(class_name, "params[:id]") %>
52
+ @<%= singular_table_name %> = <%= orm_class.find(class_name, "params.expect(:id)") %>
53
53
  end
54
54
 
55
55
  # Only allow a list of trusted parameters through.
@@ -57,7 +57,7 @@ class <%= controller_class_name %>Controller < ApplicationController
57
57
  <%- if attributes_names.empty? -%>
58
58
  params.fetch(:<%= singular_table_name %>, {})
59
59
  <%- else -%>
60
- params.require(:<%= singular_table_name %>).permit(<%= permitted_params %>)
60
+ params.expect(<%= singular_table_name %>: [ <%= permitted_params %> ])
61
61
  <%- end -%>
62
62
  end
63
63
  end
@@ -0,0 +1,18 @@
1
+ Description:
2
+ Generate a one-off or general purpose script, such as a data migration
3
+ script, cleanup script, etc.
4
+
5
+ Example:
6
+ `bin/rails generate script my_script`
7
+
8
+ This will create:
9
+ script/my_script.rb
10
+
11
+ You can run the script using:
12
+ `ruby script/my_script.rb`
13
+
14
+ You can specify a folder:
15
+ `bin/rails generate script cleanup/my_script`
16
+
17
+ This will create:
18
+ script/cleanup/my_script.rb
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rails/generators/named_base"
4
+
5
+ module Rails
6
+ module Generators
7
+ class ScriptGenerator < NamedBase
8
+ def generate_script
9
+ template("script.rb.tt", "script/#{file_path}.rb")
10
+ end
11
+
12
+ private
13
+ def depth
14
+ class_path.size + 1
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,3 @@
1
+ require_relative "<%= '../' * depth %>config/environment"
2
+
3
+ # Your code goes here