railties 6.0.0.beta3 → 6.0.0.rc1

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 (52) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +86 -7
  3. data/RDOC_MAIN.rdoc +3 -3
  4. data/README.rdoc +1 -1
  5. data/lib/rails/application.rb +3 -1
  6. data/lib/rails/application/configuration.rb +27 -1
  7. data/lib/rails/application/default_middleware_stack.rb +1 -0
  8. data/lib/rails/application/dummy_erb_compiler.rb +19 -0
  9. data/lib/rails/application/finisher.rb +38 -1
  10. data/lib/rails/autoloaders.rb +10 -2
  11. data/lib/rails/command/environment_argument.rb +7 -4
  12. data/lib/rails/commands/console/console_command.rb +6 -0
  13. data/lib/rails/commands/credentials/USAGE +1 -1
  14. data/lib/rails/commands/credentials/credentials_command.rb +17 -3
  15. data/lib/rails/commands/dbconsole/dbconsole_command.rb +19 -7
  16. data/lib/rails/commands/dev/dev_command.rb +4 -2
  17. data/lib/rails/commands/encrypted/USAGE +28 -0
  18. data/lib/rails/commands/encrypted/encrypted_command.rb +1 -0
  19. data/lib/rails/commands/initializers/initializers_command.rb +7 -0
  20. data/lib/rails/commands/notes/notes_command.rb +1 -1
  21. data/lib/rails/commands/runner/runner_command.rb +7 -3
  22. data/lib/rails/commands/server/server_command.rb +8 -6
  23. data/lib/rails/engine.rb +27 -31
  24. data/lib/rails/gem_version.rb +1 -1
  25. data/lib/rails/generators.rb +2 -0
  26. data/lib/rails/generators/app_base.rb +2 -2
  27. data/lib/rails/generators/app_name.rb +2 -2
  28. data/lib/rails/generators/database.rb +1 -1
  29. data/lib/rails/generators/erb/scaffold/templates/_form.html.erb.tt +6 -3
  30. data/lib/rails/generators/erb/scaffold/templates/show.html.erb.tt +8 -0
  31. data/lib/rails/generators/generated_attribute.rb +36 -10
  32. data/lib/rails/generators/named_base.rb +1 -0
  33. data/lib/rails/generators/rails/app/templates/Gemfile.tt +3 -3
  34. data/lib/rails/generators/rails/app/templates/app/javascript/packs/application.js.tt +8 -0
  35. data/lib/rails/generators/rails/app/templates/bin/setup.tt +3 -2
  36. data/lib/rails/generators/rails/app/templates/config/environments/development.rb.tt +2 -0
  37. data/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt +2 -0
  38. data/lib/rails/generators/rails/app/templates/config/environments/test.rb.tt +10 -5
  39. data/lib/rails/generators/rails/app/templates/ruby-version.tt +1 -1
  40. data/lib/rails/generators/rails/assets/assets_generator.rb +7 -0
  41. data/lib/rails/generators/rails/db/system/change/change_generator.rb +12 -2
  42. data/lib/rails/generators/rails/plugin/plugin_generator.rb +0 -15
  43. data/lib/rails/generators/rails/scaffold_controller/scaffold_controller_generator.rb +8 -0
  44. data/lib/rails/generators/rails/scaffold_controller/templates/api_controller.rb.tt +1 -1
  45. data/lib/rails/generators/rails/scaffold_controller/templates/controller.rb.tt +1 -1
  46. data/lib/rails/generators/test_unit/model/templates/fixtures.yml.tt +2 -2
  47. data/lib/rails/mailers_controller.rb +6 -3
  48. data/lib/rails/source_annotation_extractor.rb +14 -1
  49. data/lib/rails/tasks.rb +1 -0
  50. data/lib/rails/tasks/zeitwerk.rake +78 -0
  51. metadata +14 -12
  52. data/lib/rails/generators/rails/app/templates/bin/update.tt +0 -33
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "active_support/time"
4
+ require "active_support/deprecation"
4
5
 
5
6
  module Rails
6
7
  module Generators
@@ -51,6 +52,12 @@ module Rails
51
52
  type = $1
52
53
  provided_options = $2.split(/[,.-]/)
53
54
  options = Hash[provided_options.map { |opt| [opt.to_sym, true] }]
55
+
56
+ if options[:required]
57
+ ActiveSupport::Deprecation.warn("Passing {required} option has no effect on the model generator. It will be removed in Rails 6.1.\n")
58
+ options.delete(:required)
59
+ end
60
+
54
61
  return type, options
55
62
  else
56
63
  return type, {}
@@ -68,13 +75,15 @@ module Rails
68
75
 
69
76
  def field_type
70
77
  @field_type ||= case type
71
- when :integer then :number_field
72
- when :float, :decimal then :text_field
73
- when :time then :time_select
74
- when :datetime, :timestamp then :datetime_select
75
- when :date then :date_select
76
- when :text then :text_area
77
- when :boolean then :check_box
78
+ when :integer then :number_field
79
+ when :float, :decimal then :text_field
80
+ when :time then :time_select
81
+ when :datetime, :timestamp then :datetime_select
82
+ when :date then :date_select
83
+ when :text then :text_area
84
+ when :rich_text then :rich_text_area
85
+ when :boolean then :check_box
86
+ when :attachment, :attachments then :file_field
78
87
  else
79
88
  :text_field
80
89
  end
@@ -90,7 +99,9 @@ module Rails
90
99
  when :string then name == "type" ? "" : "MyString"
91
100
  when :text then "MyText"
92
101
  when :boolean then false
93
- when :references, :belongs_to then nil
102
+ when :references, :belongs_to,
103
+ :attachment, :attachments,
104
+ :rich_text then nil
94
105
  else
95
106
  ""
96
107
  end
@@ -133,7 +144,7 @@ module Rails
133
144
  end
134
145
 
135
146
  def required?
136
- attr_options[:required]
147
+ reference? && Rails.application.config.active_record.belongs_to_required_by_default
137
148
  end
138
149
 
139
150
  def has_index?
@@ -152,6 +163,22 @@ module Rails
152
163
  type == :token
153
164
  end
154
165
 
166
+ def rich_text?
167
+ type == :rich_text
168
+ end
169
+
170
+ def attachment?
171
+ type == :attachment
172
+ end
173
+
174
+ def attachments?
175
+ type == :attachments
176
+ end
177
+
178
+ def virtual?
179
+ rich_text? || attachment? || attachments?
180
+ end
181
+
155
182
  def inject_options
156
183
  (+"").tap { |s| options_for_migration.each { |k, v| s << ", #{k}: #{v.inspect}" } }
157
184
  end
@@ -163,7 +190,6 @@ module Rails
163
190
  def options_for_migration
164
191
  @attr_options.dup.tap do |options|
165
192
  if required?
166
- options.delete(:required)
167
193
  options[:null] = false
168
194
  end
169
195
 
@@ -187,6 +187,7 @@ module Rails
187
187
 
188
188
  def attributes_names # :doc:
189
189
  @attributes_names ||= attributes.each_with_object([]) do |a, names|
190
+ next if a.attachments?
190
191
  names << a.column_name
191
192
  names << "password_confirmation" if a.password_digest?
192
193
  names << "#{a.name}_type" if a.polymorphic?
@@ -28,7 +28,7 @@ ruby <%= "'#{RUBY_VERSION}'" -%>
28
28
 
29
29
  <% if depend_on_bootsnap? -%>
30
30
  # Reduces boot times through caching; required in config/boot.rb
31
- gem 'bootsnap', '>= 1.4.1', require: false
31
+ gem 'bootsnap', '>= 1.4.2', require: false
32
32
 
33
33
  <%- end -%>
34
34
  <%- if options.api? -%>
@@ -69,8 +69,8 @@ group :test do
69
69
  # Adds support for Capybara system testing and selenium driver
70
70
  gem 'capybara', '>= 2.15'
71
71
  gem 'selenium-webdriver'
72
- # Easy installation and use of chromedriver to run system tests with Chrome
73
- gem 'chromedriver-helper'
72
+ # Easy installation and use of web drivers to run system tests with browsers
73
+ gem 'webdrivers'
74
74
  end
75
75
  <%- end -%>
76
76
 
@@ -13,3 +13,11 @@ require("@rails/activestorage").start()
13
13
  <%- unless options[:skip_action_cable] -%>
14
14
  require("channels")
15
15
  <%- end -%>
16
+
17
+
18
+ // Uncomment to copy all static images under ../images to the output folder and reference
19
+ // them with the image_pack_tag helper in views (e.g <%%= image_pack_tag 'rails.png' %>)
20
+ // or the `imagePath` JavaScript helper below.
21
+ //
22
+ // const images = require.context('../images', true)
23
+ // const imagePath = (name) => images(name, true)
@@ -8,7 +8,8 @@ def system!(*args)
8
8
  end
9
9
 
10
10
  FileUtils.chdir APP_ROOT do
11
- # This script is a starting point to setup your application.
11
+ # This script is a way to setup or update your development environment automatically.
12
+ # This script is idempotent, so that you can run it at anytime and get an expectable outcome.
12
13
  # Add necessary setup steps to this file.
13
14
 
14
15
  puts '== Installing dependencies =='
@@ -27,7 +28,7 @@ FileUtils.chdir APP_ROOT do
27
28
  # end
28
29
 
29
30
  puts "\n== Preparing database =="
30
- system! 'bin/rails db:setup'
31
+ system! 'bin/rails db:prepare'
31
32
  <% end -%>
32
33
 
33
34
  puts "\n== Removing old logs and tempfiles =="
@@ -15,9 +15,11 @@ Rails.application.configure do
15
15
  # Enable/disable caching. By default caching is disabled.
16
16
  # Run rails dev:cache to toggle caching.
17
17
  if Rails.root.join('tmp', 'caching-dev.txt').exist?
18
+ <%- unless options.api? -%>
18
19
  config.action_controller.perform_caching = true
19
20
  config.action_controller.enable_fragment_cache_logging = true
20
21
 
22
+ <%- end -%>
21
23
  config.cache_store = :memory_store
22
24
  config.public_file_server.headers = {
23
25
  'Cache-Control' => "public, max-age=#{2.days.to_i}"
@@ -12,7 +12,9 @@ Rails.application.configure do
12
12
 
13
13
  # Full error reports are disabled and caching is turned on.
14
14
  config.consider_all_requests_local = false
15
+ <%- unless options.api? -%>
15
16
  config.action_controller.perform_caching = true
17
+ <%- end -%>
16
18
 
17
19
  # Ensures that a master key has been made available in either ENV["RAILS_MASTER_KEY"]
18
20
  # or in config/master.key. This key is used to decrypt credentials (and other encrypted files).
@@ -1,11 +1,16 @@
1
+ # The test environment is used exclusively to run your application's
2
+ # test suite. You never need to work with it otherwise. Remember that
3
+ # your test database is "scratch space" for the test suite and is wiped
4
+ # and recreated between test runs. Don't rely on the data there!
5
+
1
6
  Rails.application.configure do
2
7
  # Settings specified here will take precedence over those in config/application.rb.
3
-
4
- # The test environment is used exclusively to run your application's
5
- # test suite. You never need to work with it otherwise. Remember that
6
- # your test database is "scratch space" for the test suite and is wiped
7
- # and recreated between test runs. Don't rely on the data there!
8
+ <%# Spring executes the reloaders when files change. %>
9
+ <%- if spring_install? -%>
10
+ config.cache_classes = false
11
+ <%- else -%>
8
12
  config.cache_classes = true
13
+ <%- end -%>
9
14
 
10
15
  # Do not eager load code on boot. This avoids loading your whole application
11
16
  # just for the purpose of running a single test. If you are using a tool that
@@ -1 +1 @@
1
- <%= ENV["RBENV_VERSION"] || ENV["rvm_ruby_string"] || "#{RUBY_ENGINE}-#{RUBY_ENGINE_VERSION}" -%>
1
+ <%= ENV["RBENV_VERSION"] || ENV["rvm_ruby_string"] || "#{RUBY_ENGINE}-#{RUBY_ENGINE_VERSION}" %>
@@ -3,7 +3,10 @@
3
3
  module Rails
4
4
  module Generators
5
5
  class AssetsGenerator < NamedBase # :nodoc:
6
+ class_option :javascripts, type: :boolean, desc: "Generate JavaScripts"
6
7
  class_option :stylesheets, type: :boolean, desc: "Generate Stylesheets"
8
+
9
+ class_option :javascript_engine, desc: "Engine for JavaScripts"
7
10
  class_option :stylesheet_engine, desc: "Engine for Stylesheets"
8
11
 
9
12
  private
@@ -11,6 +14,10 @@ module Rails
11
14
  file_name
12
15
  end
13
16
 
17
+ hook_for :javascript_engine do |javascript_engine|
18
+ invoke javascript_engine, [name] if options[:javascripts]
19
+ end
20
+
14
21
  hook_for :stylesheet_engine do |stylesheet_engine|
15
22
  invoke stylesheet_engine, [name] if options[:stylesheets]
16
23
  end
@@ -35,8 +35,9 @@ module Rails
35
35
  end
36
36
 
37
37
  def edit_gemfile
38
- database_gem_name, _ = gem_for_database
39
- gsub_file("Gemfile", all_database_gems_regex, database_gem_name)
38
+ name, version = gem_for_database
39
+ gsub_file("Gemfile", all_database_gems_regex, name)
40
+ gsub_file("Gemfile", gem_entry_regex_for(name), gem_entry_for(name, *version))
40
41
  end
41
42
 
42
43
  private
@@ -48,6 +49,15 @@ module Rails
48
49
  all_database_gem_names = all_database_gems.map(&:first)
49
50
  /(\b#{all_database_gem_names.join('\b|\b')}\b)/
50
51
  end
52
+
53
+ def gem_entry_regex_for(gem_name)
54
+ /^gem.*\b#{gem_name}\b.*/
55
+ end
56
+
57
+ def gem_entry_for(*gem_name_and_version)
58
+ gem_name_and_version.map! { |segment| "'#{segment}'" }
59
+ "gem #{gem_name_and_version.join(", ")}"
60
+ end
51
61
  end
52
62
  end
53
63
  end
@@ -144,17 +144,6 @@ task default: :test
144
144
  end
145
145
  end
146
146
 
147
- def javascripts
148
- return if options.skip_javascript?
149
-
150
- if mountable?
151
- template "rails/javascripts.js",
152
- "app/assets/javascripts/#{namespaced_name}/application.js"
153
- elsif full?
154
- empty_directory_with_keep_file "app/assets/javascripts/#{namespaced_name}"
155
- end
156
- end
157
-
158
147
  def bin(force = false)
159
148
  bin_file = engine? ? "bin/rails.tt" : "bin/test.tt"
160
149
  template bin_file, force: force do |content|
@@ -236,10 +225,6 @@ task default: :test
236
225
  build(:stylesheets) unless api?
237
226
  end
238
227
 
239
- def create_javascript_files
240
- build(:javascripts) unless api?
241
- end
242
-
243
228
  def create_bin_files
244
229
  build(:bin)
245
230
  end
@@ -32,6 +32,14 @@ module Rails
32
32
  hook_for :helper, as: :scaffold do |invoked|
33
33
  invoke invoked, [ controller_name ]
34
34
  end
35
+
36
+ private
37
+
38
+ def permitted_params
39
+ params = attributes_names.map { |name| ":#{name}" }.join(", ")
40
+ params += attributes.select(&:attachments?).map { |a| ", #{a.name}: []" }.join
41
+ params
42
+ end
35
43
  end
36
44
  end
37
45
  end
@@ -54,7 +54,7 @@ class <%= controller_class_name %>Controller < ApplicationController
54
54
  <%- if attributes_names.empty? -%>
55
55
  params.fetch(:<%= singular_table_name %>, {})
56
56
  <%- else -%>
57
- params.require(:<%= singular_table_name %>).permit(<%= attributes_names.map { |name| ":#{name}" }.join(', ') %>)
57
+ params.require(:<%= singular_table_name %>).permit(<%= permitted_params %>)
58
58
  <%- end -%>
59
59
  end
60
60
  end
@@ -61,7 +61,7 @@ class <%= controller_class_name %>Controller < ApplicationController
61
61
  <%- if attributes_names.empty? -%>
62
62
  params.fetch(:<%= singular_table_name %>, {})
63
63
  <%- else -%>
64
- params.require(:<%= singular_table_name %>).permit(<%= attributes_names.map { |name| ":#{name}" }.join(', ') %>)
64
+ params.require(:<%= singular_table_name %>).permit(<%= permitted_params %>)
65
65
  <%- end -%>
66
66
  end
67
67
  end
@@ -1,4 +1,4 @@
1
- # Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html
1
+ # Read about fixtures at https://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html
2
2
  <% unless attributes.empty? -%>
3
3
  <% %w(one two).each do |name| %>
4
4
  <%= name %>:
@@ -7,7 +7,7 @@
7
7
  password_digest: <%%= BCrypt::Password.create('secret') %>
8
8
  <%- elsif attribute.reference? -%>
9
9
  <%= yaml_key_value(attribute.column_name.sub(/_id$/, ''), attribute.default || name) %>
10
- <%- else -%>
10
+ <%- elsif !attribute.virtual? -%>
11
11
  <%= yaml_key_value(attribute.column_name, attribute.default) %>
12
12
  <%- end -%>
13
13
  <%- if attribute.polymorphic? -%>
@@ -5,8 +5,9 @@ require "rails/application_controller"
5
5
  class Rails::MailersController < Rails::ApplicationController # :nodoc:
6
6
  prepend_view_path ActionDispatch::DebugView::RESCUES_TEMPLATE_PATH
7
7
 
8
+ around_action :set_locale, only: :preview
9
+ before_action :find_preview, only: :preview
8
10
  before_action :require_local!, unless: :show_previews?
9
- before_action :find_preview, :set_locale, only: :preview
10
11
 
11
12
  helper_method :part_query, :locale_query
12
13
 
@@ -38,7 +39,7 @@ class Rails::MailersController < Rails::ApplicationController # :nodoc:
38
39
  end
39
40
  else
40
41
  @part = find_preferred_part(request.format, Mime[:html], Mime[:text])
41
- render action: "email", layout: false, formats: %w[html]
42
+ render action: "email", layout: false, formats: [:html]
42
43
  end
43
44
  else
44
45
  raise AbstractController::ActionNotFound, "Email '#{@email_action}' not found in #{@preview.name}"
@@ -92,6 +93,8 @@ class Rails::MailersController < Rails::ApplicationController # :nodoc:
92
93
  end
93
94
 
94
95
  def set_locale
95
- I18n.locale = params[:locale] || I18n.default_locale
96
+ I18n.with_locale(params[:locale] || I18n.default_locale) do
97
+ yield
98
+ end
96
99
  end
97
100
  end
@@ -29,6 +29,16 @@ module Rails
29
29
  directories.push(*dirs)
30
30
  end
31
31
 
32
+ def self.tags
33
+ @@tags ||= %w(OPTIMIZE FIXME TODO)
34
+ end
35
+
36
+ # Registers additional tags
37
+ # Rails::SourceAnnotationExtractor::Annotation.register_tags("TESTME", "DEPRECATEME")
38
+ def self.register_tags(*additional_tags)
39
+ tags.push(*additional_tags)
40
+ end
41
+
32
42
  def self.extensions
33
43
  @@extensions ||= {}
34
44
  end
@@ -66,6 +76,8 @@ module Rails
66
76
  # Prints all annotations with tag +tag+ under the root directories +app+,
67
77
  # +config+, +db+, +lib+, and +test+ (recursively).
68
78
  #
79
+ # If +tag+ is <tt>nil</tt>, annotations with either default or registered tags are printed.
80
+ #
69
81
  # Specific directories can be explicitly set using the <tt>:dirs</tt> key in +options+.
70
82
  #
71
83
  # Rails::SourceAnnotationExtractor.enumerate 'TODO|FIXME', dirs: %w(app lib), tag: true
@@ -75,7 +87,8 @@ module Rails
75
87
  # See <tt>#find_in</tt> for a list of file extensions that will be taken into account.
76
88
  #
77
89
  # This class method is the single entry point for the `rails notes` command.
78
- def self.enumerate(tag, options = {})
90
+ def self.enumerate(tag = nil, options = {})
91
+ tag ||= Annotation.tags.join("|")
79
92
  extractor = new(tag)
80
93
  dirs = options.delete(:dirs) || Annotation.directories
81
94
  extractor.display(extractor.find(dirs), options)
@@ -15,6 +15,7 @@ require "rake"
15
15
  routes
16
16
  tmp
17
17
  yarn
18
+ zeitwerk
18
19
  ).tap { |arr|
19
20
  arr << "statistics" if Rake.application.current_scope.empty?
20
21
  }.each do |task|
@@ -0,0 +1,78 @@
1
+ # frozen_string_literal: true
2
+
3
+ ensure_classic_mode = ->() do
4
+ if Rails.autoloaders.zeitwerk_enabled?
5
+ abort <<~EOS
6
+ Please, enable temporarily :classic mode:
7
+
8
+ # config/application.rb
9
+ config.autoloader = :classic
10
+
11
+ and try again. When all is good, you can delete that line.
12
+ EOS
13
+ end
14
+ end
15
+
16
+ eager_load = ->() do
17
+ Rails.configuration.eager_load_namespaces.each(&:eager_load!)
18
+ end
19
+
20
+ mismatches = []
21
+ check_directory = ->(directory, parent) do
22
+ # test/mailers/previews might not exist.
23
+ return unless File.exists?(directory)
24
+
25
+ Dir.foreach(directory) do |entry|
26
+ next if entry.start_with?(".")
27
+ next if parent == Object && entry == "concerns"
28
+
29
+ abspath = File.join(directory, entry)
30
+
31
+ if File.directory?(abspath) || abspath.end_with?(".rb")
32
+ print "."
33
+ cname = File.basename(abspath, ".rb").camelize.to_sym
34
+ if parent.const_defined?(cname, false)
35
+ if File.directory?(abspath)
36
+ check_directory[abspath, parent.const_get(cname)]
37
+ end
38
+ else
39
+ mismatches << [abspath, parent, cname]
40
+ end
41
+ end
42
+ end
43
+ end
44
+
45
+ report = ->() do
46
+ puts
47
+ if mismatches.empty?
48
+ puts "All is good!"
49
+ puts "Please, remember to delete `config.autoloader = :classic` from config/application.rb."
50
+ else
51
+ mismatches.each do |abspath, parent, cname|
52
+ relpath = abspath.sub(%r{\A#{Regexp.escape(Rails.root.to_path)}/}, "")
53
+ cpath = parent == Object ? cname : "#{parent.name}::#{cname}"
54
+ puts "expected #{relpath} to define #{cpath}"
55
+ end
56
+ puts
57
+ puts <<~EOS
58
+ Please revise the reported mismatches. You can normally fix them by adding
59
+ acronyms to config/initializers/inflections.rb or renaming the constants.
60
+ EOS
61
+ end
62
+ end
63
+
64
+ namespace :zeitwerk do
65
+ desc "Checks project structure for Zeitwerk compatibility"
66
+ task check: :environment do
67
+ ensure_classic_mode[]
68
+ eager_load[]
69
+
70
+ $stdout.sync = true
71
+ ActiveSupport::Dependencies.autoload_paths.each do |autoload_path|
72
+ check_directory[autoload_path, Object]
73
+ end
74
+ puts
75
+
76
+ report[]
77
+ end
78
+ end