diff options
Diffstat (limited to 'railties/lib/rails/generators')
208 files changed, 2362 insertions, 1299 deletions
diff --git a/railties/lib/rails/generators/actions.rb b/railties/lib/rails/generators/actions.rb index 57309112b5..1a5f2ff203 100644 --- a/railties/lib/rails/generators/actions.rb +++ b/railties/lib/rails/generators/actions.rb @@ -1,41 +1,45 @@ -require 'open-uri' +# frozen_string_literal: true + +require "active_support/core_ext/string/strip" module Rails module Generators module Actions def initialize(*) # :nodoc: super - @in_group = nil - @after_bundle_callbacks = [] + @indentation = 0 end # Adds an entry into +Gemfile+ for the supplied gem. # # gem "rspec", group: :test # gem "technoweenie-restful-authentication", lib: "restful-authentication", source: "http://gems.github.com/" - # gem "rails", "3.0", git: "git://github.com/rails/rails" + # gem "rails", "3.0", git: "https://github.com/rails/rails" + # gem "RedCloth", ">= 4.1.0", "< 4.2.0" def gem(*args) options = args.extract_options! - name, version = args + name, *versions = args # Set the message to be shown in logs. Uses the git repo if one is given, # otherwise use name (version). parts, message = [ quote(name) ], name.dup - if version ||= options.delete(:version) - parts << quote(version) - message << " (#{version})" + + if versions = versions.any? ? versions : options.delete(:version) + _versions = Array(versions) + _versions.each do |version| + parts << quote(version) + end + message << " (#{_versions.join(", ")})" end message = options[:git] if options[:git] log :gemfile, message - options.each do |option, value| - parts << "#{option}: #{quote(value)}" - end + parts << quote(options) unless options.empty? in_root do str = "gem #{parts.join(", ")}" - str = " " + str if @in_group + str = indentation + str str = "\n" + str append_file "Gemfile", str, verbose: false end @@ -47,17 +51,29 @@ module Rails # gem "rspec-rails" # end def gem_group(*names, &block) - name = names.map(&:inspect).join(", ") - log :gemfile, "group #{name}" + options = names.extract_options! + str = names.map(&:inspect) + str << quote(options) unless options.empty? + str = str.join(", ") + log :gemfile, "group #{str}" in_root do - append_file "Gemfile", "\ngroup #{name} do", force: true + append_file "Gemfile", "\ngroup #{str} do", force: true + with_indentation(&block) + append_file "Gemfile", "\nend\n", force: true + end + end - @in_group = true - instance_eval(&block) - @in_group = false + def github(repo, options = {}, &block) + str = [quote(repo)] + str << quote(options) unless options.empty? + str = str.join(", ") + log :github, "github #{str}" - append_file "Gemfile", "\nend\n", force: true + in_root do + append_file "Gemfile", "\n#{indentation}github #{str} do", force: true + with_indentation(&block) + append_file "Gemfile", "\n#{indentation}end", force: true end end @@ -70,15 +86,13 @@ module Rails # add_source "http://gems.github.com/" do # gem "rspec-rails" # end - def add_source(source, options={}, &block) + def add_source(source, options = {}, &block) log :source, source in_root do if block append_file "Gemfile", "\nsource #{quote(source)} do", force: true - @in_group = true - instance_eval(&block) - @in_group = false + with_indentation(&block) append_file "Gemfile", "\nend\n", force: true else prepend_file "Gemfile", "source #{quote(source)}\n", verbose: false @@ -98,17 +112,17 @@ module Rails # environment(nil, env: "development") do # "config.action_controller.asset_host = 'localhost:3000'" # end - def environment(data=nil, options={}) - sentinel = /class [a-z_:]+ < Rails::Application/i - env_file_sentinel = /Rails\.application\.configure do/ - data = yield if !data && block_given? + def environment(data = nil, options = {}) + sentinel = "class Application < Rails::Application\n" + env_file_sentinel = "Rails.application.configure do\n" + data ||= yield if block_given? in_root do if options[:env].nil? - inject_into_file 'config/application.rb', "\n #{data}", after: sentinel, verbose: false + inject_into_file "config/application.rb", optimize_indentation(data, 4), after: sentinel, verbose: false else Array(options[:env]).each do |env| - inject_into_file "config/environments/#{env}.rb", "\n #{data}", after: env_file_sentinel, verbose: false + inject_into_file "config/environments/#{env}.rb", optimize_indentation(data, 2), after: env_file_sentinel, verbose: false end end end @@ -120,7 +134,7 @@ module Rails # git :init # git add: "this.file that.rb" # git add: "onefile.rb", rm: "badfile.cxx" - def git(commands={}) + def git(commands = {}) if commands.is_a?(Symbol) run "git #{commands}" else @@ -139,12 +153,13 @@ module Rails # end # # vendor("foreign.rb", "# Foreign code is fun") - def vendor(filename, data=nil, &block) + def vendor(filename, data = nil) log :vendor, filename - create_file("vendor/#{filename}", data, verbose: false, &block) + data ||= yield if block_given? + create_file("vendor/#{filename}", optimize_indentation(data), verbose: false) end - # Create a new file in the lib/ directory. Code can be specified + # Create a new file in the <tt>lib/</tt> directory. Code can be specified # in a block or a data string can be given. # # lib("crypto.rb") do @@ -152,9 +167,10 @@ module Rails # end # # lib("foreign.rb", "# Foreign code is fun") - def lib(filename, data=nil, &block) + def lib(filename, data = nil) log :lib, filename - create_file("lib/#{filename}", data, verbose: false, &block) + data ||= yield if block_given? + create_file("lib/#{filename}", optimize_indentation(data), verbose: false) end # Create a new +Rakefile+ with the provided code (either in a block or a string). @@ -172,9 +188,10 @@ module Rails # end # # rakefile('seed.rake', 'puts "Planting seeds"') - def rakefile(filename, data=nil, &block) + def rakefile(filename, data = nil) log :rakefile, filename - create_file("lib/tasks/#{filename}", data, verbose: false, &block) + data ||= yield if block_given? + create_file("lib/tasks/#{filename}", optimize_indentation(data), verbose: false) end # Create a new initializer with the provided code (either in a block or a string). @@ -190,9 +207,10 @@ module Rails # end # # initializer("api.rb", "API_KEY = '123456'") - def initializer(filename, data=nil, &block) + def initializer(filename, data = nil) log :initializer, filename - create_file("config/initializers/#{filename}", data, verbose: false, &block) + data ||= yield if block_given? + create_file("config/initializers/#{filename}", optimize_indentation(data), verbose: false) end # Generate something using a generator from Rails or a plugin. @@ -202,9 +220,12 @@ module Rails # generate(:authenticated, "user session") def generate(what, *args) log :generate, what + + options = args.extract_options! + options[:without_rails_env] = true argument = args.flat_map(&:to_s).join(" ") - in_root { run_ruby_script("bin/rails generate #{what} #{argument}", verbose: false) } + execute_command :rails, "generate #{what} #{argument}", options end # Runs the supplied rake task (invoked with 'rake ...') @@ -212,27 +233,21 @@ module Rails # rake("db:migrate") # rake("db:migrate", env: "production") # rake("gems:install", sudo: true) - def rake(command, options={}) + # rake("gems:install", capture: true) + def rake(command, options = {}) execute_command :rake, command, options end # Runs the supplied rake task (invoked with 'rails ...') # - # rails("db:migrate") - # rails("db:migrate", env: "production") - # rails("gems:install", sudo: true) - def rails_command(command, options={}) + # rails_command("db:migrate") + # rails_command("db:migrate", env: "production") + # rails_command("gems:install", sudo: true) + # rails_command("gems:install", capture: true) + def rails_command(command, options = {}) execute_command :rails, command, options end - # Just run the capify command in root - # - # capify! - def capify! - log :capify, "" - in_root { run("#{extify(:capify)} .", verbose: false) } - end - # Make an entry in Rails routing file <tt>config/routes.rb</tt> # # route "root 'welcome#index'" @@ -241,7 +256,7 @@ module Rails sentinel = /\.routes\.draw do\s*\n/m in_root do - inject_into_file 'config/routes.rb', " #{routing_code}\n", { after: sentinel, verbose: false, force: false } + inject_into_file "config/routes.rb", optimize_indentation(routing_code, 2), after: sentinel, verbose: false, force: false end end @@ -252,43 +267,38 @@ module Rails log File.read(find_in_source_paths(path)) end - # Registers a callback to be executed after bundle and spring binstubs - # have run. - # - # after_bundle do - # git add: '.' - # end - def after_bundle(&block) - @after_bundle_callbacks << block - end - - protected + private # Define log for backwards compatibility. If just one argument is sent, # invoke say, otherwise invoke say_status. Differently from say and # similarly to say_status, this method respects the quiet? option given. - def log(*args) + def log(*args) # :doc: if args.size == 1 say args.first.to_s unless options.quiet? else - args << (self.behavior == :invoke ? :green : :red) + args << (behavior == :invoke ? :green : :red) say_status(*args) end end - # Runs the supplied command using either "rake ..." or "rails ..." # based on the executor parameter provided. - def execute_command(executor, command, options={}) + def execute_command(executor, command, options = {}) # :doc: log executor, command - env = options[:env] || ENV["RAILS_ENV"] || 'development' - sudo = options[:sudo] && RbConfig::CONFIG['host_os'] !~ /mswin|mingw/ ? 'sudo ' : '' - in_root { run("#{sudo}#{extify(executor)} #{command} RAILS_ENV=#{env}", verbose: false) } + env = options[:env] || ENV["RAILS_ENV"] || "development" + rails_env = " RAILS_ENV=#{env}" unless options[:without_rails_env] + sudo = options[:sudo] && !Gem.win_platform? ? "sudo " : "" + config = { verbose: false } + + config[:capture] = options[:capture] if options[:capture] + config[:abort_on_failure] = options[:abort_on_failure] if options[:abort_on_failure] + + in_root { run("#{sudo}#{extify(executor)} #{command}#{rails_env}", config) } end # Add an extension to the given name based on the platform. - def extify(name) - if RbConfig::CONFIG['host_os'] =~ /mswin|mingw/ + def extify(name) # :doc: + if Gem.win_platform? "#{name}.bat" else name @@ -297,7 +307,12 @@ module Rails # Surround string with single quotes if there is no quotes. # Otherwise fall back to double quotes - def quote(value) + def quote(value) # :doc: + if value.respond_to? :each_pair + return value.map do |k, v| + "#{k}: #{quote(v)}" + end.join(", ") + end return value.inspect unless value.is_a? String if value.include?("'") @@ -306,6 +321,30 @@ module Rails "'#{value}'" end end + + # Returns optimized string with indentation + def optimize_indentation(value, amount = 0) # :doc: + return "#{value}\n" unless value.is_a?(String) + + if value.lines.size > 1 + value.strip_heredoc.indent(amount) + else + "#{value.strip.indent(amount)}\n" + end + end + + # Indent the +Gemfile+ to the depth of @indentation + def indentation # :doc: + " " * @indentation + end + + # Manage +Gemfile+ indentation for a DSL action block + def with_indentation(&block) # :doc: + @indentation += 1 + instance_eval(&block) + ensure + @indentation -= 1 + end end end end diff --git a/railties/lib/rails/generators/actions/create_migration.rb b/railties/lib/rails/generators/actions/create_migration.rb index d664b07652..05bc242447 100644 --- a/railties/lib/rails/generators/actions/create_migration.rb +++ b/railties/lib/rails/generators/actions/create_migration.rb @@ -1,10 +1,12 @@ -require 'thor/actions' +# frozen_string_literal: true + +require "fileutils" +require "thor/actions" module Rails module Generators module Actions class CreateMigration < Thor::Actions::CreateFile #:nodoc: - def migration_dir File.dirname(@destination) end @@ -37,32 +39,32 @@ module Rails end alias :exists? :existing_migration - protected + private - def on_conflict_behavior - options = base.options.merge(config) - if identical? - say_status :identical, :blue, relative_existing_migration - elsif options[:force] - say_status :remove, :green, relative_existing_migration - say_status :create, :green - unless pretend? - ::FileUtils.rm_rf(existing_migration) - yield + def on_conflict_behavior # :doc: + options = base.options.merge(config) + if identical? + say_status :identical, :blue, relative_existing_migration + elsif options[:force] + say_status :remove, :green, relative_existing_migration + say_status :create, :green + unless pretend? + ::FileUtils.rm_rf(existing_migration) + yield + end + elsif options[:skip] + say_status :skip, :yellow + else + say_status :conflict, :red + raise Error, "Another migration is already named #{migration_file_name}: " \ + "#{existing_migration}. Use --force to replace this migration " \ + "or --skip to ignore conflicted file." end - elsif options[:skip] - say_status :skip, :yellow - else - say_status :conflict, :red - raise Error, "Another migration is already named #{migration_file_name}: " + - "#{existing_migration}. Use --force to replace this migration " + - "or --skip to ignore conflicted file." end - end - def say_status(status, color, message = relative_destination) - base.shell.say_status(status, message, color) if config[:verbose] - end + def say_status(status, color, message = relative_destination) # :doc: + base.shell.say_status(status, message, color) if config[:verbose] + end end end end diff --git a/railties/lib/rails/generators/active_model.rb b/railties/lib/rails/generators/active_model.rb index 6183944bb0..8df8eb2438 100644 --- a/railties/lib/rails/generators/active_model.rb +++ b/railties/lib/rails/generators/active_model.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Rails module Generators # ActiveModel is a class to be implemented by each ORM to allow Rails to @@ -39,13 +41,13 @@ module Rails # GET edit # PATCH/PUT update # DELETE destroy - def self.find(klass, params=nil) + def self.find(klass, params = nil) "#{klass}.find(#{params})" end # GET new # POST create - def self.build(klass, params=nil) + def self.build(klass, params = nil) if params "#{klass}.new(#{params})" else @@ -59,7 +61,7 @@ module Rails end # PATCH/PUT update - def update(params=nil) + def update(params = nil) "#{name}.update(#{params})" end diff --git a/railties/lib/rails/generators/app_base.rb b/railties/lib/rails/generators/app_base.rb index 89341e6fa2..66f6b57379 100644 --- a/railties/lib/rails/generators/app_base.rb +++ b/railties/lib/rails/generators/app_base.rb @@ -1,17 +1,18 @@ -require 'digest/md5' -require 'active_support/core_ext/string/strip' -require 'rails/version' unless defined?(Rails::VERSION) -require 'open-uri' -require 'uri' -require 'rails/generators' -require 'active_support/core_ext/array/extract_options' +# frozen_string_literal: true + +require "fileutils" +require "digest/md5" +require "rails/version" unless defined?(Rails::VERSION) +require "open-uri" +require "uri" +require "rails/generators" +require "active_support/core_ext/array/extract_options" module Rails module Generators class AppBase < Base # :nodoc: - DATABASES = %w( mysql oracle postgresql sqlite3 frontbase ibm_db sqlserver ) - JDBC_DATABASES = %w( jdbcmysql jdbcsqlite3 jdbcpostgresql jdbc ) - DATABASES.concat(JDBC_DATABASES) + include Database + include AppName attr_accessor :rails_template add_shebang_option! @@ -23,84 +24,92 @@ module Rails end def self.add_shared_options_for(name) - class_option :template, type: :string, aliases: '-m', - desc: "Path to some #{name} template (can be a filesystem path or URL)" + class_option :template, type: :string, aliases: "-m", + desc: "Path to some #{name} template (can be a filesystem path or URL)" + + class_option :database, type: :string, aliases: "-d", default: "sqlite3", + desc: "Preconfigure for selected database (options: #{DATABASES.join('/')})" + + class_option :skip_gemfile, type: :boolean, default: false, + desc: "Don't create a Gemfile" + + class_option :skip_git, type: :boolean, aliases: "-G", default: false, + desc: "Skip .gitignore file" - class_option :database, type: :string, aliases: '-d', default: 'sqlite3', - desc: "Preconfigure for selected database (options: #{DATABASES.join('/')})" + class_option :skip_keeps, type: :boolean, default: false, + desc: "Skip source control .keep files" - class_option :javascript, type: :string, aliases: '-j', default: 'jquery', - desc: 'Preconfigure for selected JavaScript library' + class_option :skip_action_mailer, type: :boolean, aliases: "-M", + default: false, + desc: "Skip Action Mailer files" - class_option :skip_gemfile, type: :boolean, default: false, - desc: "Don't create a Gemfile" + class_option :skip_action_mailbox, type: :boolean, default: false, + desc: "Skip Action Mailbox gem" - class_option :skip_bundle, type: :boolean, aliases: '-B', default: false, - desc: "Don't run bundle install" + class_option :skip_action_text, type: :boolean, default: false, + desc: "Skip Action Text gem" - class_option :skip_git, type: :boolean, aliases: '-G', default: false, - desc: 'Skip .gitignore file' + class_option :skip_active_record, type: :boolean, aliases: "-O", default: false, + desc: "Skip Active Record files" - class_option :skip_keeps, type: :boolean, default: false, - desc: 'Skip source control .keep files' + class_option :skip_active_storage, type: :boolean, default: false, + desc: "Skip Active Storage files" - class_option :skip_action_mailer, type: :boolean, aliases: "-M", - default: false, - desc: "Skip Action Mailer files" + class_option :skip_puma, type: :boolean, aliases: "-P", default: false, + desc: "Skip Puma related files" - class_option :skip_active_record, type: :boolean, aliases: '-O', default: false, - desc: 'Skip Active Record files' + class_option :skip_action_cable, type: :boolean, aliases: "-C", default: false, + desc: "Skip Action Cable files" - class_option :skip_puma, type: :boolean, aliases: '-P', default: false, - desc: 'Skip Puma related files' + class_option :skip_sprockets, type: :boolean, aliases: "-S", default: false, + desc: "Skip Sprockets files" - class_option :skip_action_cable, type: :boolean, aliases: '-C', default: false, - desc: 'Skip Action Cable files' + class_option :skip_spring, type: :boolean, default: false, + desc: "Don't install Spring application preloader" - class_option :skip_sprockets, type: :boolean, aliases: '-S', default: false, - desc: 'Skip Sprockets files' + class_option :skip_listen, type: :boolean, default: false, + desc: "Don't generate configuration that depends on the listen gem" - class_option :skip_spring, type: :boolean, default: false, - desc: "Don't install Spring application preloader" + class_option :skip_javascript, type: :boolean, aliases: "-J", default: name == "plugin", + desc: "Skip JavaScript files" - class_option :skip_listen, type: :boolean, default: false, - desc: "Don't generate configuration that depends on the listen gem" + class_option :skip_turbolinks, type: :boolean, default: false, + desc: "Skip turbolinks gem" - class_option :skip_javascript, type: :boolean, aliases: '-J', default: false, - desc: 'Skip JavaScript files' + class_option :skip_test, type: :boolean, aliases: "-T", default: false, + desc: "Skip test files" - class_option :skip_turbolinks, type: :boolean, default: false, - desc: 'Skip turbolinks gem' + class_option :skip_system_test, type: :boolean, default: false, + desc: "Skip system test files" - class_option :skip_test, type: :boolean, aliases: '-T', default: false, - desc: 'Skip test files' + class_option :skip_bootsnap, type: :boolean, default: false, + desc: "Skip bootsnap gem" - class_option :dev, type: :boolean, default: false, - desc: "Setup the #{name} with Gemfile pointing to your Rails checkout" + class_option :dev, type: :boolean, default: false, + desc: "Setup the #{name} with Gemfile pointing to your Rails checkout" - class_option :edge, type: :boolean, default: false, - desc: "Setup the #{name} with Gemfile pointing to Rails repository" + class_option :edge, type: :boolean, default: false, + desc: "Setup the #{name} with Gemfile pointing to Rails repository" - class_option :rc, type: :string, default: nil, - desc: "Path to file containing extra configuration options for rails command" + class_option :rc, type: :string, default: nil, + desc: "Path to file containing extra configuration options for rails command" - class_option :no_rc, type: :boolean, default: false, - desc: 'Skip loading of extra configuration options from .railsrc file' + class_option :no_rc, type: :boolean, default: false, + desc: "Skip loading of extra configuration options from .railsrc file" - class_option :help, type: :boolean, aliases: '-h', group: :rails, - desc: 'Show this help message and quit' + class_option :help, type: :boolean, aliases: "-h", group: :rails, + desc: "Show this help message and quit" end def initialize(*args) @gem_filter = lambda { |gem| true } @extra_entries = [] super - convert_database_option_for_jruby end - protected + private - def gemfile_entry(name, *args) + def gemfile_entry(name, *args) # :doc: options = args.extract_options! version = args.first github = options[:github] @@ -116,11 +125,12 @@ module Rails self end - def gemfile_entries + def gemfile_entries # :doc: [rails_gemfile_entry, database_gemfile_entry, - webserver_gemfile_entry, + web_server_gemfile_entry, assets_gemfile_entry, + webpacker_gemfile_entry, javascript_gemfile_entry, jbuilder_gemfile_entry, psych_gemfile_entry, @@ -128,13 +138,13 @@ module Rails @extra_entries].flatten.find_all(&@gem_filter) end - def add_gem_entry_filter + def add_gem_entry_filter # :doc: @gem_filter = lambda { |next_filter, entry| yield(entry) && next_filter.call(entry) }.curry[@gem_filter] end - def builder + def builder # :doc: @builder ||= begin builder_class = get_builder_class builder_class.include(ActionMethods) @@ -142,62 +152,95 @@ module Rails end end - def build(meth, *args) + def build(meth, *args) # :doc: builder.send(meth, *args) if builder.respond_to?(meth) end - def create_root + def create_root # :doc: valid_const? - empty_directory '.' + empty_directory "." FileUtils.cd(destination_root) unless options[:pretend] end - def apply_rails_template + def apply_rails_template # :doc: apply rails_template if rails_template rescue Thor::Error, LoadError, Errno::ENOENT => e raise Error, "The template [#{rails_template}] could not be loaded. Error: #{e}" end - def set_default_accessors! + def set_default_accessors! # :doc: self.destination_root = File.expand_path(app_path, destination_root) - self.rails_template = case options[:template] + self.rails_template = \ + case options[:template] when /^https?:\/\// options[:template] when String File.expand_path(options[:template], Dir.pwd) else options[:template] - end + end end - def database_gemfile_entry + def database_gemfile_entry # :doc: return [] if options[:skip_active_record] gem_name, gem_version = gem_for_database GemfileEntry.version gem_name, gem_version, "Use #{options[:database]} as the database for Active Record" end - def webserver_gemfile_entry + def web_server_gemfile_entry # :doc: return [] if options[:skip_puma] - comment = 'Use Puma as the app server' - GemfileEntry.new('puma', '~> 3.0', comment) + comment = "Use Puma as the app server" + GemfileEntry.new("puma", "~> 3.11", comment) + end + + def include_all_railties? # :doc: + [ + options.values_at( + :skip_active_record, + :skip_action_mailer, + :skip_test, + :skip_sprockets, + :skip_action_cable + ), + skip_active_storage?, + skip_action_mailbox?, + skip_action_text? + ].flatten.none? + end + + def comment_if(value) # :doc: + question = "#{value}?" + + comment = + if respond_to?(question, true) + send(question) + else + options[value] + end + + comment ? "# " : "" end - def include_all_railties? - options.values_at(:skip_active_record, :skip_action_mailer, :skip_test, :skip_sprockets, :skip_action_cable).none? + def keeps? # :doc: + !options[:skip_keeps] end - def comment_if(value) - options[value] ? '# ' : '' + def sqlite3? # :doc: + !options[:skip_active_record] && options[:database] == "sqlite3" end - def keeps? - !options[:skip_keeps] + def skip_active_storage? # :doc: + options[:skip_active_storage] || options[:skip_active_record] end - def sqlite3? - !options[:skip_active_record] && options[:database] == 'sqlite3' + def skip_action_mailbox? # :doc: + options[:skip_action_mailbox] || skip_active_storage? + end + + def skip_action_text? # :doc: + options[:skip_action_text] || skip_active_storage? end class GemfileEntry < Struct.new(:name, :version, :comment, :options, :commented_out) @@ -233,130 +276,81 @@ module Rails end def rails_gemfile_entry - dev_edge_common = [ - ] if options.dev? [ - GemfileEntry.path('rails', Rails::Generators::RAILS_DEV_PATH) - ] + dev_edge_common + GemfileEntry.path("rails", Rails::Generators::RAILS_DEV_PATH) + ] elsif options.edge? [ - GemfileEntry.github('rails', 'rails/rails') - ] + dev_edge_common + GemfileEntry.github("rails", "rails/rails") + ] else - [GemfileEntry.version('rails', + [GemfileEntry.version("rails", rails_version_specifier, "Bundle edge Rails instead: gem 'rails', github: 'rails/rails'")] end end def rails_version_specifier(gem_version = Rails.gem_version) - if gem_version.prerelease? - next_series = gem_version - next_series = next_series.bump while next_series.segments.size > 2 - - [">= #{gem_version}", "< #{next_series}"] - elsif gem_version.segments.size == 3 + if gem_version.segments.size == 3 || gem_version.release.segments.size == 3 + # ~> 1.2.3 + # ~> 1.2.3.pre4 "~> #{gem_version}" else + # ~> 1.2.3, >= 1.2.3.4 + # ~> 1.2.3, >= 1.2.3.4.pre5 patch = gem_version.segments[0, 3].join(".") ["~> #{patch}", ">= #{gem_version}"] end end - def gem_for_database - # %w( mysql oracle postgresql sqlite3 frontbase ibm_db sqlserver jdbcmysql jdbcsqlite3 jdbcpostgresql ) - case options[:database] - when "oracle" then ["ruby-oci8", nil] - when "postgresql" then ["pg", ["~> 0.18"]] - when "frontbase" then ["ruby-frontbase", nil] - when "mysql" then ["mysql2", [">= 0.3.18", "< 0.5"]] - when "sqlserver" then ["activerecord-sqlserver-adapter", nil] - when "jdbcmysql" then ["activerecord-jdbcmysql-adapter", nil] - when "jdbcsqlite3" then ["activerecord-jdbcsqlite3-adapter", nil] - when "jdbcpostgresql" then ["activerecord-jdbcpostgresql-adapter", nil] - when "jdbc" then ["activerecord-jdbc-adapter", nil] - else [options[:database], nil] - end - end - - def convert_database_option_for_jruby - if defined?(JRUBY_VERSION) - case options[:database] - when "oracle" then options[:database].replace "jdbc" - when "postgresql" then options[:database].replace "jdbcpostgresql" - when "mysql" then options[:database].replace "jdbcmysql" - when "sqlite3" then options[:database].replace "jdbcsqlite3" - end - end - end - def assets_gemfile_entry return [] if options[:skip_sprockets] - gems = [] - gems << GemfileEntry.version('sass-rails', '~> 5.0', - 'Use SCSS for stylesheets') + GemfileEntry.version("sass-rails", "~> 5.0", "Use SCSS for stylesheets") + end - gems << GemfileEntry.version('uglifier', - '>= 1.3.0', - 'Use Uglifier as compressor for JavaScript assets') + def webpacker_gemfile_entry + return [] if options[:skip_javascript] - gems + if options.dev? || options.edge? + GemfileEntry.github "webpacker", "rails/webpacker", nil, "Use development version of Webpacker" + else + GemfileEntry.version "webpacker", "~> 4.0", "Transpile app-like JavaScript. Read more: https://github.com/rails/webpacker" + end end def jbuilder_gemfile_entry - comment = 'Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder' - GemfileEntry.new 'jbuilder', '~> 2.0', comment, {}, options[:api] - end - - def coffee_gemfile_entry - GemfileEntry.version 'coffee-rails', '~> 4.1.0', 'Use CoffeeScript for .coffee assets and views' + comment = "Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder" + GemfileEntry.new "jbuilder", "~> 2.5", comment, {}, options[:api] end def javascript_gemfile_entry - if options[:skip_javascript] || options[:skip_sprockets] + if options[:skip_javascript] || options[:skip_turbolinks] [] else - gems = [coffee_gemfile_entry, javascript_runtime_gemfile_entry] - gems << GemfileEntry.version("#{options[:javascript]}-rails", nil, - "Use #{options[:javascript]} as the JavaScript library") - - unless options[:skip_turbolinks] - gems << GemfileEntry.version("turbolinks", "~> 5.x", - "Turbolinks makes navigating your web application faster. Read more: https://github.com/turbolinks/turbolinks") - end - - gems - end - end - - def javascript_runtime_gemfile_entry - comment = 'See https://github.com/rails/execjs#readme for more supported runtimes' - if defined?(JRUBY_VERSION) - GemfileEntry.version 'therubyrhino', nil, comment - else - GemfileEntry.new 'therubyracer', nil, comment, { platforms: :ruby }, true + [ GemfileEntry.version("turbolinks", "~> 5", + "Turbolinks makes navigating your web application faster. Read more: https://github.com/turbolinks/turbolinks") ] end end def psych_gemfile_entry return [] unless defined?(Rubinius) - comment = 'Use Psych as the YAML engine, instead of Syck, so serialized ' \ - 'data can be read safely from different rubies (see http://git.io/uuLVag)' - GemfileEntry.new('psych', '~> 2.0', comment, platforms: :rbx) + comment = "Use Psych as the YAML engine, instead of Syck, so serialized " \ + "data can be read safely from different rubies (see http://git.io/uuLVag)" + GemfileEntry.new("psych", "~> 2.0", comment, platforms: :rbx) end def cable_gemfile_entry return [] if options[:skip_action_cable] - comment = 'Use Redis adapter to run Action Cable in production' + comment = "Use Redis adapter to run Action Cable in production" gems = [] - gems << GemfileEntry.new("redis", '~> 3.0', comment, {}, true) + gems << GemfileEntry.new("redis", "~> 4.0", comment, {}, true) gems end - def bundle_command(command) + def bundle_command(command, env = {}) say_status :run, "bundle #{command}" # We are going to shell out rather than invoking Bundler::CLI.new(command) @@ -364,19 +358,21 @@ module Rails # its own vendored Thor, which could be a different version. Running both # things in the same process is a recipe for a night with paracetamol. # - # We unset temporary bundler variables to load proper bundler and Gemfile. - # # Thanks to James Tucker for the Gem tricks involved in this call. - _bundle_command = Gem.bin_path('bundler', 'bundle') + _bundle_command = Gem.bin_path("bundler", "bundle") - require 'bundler' - Bundler.with_clean_env do - full_command = %Q["#{Gem.ruby}" "#{_bundle_command}" #{command}] - if options[:quiet] - system(full_command, out: File::NULL) - else - system(full_command) - end + require "bundler" + Bundler.with_original_env do + exec_bundle_command(_bundle_command, command, env) + end + end + + def exec_bundle_command(bundle_command, command, env) + full_command = %Q["#{Gem.ruby}" "#{bundle_command}" #{command}] + if options[:quiet] + system(env, full_command, out: File::NULL) + else + system(env, full_command) end end @@ -388,16 +384,41 @@ module Rails !options[:skip_spring] && !options.dev? && Process.respond_to?(:fork) && !RUBY_PLATFORM.include?("cygwin") end + def webpack_install? + !(options[:skip_javascript] || options[:skip_webpack_install]) + end + + def depends_on_system_test? + !(options[:skip_system_test] || options[:skip_test] || options[:api]) + end + def depend_on_listen? !options[:skip_listen] && os_supports_listen_out_of_the_box? end + def depend_on_bootsnap? + !options[:skip_bootsnap] && !options[:dev] && !defined?(JRUBY_VERSION) + end + def os_supports_listen_out_of_the_box? - RbConfig::CONFIG['host_os'] =~ /darwin|linux/ + RbConfig::CONFIG["host_os"] =~ /darwin|linux/ end def run_bundle - bundle_command('install') if bundle_install? + bundle_command("install", "BUNDLE_IGNORE_MESSAGES" => "1") if bundle_install? + end + + def run_webpack + if webpack_install? + rails_command "webpacker:install" + rails_command "webpacker:install:#{options[:webpack]}" if options[:webpack] && options[:webpack] != "webpack" + end + end + + def generate_bundler_binstub + if bundle_install? + bundle_command("binstubs bundler") + end end def generate_spring_binstubs diff --git a/railties/lib/rails/generators/app_name.rb b/railties/lib/rails/generators/app_name.rb new file mode 100644 index 0000000000..c4f71694d8 --- /dev/null +++ b/railties/lib/rails/generators/app_name.rb @@ -0,0 +1,50 @@ +# frozen_string_literal: true + +module Rails + module Generators + module AppName # :nodoc: + RESERVED_NAMES = %w(application destroy plugin runner test) + + private + def app_name + @app_name ||= original_app_name.tr("-", "_") + end + + def original_app_name + @original_app_name ||= (defined_app_const_base? ? defined_app_name : File.basename(destination_root)).tr('\\', "").tr(". ", "_") + end + + def defined_app_name + defined_app_const_base.underscore + end + + def defined_app_const_base + Rails.respond_to?(:application) && defined?(Rails::Application) && + Rails.application.is_a?(Rails::Application) && Rails.application.class.name.chomp("::Application") + end + + alias :defined_app_const_base? :defined_app_const_base + + def app_const_base + @app_const_base ||= defined_app_const_base || app_name.gsub(/\W/, "_").squeeze("_").camelize + end + alias :camelized :app_const_base + + def app_const + @app_const ||= "#{app_const_base}::Application" + end + + def valid_const? + if /^\d/.match?(app_const) + raise Error, "Invalid application name #{original_app_name}. Please give a name which does not start with numbers." + elsif RESERVED_NAMES.include?(original_app_name) + raise Error, "Invalid application name #{original_app_name}. Please give a " \ + "name which does not match one of the reserved rails " \ + "words: #{RESERVED_NAMES.join(", ")}" + elsif Object.const_defined?(app_const_base) + raise Error, "Invalid application name #{original_app_name}, constant #{app_const_base} is already in use. Please choose another application name." + end + end + end + end +end diff --git a/railties/lib/rails/generators/base.rb b/railties/lib/rails/generators/base.rb index c72ec400a0..5523a3f659 100644 --- a/railties/lib/rails/generators/base.rb +++ b/railties/lib/rails/generators/base.rb @@ -1,5 +1,7 @@ +# frozen_string_literal: true + begin - require 'thor/group' + require "thor/group" rescue LoadError puts "Thor is not available.\nIf you ran this command from a git checkout " \ "of Rails, please make sure thor is installed,\nand run this command " \ @@ -16,18 +18,21 @@ module Rails include Thor::Actions include Rails::Generators::Actions + class_option :skip_namespace, type: :boolean, default: false, + desc: "Skip namespace (affects only isolated applications)" + add_runtime_options! strict_args_position! # Returns the source root for this generator using default_source_root as default. - def self.source_root(path=nil) + def self.source_root(path = nil) @_source_root = path if path @_source_root ||= default_source_root end # Tries to get the description from a USAGE file one folder above the source # root otherwise uses a default description. - def self.desc(description=nil) + def self.desc(description = nil) return super if description @desc ||= if usage_path @@ -40,15 +45,15 @@ module Rails # Convenience method to get the namespace from the class name. It's the # same as Thor default except that the Generator at the end of the class # is removed. - def self.namespace(name=nil) + def self.namespace(name = nil) return super if name - @namespace ||= super.sub(/_generator$/, '').sub(/:generators:/, ':') + @namespace ||= super.sub(/_generator$/, "").sub(/:generators:/, ":") end # Convenience method to hide this generator from the available ones when # running rails generator command. def self.hide! - Rails::Generators.hide_namespace self.namespace + Rails::Generators.hide_namespace(namespace) end # Invoke a generator based on the value supplied by the user to the @@ -168,7 +173,7 @@ module Rails names.each do |name| unless class_options.key?(name) defaults = if options[:type] == :boolean - { } + {} elsif [true, false].include?(default_value_for_option(name, options)) { banner: "" } else @@ -195,7 +200,7 @@ module Rails end # Make class option aware of Rails::Generators.options and Rails::Generators.aliases. - def self.class_option(name, options={}) #:nodoc: + def self.class_option(name, options = {}) #:nodoc: options[:desc] = "Indicates when to generate #{name.to_s.humanize.downcase}" unless options.key?(:desc) options[:aliases] = default_aliases_for_option(name, options) options[:default] = default_value_for_option(name, options) @@ -208,14 +213,14 @@ module Rails def self.default_source_root return unless base_name && generator_name return unless default_generator_root - path = File.join(default_generator_root, 'templates') + path = File.join(default_generator_root, "templates") path if File.exist?(path) end # Returns the base root for a common set of generators. This is used to dynamically # guess the default source root. def self.base_root - File.dirname(__FILE__) + __dir__ end # Cache source root and add lib/generators/base/generator/templates to @@ -230,7 +235,7 @@ module Rails Rails::Generators.subclasses << base Rails::Generators.templates_path.each do |path| - if base.name.include?('::') + if base.name.include?("::") base.source_paths << File.join(path, base.base_name, base.generator_name) else base.source_paths << File.join(path, base.generator_name) @@ -239,11 +244,11 @@ module Rails end end - protected + private # Check whether the given class names are already taken by user # application or Ruby on Rails. - def class_collisions(*class_names) #:nodoc: + def class_collisions(*class_names) return unless behavior == :invoke class_names.flatten.each do |class_name| @@ -251,35 +256,69 @@ module Rails next if class_name.strip.empty? # Split the class from its module nesting - nesting = class_name.split('::') + nesting = class_name.split("::") last_name = nesting.pop last = extract_last_module(nesting) if last && last.const_defined?(last_name.camelize, false) - raise Error, "The name '#{class_name}' is either already used in your application " << - "or reserved by Ruby on Rails. Please choose an alternative and run " << + raise Error, "The name '#{class_name}' is either already used in your application " \ + "or reserved by Ruby on Rails. Please choose an alternative and run " \ "this generator again." end end end # Takes in an array of nested modules and extracts the last module - def extract_last_module(nesting) + def extract_last_module(nesting) # :doc: nesting.inject(Object) do |last_module, nest| break unless last_module.const_defined?(nest, false) last_module.const_get(nest) end end + # Wrap block with namespace of current application + # if namespace exists and is not skipped + def module_namespacing(&block) # :doc: + content = capture(&block) + content = wrap_with_namespace(content) if namespaced? + concat(content) + end + + def indent(content, multiplier = 2) # :doc: + spaces = " " * multiplier + content.each_line.map { |line| line.blank? ? line : "#{spaces}#{line}" }.join + end + + def wrap_with_namespace(content) # :doc: + content = indent(content).chomp + "module #{namespace.name}\n#{content}\nend\n" + end + + def namespace # :doc: + Rails::Generators.namespace + end + + def namespaced? # :doc: + !options[:skip_namespace] && namespace + end + + def namespace_dirs + @namespace_dirs ||= namespace.name.split("::").map(&:underscore) + end + + def namespaced_path # :doc: + @namespaced_path ||= namespace_dirs.join("/") + end + # Use Rails default banner. - def self.banner - "rails generate #{namespace.sub(/^rails:/,'')} #{self.arguments.map(&:usage).join(' ')} [options]".gsub(/\s+/, ' ') + def self.banner # :doc: + "rails generate #{namespace.sub(/^rails:/, '')} #{arguments.map(&:usage).join(' ')} [options]".gsub(/\s+/, " ") end # Sets the base_name taking into account the current class namespace. - def self.base_name + def self.base_name # :doc: @base_name ||= begin - if base = name.to_s.split('::').first + if base = name.to_s.split("::").first base.underscore end end @@ -287,10 +326,10 @@ module Rails # Removes the namespaces and get the generator name. For example, # Rails::Generators::ModelGenerator will return "model" as generator name. - def self.generator_name + def self.generator_name # :doc: @generator_name ||= begin - if generator = name.to_s.split('::').last - generator.sub!(/Generator$/, '') + if generator = name.to_s.split("::").last + generator.sub!(/Generator$/, "") generator.underscore end end @@ -298,21 +337,21 @@ module Rails # Returns the default value for the option name given doing a lookup in # Rails::Generators.options. - def self.default_value_for_option(name, options) + def self.default_value_for_option(name, options) # :doc: default_for_option(Rails::Generators.options, name, options, options[:default]) end # Returns default aliases for the option name given doing a lookup in # Rails::Generators.aliases. - def self.default_aliases_for_option(name, options) + def self.default_aliases_for_option(name, options) # :doc: default_for_option(Rails::Generators.aliases, name, options, options[:aliases]) end # Returns default for the option name given doing a lookup in config. - def self.default_for_option(config, name, options, default) - if generator_name and c = config[generator_name.to_sym] and c.key?(name) + def self.default_for_option(config, name, options, default) # :doc: + if generator_name && (c = config[generator_name.to_sym]) && c.key?(name) c[name] - elsif base_name and c = config[base_name.to_sym] and c.key?(name) + elsif base_name && (c = config[base_name.to_sym]) && c.key?(name) c[name] elsif config[:rails].key?(name) config[:rails][name] @@ -331,7 +370,7 @@ module Rails def self.prepare_for_invocation(name, value) #:nodoc: return super unless value.is_a?(String) || value.is_a?(Symbol) - if value && constants = self.hooks[name] + if value && constants = hooks[name] value = name if TrueClass === value Rails::Generators.find_by_namespace(value, *constants) elsif klass = Rails::Generators.find_by_namespace(value) @@ -343,7 +382,7 @@ module Rails # Small macro to add ruby as an option to the generator with proper # default value plus an instance helper method called shebang. - def self.add_shebang_option! + def self.add_shebang_option! # :doc: class_option :ruby, type: :string, aliases: "-r", default: Thor::Util.ruby_command, desc: "Path to the Ruby binary of your choice", banner: "PATH" @@ -361,7 +400,7 @@ module Rails } end - def self.usage_path + def self.usage_path # :doc: paths = [ source_root && File.expand_path("../USAGE", source_root), default_generator_root && File.join(default_generator_root, "USAGE") @@ -369,11 +408,10 @@ module Rails paths.compact.detect { |path| File.exist? path } end - def self.default_generator_root + def self.default_generator_root # :doc: path = File.expand_path(File.join(base_name, generator_name), base_root) path if File.exist?(path) end - end end end diff --git a/railties/lib/rails/generators/css/assets/assets_generator.rb b/railties/lib/rails/generators/css/assets/assets_generator.rb index e4a305f4b3..f657d1e50f 100644 --- a/railties/lib/rails/generators/css/assets/assets_generator.rb +++ b/railties/lib/rails/generators/css/assets/assets_generator.rb @@ -1,12 +1,14 @@ +# frozen_string_literal: true + require "rails/generators/named_base" module Css # :nodoc: module Generators # :nodoc: class AssetsGenerator < Rails::Generators::NamedBase # :nodoc: - source_root File.expand_path("../templates", __FILE__) + source_root File.expand_path("templates", __dir__) def copy_stylesheet - copy_file "stylesheet.css", File.join('app/assets/stylesheets', class_path, "#{file_name}.css") + copy_file "stylesheet.css", File.join("app/assets/stylesheets", class_path, "#{file_name}.css") end end end diff --git a/railties/lib/rails/generators/css/scaffold/scaffold_generator.rb b/railties/lib/rails/generators/css/scaffold/scaffold_generator.rb index cf534030f9..89c560f382 100644 --- a/railties/lib/rails/generators/css/scaffold/scaffold_generator.rb +++ b/railties/lib/rails/generators/css/scaffold/scaffold_generator.rb @@ -1,15 +1,17 @@ +# frozen_string_literal: true + require "rails/generators/named_base" module Css # :nodoc: module Generators # :nodoc: class ScaffoldGenerator < Rails::Generators::NamedBase # :nodoc: + source_root Rails::Generators::ScaffoldGenerator.source_root + # In order to allow the Sass generators to pick up the default Rails CSS and # transform it, we leave it in a standard location for the CSS stylesheet # generators to handle. For the simple, default case, just copy it over. def copy_stylesheet - dir = Rails::Generators::ScaffoldGenerator.source_root - file = File.join(dir, "scaffold.css") - create_file "app/assets/stylesheets/scaffold.css", File.read(file) + copy_file "scaffold.css", "app/assets/stylesheets/scaffold.css" end end end diff --git a/railties/lib/rails/generators/database.rb b/railties/lib/rails/generators/database.rb new file mode 100644 index 0000000000..18fc7be3ff --- /dev/null +++ b/railties/lib/rails/generators/database.rb @@ -0,0 +1,58 @@ +# frozen_string_literal: true + +module Rails + module Generators + module Database # :nodoc: + JDBC_DATABASES = %w( jdbcmysql jdbcsqlite3 jdbcpostgresql jdbc ) + DATABASES = %w( mysql postgresql sqlite3 oracle frontbase ibm_db sqlserver ) + JDBC_DATABASES + + def initialize(*) + super + convert_database_option_for_jruby + end + + def gem_for_database(database = options[:database]) + case database + when "mysql" then ["mysql2", [">= 0.4.4"]] + when "postgresql" then ["pg", [">= 0.18", "< 2.0"]] + when "sqlite3" then ["sqlite3", ["~> 1.3", ">= 1.3.6"]] + when "oracle" then ["activerecord-oracle_enhanced-adapter", nil] + when "frontbase" then ["ruby-frontbase", nil] + when "sqlserver" then ["activerecord-sqlserver-adapter", nil] + when "jdbcmysql" then ["activerecord-jdbcmysql-adapter", nil] + when "jdbcsqlite3" then ["activerecord-jdbcsqlite3-adapter", nil] + when "jdbcpostgresql" then ["activerecord-jdbcpostgresql-adapter", nil] + when "jdbc" then ["activerecord-jdbc-adapter", nil] + else [database, nil] + end + end + + def convert_database_option_for_jruby + if defined?(JRUBY_VERSION) + opt = options.dup + case opt[:database] + when "postgresql" then opt[:database] = "jdbcpostgresql" + when "mysql" then opt[:database] = "jdbcmysql" + when "sqlite3" then opt[:database] = "jdbcsqlite3" + end + self.options = opt.freeze + end + end + + private + def mysql_socket + @mysql_socket ||= [ + "/tmp/mysql.sock", # default + "/var/run/mysqld/mysqld.sock", # debian/gentoo + "/var/tmp/mysql.sock", # freebsd + "/var/lib/mysql/mysql.sock", # fedora + "/opt/local/lib/mysql/mysql.sock", # fedora + "/opt/local/var/run/mysqld/mysqld.sock", # mac + darwinports + mysql + "/opt/local/var/run/mysql4/mysqld.sock", # mac + darwinports + mysql4 + "/opt/local/var/run/mysql5/mysqld.sock", # mac + darwinports + mysql5 + "/opt/lampp/var/mysql/mysql.sock" # xampp for linux + ].find { |f| File.exist?(f) } unless Gem.win_platform? + end + end + end +end diff --git a/railties/lib/rails/generators/erb.rb b/railties/lib/rails/generators/erb.rb index 0755ac335c..ba20bcd32a 100644 --- a/railties/lib/rails/generators/erb.rb +++ b/railties/lib/rails/generators/erb.rb @@ -1,25 +1,27 @@ -require 'rails/generators/named_base' +# frozen_string_literal: true + +require "rails/generators/named_base" module Erb # :nodoc: module Generators # :nodoc: class Base < Rails::Generators::NamedBase #:nodoc: - protected + private - def formats - [format] - end + def formats + [format] + end - def format - :html - end + def format + :html + end - def handler - :erb - end + def handler + :erb + end - def filename_with_extensions(name, format = self.format) - [name, format, handler].compact.join(".") - end + def filename_with_extensions(name, file_format = format) + [name, file_format, handler].compact.join(".") + end end end end diff --git a/railties/lib/rails/generators/erb/controller/controller_generator.rb b/railties/lib/rails/generators/erb/controller/controller_generator.rb index 94c1b835d1..8e13744b2a 100644 --- a/railties/lib/rails/generators/erb/controller/controller_generator.rb +++ b/railties/lib/rails/generators/erb/controller/controller_generator.rb @@ -1,4 +1,6 @@ -require 'rails/generators/erb' +# frozen_string_literal: true + +require "rails/generators/erb" module Erb # :nodoc: module Generators # :nodoc: diff --git a/railties/lib/rails/generators/erb/controller/templates/view.html.erb b/railties/lib/rails/generators/erb/controller/templates/view.html.erb.tt index cd54d13d83..cd54d13d83 100644 --- a/railties/lib/rails/generators/erb/controller/templates/view.html.erb +++ b/railties/lib/rails/generators/erb/controller/templates/view.html.erb.tt diff --git a/railties/lib/rails/generators/erb/mailer/mailer_generator.rb b/railties/lib/rails/generators/erb/mailer/mailer_generator.rb index 7f00943d80..997602cb8c 100644 --- a/railties/lib/rails/generators/erb/mailer/mailer_generator.rb +++ b/railties/lib/rails/generators/erb/mailer/mailer_generator.rb @@ -1,4 +1,6 @@ -require 'rails/generators/erb' +# frozen_string_literal: true + +require "rails/generators/erb" module Erb # :nodoc: module Generators # :nodoc: @@ -6,9 +8,16 @@ module Erb # :nodoc: argument :actions, type: :array, default: [], banner: "method method" def copy_view_files - view_base_path = File.join("app/views", class_path, file_name + '_mailer') + view_base_path = File.join("app/views", class_path, file_name + "_mailer") empty_directory view_base_path + if behavior == :invoke + formats.each do |format| + layout_path = File.join("app/views/layouts", class_path, filename_with_extensions("mailer", format)) + template filename_with_extensions(:layout, format), layout_path unless File.exist?(layout_path) + end + end + actions.each do |action| @action = action @@ -19,15 +28,15 @@ module Erb # :nodoc: end end - protected + private - def formats - [:text, :html] - end + def formats + [:text, :html] + end - def file_name - @_file_name ||= super.gsub(/_mailer/i, '') - end + def file_name + @_file_name ||= super.sub(/_mailer\z/i, "") + end end end end diff --git a/railties/lib/rails/generators/erb/mailer/templates/layout.html.erb.tt b/railties/lib/rails/generators/erb/mailer/templates/layout.html.erb.tt new file mode 100644 index 0000000000..55f3675d49 --- /dev/null +++ b/railties/lib/rails/generators/erb/mailer/templates/layout.html.erb.tt @@ -0,0 +1,13 @@ +<!DOCTYPE html> +<html> + <head> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> + <style> + /* Email styles need to be inline */ + </style> + </head> + + <body> + <%%= yield %> + </body> +</html> diff --git a/railties/lib/rails/generators/erb/mailer/templates/layout.text.erb.tt b/railties/lib/rails/generators/erb/mailer/templates/layout.text.erb.tt new file mode 100644 index 0000000000..6363733e6e --- /dev/null +++ b/railties/lib/rails/generators/erb/mailer/templates/layout.text.erb.tt @@ -0,0 +1 @@ +<%%= yield %> diff --git a/railties/lib/rails/generators/erb/mailer/templates/view.html.erb b/railties/lib/rails/generators/erb/mailer/templates/view.html.erb.tt index b5045671b3..b5045671b3 100644 --- a/railties/lib/rails/generators/erb/mailer/templates/view.html.erb +++ b/railties/lib/rails/generators/erb/mailer/templates/view.html.erb.tt diff --git a/railties/lib/rails/generators/erb/mailer/templates/view.text.erb b/railties/lib/rails/generators/erb/mailer/templates/view.text.erb.tt index 342285df19..342285df19 100644 --- a/railties/lib/rails/generators/erb/mailer/templates/view.text.erb +++ b/railties/lib/rails/generators/erb/mailer/templates/view.text.erb.tt diff --git a/railties/lib/rails/generators/erb/scaffold/scaffold_generator.rb b/railties/lib/rails/generators/erb/scaffold/scaffold_generator.rb index c94829a0ae..2fc04e4094 100644 --- a/railties/lib/rails/generators/erb/scaffold/scaffold_generator.rb +++ b/railties/lib/rails/generators/erb/scaffold/scaffold_generator.rb @@ -1,5 +1,7 @@ -require 'rails/generators/erb' -require 'rails/generators/resource_helpers' +# frozen_string_literal: true + +require "rails/generators/erb" +require "rails/generators/resource_helpers" module Erb # :nodoc: module Generators # :nodoc: @@ -21,7 +23,7 @@ module Erb # :nodoc: end end - protected + private def available_views %w(index edit show new _form) diff --git a/railties/lib/rails/generators/erb/scaffold/templates/_form.html.erb b/railties/lib/rails/generators/erb/scaffold/templates/_form.html.erb deleted file mode 100644 index 519b6c8603..0000000000 --- a/railties/lib/rails/generators/erb/scaffold/templates/_form.html.erb +++ /dev/null @@ -1,34 +0,0 @@ -<%%= form_for(<%= singular_table_name %>) do |f| %> - <%% if <%= singular_table_name %>.errors.any? %> - <div id="error_explanation"> - <h2><%%= pluralize(<%= singular_table_name %>.errors.count, "error") %> prohibited this <%= singular_table_name %> from being saved:</h2> - - <ul> - <%% <%= singular_table_name %>.errors.full_messages.each do |message| %> - <li><%%= message %></li> - <%% end %> - </ul> - </div> - <%% end %> - -<% attributes.each do |attribute| -%> - <div class="field"> -<% if attribute.password_digest? -%> - <%%= f.label :password %> - <%%= f.password_field :password %> - </div> - - <div class="field"> - <%%= f.label :password_confirmation %> - <%%= f.password_field :password_confirmation %> -<% else -%> - <%%= f.label :<%= attribute.column_name %> %> - <%%= f.<%= attribute.field_type %> :<%= attribute.column_name %> %> -<% end -%> - </div> - -<% end -%> - <div class="actions"> - <%%= f.submit %> - </div> -<%% end %> diff --git a/railties/lib/rails/generators/erb/scaffold/templates/_form.html.erb.tt b/railties/lib/rails/generators/erb/scaffold/templates/_form.html.erb.tt new file mode 100644 index 0000000000..1dddc3d698 --- /dev/null +++ b/railties/lib/rails/generators/erb/scaffold/templates/_form.html.erb.tt @@ -0,0 +1,37 @@ +<%%= form_with(model: <%= model_resource_name %>, local: true) do |form| %> + <%% if <%= singular_table_name %>.errors.any? %> + <div id="error_explanation"> + <h2><%%= pluralize(<%= singular_table_name %>.errors.count, "error") %> prohibited this <%= singular_table_name %> from being saved:</h2> + + <ul> + <%% <%= singular_table_name %>.errors.full_messages.each do |message| %> + <li><%%= message %></li> + <%% end %> + </ul> + </div> + <%% end %> + +<% attributes.each do |attribute| -%> + <div class="field"> +<% if attribute.password_digest? -%> + <%%= form.label :password %> + <%%= form.password_field :password %> + </div> + + <div class="field"> + <%%= form.label :password_confirmation %> + <%%= form.password_field :password_confirmation %> +<% elsif attribute.attachments? -%> + <%%= form.label :<%= attribute.column_name %> %> + <%%= form.<%= attribute.field_type %> :<%= attribute.column_name %>, multiple: true %> +<% else -%> + <%%= form.label :<%= attribute.column_name %> %> + <%%= form.<%= attribute.field_type %> :<%= attribute.column_name %> %> +<% end -%> + </div> + +<% end -%> + <div class="actions"> + <%%= form.submit %> + </div> +<%% end %> diff --git a/railties/lib/rails/generators/erb/scaffold/templates/edit.html.erb b/railties/lib/rails/generators/erb/scaffold/templates/edit.html.erb.tt index 81329473d9..81329473d9 100644 --- a/railties/lib/rails/generators/erb/scaffold/templates/edit.html.erb +++ b/railties/lib/rails/generators/erb/scaffold/templates/edit.html.erb.tt diff --git a/railties/lib/rails/generators/erb/scaffold/templates/index.html.erb b/railties/lib/rails/generators/erb/scaffold/templates/index.html.erb.tt index 5f4904fee1..2cf4e5c9d0 100644 --- a/railties/lib/rails/generators/erb/scaffold/templates/index.html.erb +++ b/railties/lib/rails/generators/erb/scaffold/templates/index.html.erb.tt @@ -16,11 +16,11 @@ <%% @<%= plural_table_name %>.each do |<%= singular_table_name %>| %> <tr> <% attributes.reject(&:password_digest?).each do |attribute| -%> - <td><%%= <%= singular_table_name %>.<%= attribute.name %> %></td> + <td><%%= <%= singular_table_name %>.<%= attribute.column_name %> %></td> <% end -%> - <td><%%= link_to 'Show', <%= singular_table_name %> %></td> - <td><%%= link_to 'Edit', edit_<%= singular_table_name %>_path(<%= singular_table_name %>) %></td> - <td><%%= link_to 'Destroy', <%= singular_table_name %>, method: :delete, data: { confirm: 'Are you sure?' } %></td> + <td><%%= link_to 'Show', <%= model_resource_name %> %></td> + <td><%%= link_to 'Edit', edit_<%= singular_route_name %>_path(<%= singular_table_name %>) %></td> + <td><%%= link_to 'Destroy', <%= model_resource_name %>, method: :delete, data: { confirm: 'Are you sure?' } %></td> </tr> <%% end %> </tbody> @@ -28,4 +28,4 @@ <br> -<%%= link_to 'New <%= singular_table_name.titleize %>', new_<%= singular_table_name %>_path %> +<%%= link_to 'New <%= singular_table_name.titleize %>', new_<%= singular_route_name %>_path %> diff --git a/railties/lib/rails/generators/erb/scaffold/templates/new.html.erb b/railties/lib/rails/generators/erb/scaffold/templates/new.html.erb.tt index 9b2b2f4875..9b2b2f4875 100644 --- a/railties/lib/rails/generators/erb/scaffold/templates/new.html.erb +++ b/railties/lib/rails/generators/erb/scaffold/templates/new.html.erb.tt diff --git a/railties/lib/rails/generators/erb/scaffold/templates/show.html.erb b/railties/lib/rails/generators/erb/scaffold/templates/show.html.erb deleted file mode 100644 index 5e634153be..0000000000 --- a/railties/lib/rails/generators/erb/scaffold/templates/show.html.erb +++ /dev/null @@ -1,11 +0,0 @@ -<p id="notice"><%%= notice %></p> - -<% attributes.reject(&:password_digest?).each do |attribute| -%> -<p> - <strong><%= attribute.human_name %>:</strong> - <%%= @<%= singular_table_name %>.<%= attribute.name %> %> -</p> - -<% end -%> -<%%= link_to 'Edit', edit_<%= singular_table_name %>_path(@<%= singular_table_name %>) %> | -<%%= link_to 'Back', <%= index_helper %>_path %> diff --git a/railties/lib/rails/generators/erb/scaffold/templates/show.html.erb.tt b/railties/lib/rails/generators/erb/scaffold/templates/show.html.erb.tt new file mode 100644 index 0000000000..6b216001d2 --- /dev/null +++ b/railties/lib/rails/generators/erb/scaffold/templates/show.html.erb.tt @@ -0,0 +1,19 @@ +<p id="notice"><%%= notice %></p> + +<% attributes.reject(&:password_digest?).each do |attribute| -%> +<p> + <strong><%= attribute.human_name %>:</strong> +<% if attribute.attachment? -%> + <%%= link_to @<%= singular_table_name %>.<%= attribute.column_name %>.filename, @<%= singular_table_name %>.<%= attribute.column_name %> %> +<% elsif attribute.attachments? -%> + <%% @<%= singular_table_name %>.<%= attribute.column_name %>.each do |<%= attribute.singular_name %>| %> + <div><%%= link_to <%= attribute.singular_name %>.filename, <%= attribute.singular_name %> %></div> + <%% end %> +<% else -%> + <%%= @<%= singular_table_name %>.<%= attribute.column_name %> %> +<% end -%> +</p> + +<% end -%> +<%%= link_to 'Edit', edit_<%= singular_table_name %>_path(@<%= singular_table_name %>) %> | +<%%= link_to 'Back', <%= index_helper %>_path %> diff --git a/railties/lib/rails/generators/generated_attribute.rb b/railties/lib/rails/generators/generated_attribute.rb index 7e437e7344..99c1bc4269 100644 --- a/railties/lib/rails/generators/generated_attribute.rb +++ b/railties/lib/rails/generators/generated_attribute.rb @@ -1,4 +1,6 @@ -require 'active_support/time' +# frozen_string_literal: true + +require "active_support/time" module Rails module Generators @@ -12,7 +14,7 @@ module Rails class << self def parse(column_definition) - name, type, has_index = column_definition.split(':') + name, type, has_index = column_definition.split(":") # if user provided "name:index" instead of "name:string:index" # type should be set blank so GeneratedAttribute's constructor @@ -37,26 +39,26 @@ module Rails private - # parse possible attribute options like :limit for string/text/binary/integer, :precision/:scale for decimals or :polymorphic for references/belongs_to - # when declaring options curly brackets should be used - def parse_type_and_options(type) - case type - when /(string|text|binary|integer)\{(\d+)\}/ - return $1, limit: $2.to_i - when /decimal\{(\d+)[,.-](\d+)\}/ - return :decimal, precision: $1.to_i, scale: $2.to_i - when /(references|belongs_to)\{(.+)\}/ - type = $1 - provided_options = $2.split(/[,.-]/) - options = Hash[provided_options.map { |opt| [opt.to_sym, true] }] - return type, options - else - return type, {} + # parse possible attribute options like :limit for string/text/binary/integer, :precision/:scale for decimals or :polymorphic for references/belongs_to + # when declaring options curly brackets should be used + def parse_type_and_options(type) + case type + when /(string|text|binary|integer)\{(\d+)\}/ + return $1, limit: $2.to_i + when /decimal\{(\d+)[,.-](\d+)\}/ + return :decimal, precision: $1.to_i, scale: $2.to_i + when /(references|belongs_to)\{(.+)\}/ + type = $1 + provided_options = $2.split(/[,.-]/) + options = Hash[provided_options.map { |opt| [opt.to_sym, true] }] + return type, options + else + return type, {} + end end - end end - def initialize(name, type=nil, index_type=false, attr_options={}) + def initialize(name, type = nil, index_type = false, attr_options = {}) @name = name @type = type || :string @has_index = INDEX_OPTIONS.include?(index_type) @@ -66,40 +68,44 @@ module Rails def field_type @field_type ||= case type - when :integer then :number_field - when :float, :decimal then :text_field - when :time then :time_select - when :datetime, :timestamp then :datetime_select - when :date then :date_select - when :text then :text_area - when :boolean then :check_box - else - :text_field + when :integer then :number_field + when :float, :decimal then :text_field + when :time then :time_select + when :datetime, :timestamp then :datetime_select + when :date then :date_select + when :text then :text_area + when :rich_text then :rich_text_area + when :boolean then :check_box + when :attachment, :attachments then :file_field + else + :text_field end end def default @default ||= case type - when :integer then 1 - when :float then 1.5 - when :decimal then "9.99" - when :datetime, :timestamp, :time then Time.now.to_s(:db) - when :date then Date.today.to_s(:db) - when :string then name == "type" ? "" : "MyString" - when :text then "MyText" - when :boolean then false - when :references, :belongs_to then nil - else - "" + when :integer then 1 + when :float then 1.5 + when :decimal then "9.99" + when :datetime, :timestamp, :time then Time.now.to_s(:db) + when :date then Date.today.to_s(:db) + when :string then name == "type" ? "" : "MyString" + when :text then "MyText" + when :boolean then false + when :references, :belongs_to, + :attachment, :attachments, + :rich_text then nil + else + "" end end def plural_name - name.sub(/_id$/, '').pluralize + name.sub(/_id$/, "").pluralize end def singular_name - name.sub(/_id$/, '').singularize + name.sub(/_id$/, "").singularize end def human_name @@ -127,11 +133,11 @@ module Rails end def polymorphic? - self.attr_options[:polymorphic] + attr_options[:polymorphic] end def required? - self.attr_options[:required] + attr_options[:required] end def has_index? @@ -143,15 +149,31 @@ module Rails end def password_digest? - name == 'password' && type == :digest + name == "password" && type == :digest end def token? type == :token end + def rich_text? + type == :rich_text + end + + def attachment? + type == :attachment + end + + def attachments? + type == :attachments + end + + def virtual? + rich_text? || attachment? || attachments? + end + def inject_options - "".tap { |s| options_for_migration.each { |k,v| s << ", #{k}: #{v.inspect}" } } + (+"").tap { |s| options_for_migration.each { |k, v| s << ", #{k}: #{v.inspect}" } } end def inject_index_options diff --git a/railties/lib/rails/generators/js/assets/assets_generator.rb b/railties/lib/rails/generators/js/assets/assets_generator.rb deleted file mode 100644 index 1e925b2cd2..0000000000 --- a/railties/lib/rails/generators/js/assets/assets_generator.rb +++ /dev/null @@ -1,13 +0,0 @@ -require "rails/generators/named_base" - -module Js # :nodoc: - module Generators # :nodoc: - class AssetsGenerator < Rails::Generators::NamedBase # :nodoc: - source_root File.expand_path("../templates", __FILE__) - - def copy_javascript - copy_file "javascript.js", File.join('app/assets/javascripts', class_path, "#{file_name}.js") - end - end - end -end diff --git a/railties/lib/rails/generators/js/assets/templates/javascript.js b/railties/lib/rails/generators/js/assets/templates/javascript.js deleted file mode 100644 index dee720facd..0000000000 --- a/railties/lib/rails/generators/js/assets/templates/javascript.js +++ /dev/null @@ -1,2 +0,0 @@ -// Place all the behaviors and hooks related to the matching controller here. -// All this logic will automatically be available in application.js. diff --git a/railties/lib/rails/generators/migration.rb b/railties/lib/rails/generators/migration.rb index 87f2e1d42b..b6ec0160cf 100644 --- a/railties/lib/rails/generators/migration.rb +++ b/railties/lib/rails/generators/migration.rb @@ -1,5 +1,7 @@ -require 'active_support/concern' -require 'rails/generators/actions/create_migration' +# frozen_string_literal: true + +require "active_support/concern" +require "rails/generators/actions/create_migration" module Rails module Generators @@ -35,11 +37,11 @@ module Rails end def set_migration_assigns!(destination) - destination = File.expand_path(destination, self.destination_root) + destination = File.expand_path(destination, destination_root) migration_dir = File.dirname(destination) @migration_number = self.class.next_migration_number(migration_dir) - @migration_file_name = File.basename(destination, '.rb') + @migration_file_name = File.basename(destination, ".rb") @migration_class_name = @migration_file_name.camelize end @@ -52,16 +54,20 @@ module Rails # # migration_template "migration.rb", "db/migrate/add_foo_to_bar.rb" def migration_template(source, destination, config = {}) - source = File.expand_path(find_in_source_paths(source.to_s)) + source = File.expand_path(find_in_source_paths(source.to_s)) set_migration_assigns!(destination) - context = instance_eval('binding') + context = instance_eval("binding") dir, base = File.split(destination) - numbered_destination = File.join(dir, ["%migration_number%", base].join('_')) + numbered_destination = File.join(dir, ["%migration_number%", base].join("_")) create_migration numbered_destination, nil, config do - ERB.new(::File.binread(source), nil, '-', '@output_buffer').result(context) + if ERB.instance_method(:initialize).parameters.assoc(:key) # Ruby 2.6+ + ERB.new(::File.binread(source), trim_mode: "-", eoutvar: "@output_buffer").result(context) + else + ERB.new(::File.binread(source), nil, "-", "@output_buffer").result(context) + end end end end diff --git a/railties/lib/rails/generators/model_helpers.rb b/railties/lib/rails/generators/model_helpers.rb index 42c646543e..3676432d5c 100644 --- a/railties/lib/rails/generators/model_helpers.rb +++ b/railties/lib/rails/generators/model_helpers.rb @@ -1,14 +1,20 @@ -require 'rails/generators/active_model' +# frozen_string_literal: true + +require "rails/generators/active_model" module Rails module Generators module ModelHelpers # :nodoc: PLURAL_MODEL_NAME_WARN_MESSAGE = "[WARNING] The model name '%s' was recognized as a plural, using the singular '%s' instead. " \ "Override with --force-plural or setup custom inflection rules for this noun before running the generator." + IRREGULAR_MODEL_NAME_WARN_MESSAGE = <<~WARNING + [WARNING] Rails cannot recover singular form from its plural form '%s'. + Please setup custom inflection rules for this noun before running the generator in config/initializers/inflections.rb. + WARNING mattr_accessor :skip_warn def self.included(base) #:nodoc: - base.class_option :force_plural, type: :boolean, default: false, desc: 'Forces the use of the given model name' + base.class_option :force_plural, type: :boolean, default: false, desc: "Forces the use of the given model name" end def initialize(args, *_options) @@ -17,11 +23,14 @@ module Rails singular = name.singularize unless ModelHelpers.skip_warn say PLURAL_MODEL_NAME_WARN_MESSAGE % [name, singular] - ModelHelpers.skip_warn = true end name.replace singular assign_names!(name) end + if name.singularize != name.pluralize.singularize && ! ModelHelpers.skip_warn + say IRREGULAR_MODEL_NAME_WARN_MESSAGE % [name.pluralize] + end + ModelHelpers.skip_warn = true end end end diff --git a/railties/lib/rails/generators/named_base.rb b/railties/lib/rails/generators/named_base.rb index efbf51ddfb..42e64cd11f 100644 --- a/railties/lib/rails/generators/named_base.rb +++ b/railties/lib/rails/generators/named_base.rb @@ -1,20 +1,19 @@ -require 'active_support/core_ext/module/introspection' -require 'rails/generators/base' -require 'rails/generators/generated_attribute' +# frozen_string_literal: true + +require "rails/generators/base" +require "rails/generators/generated_attribute" module Rails module Generators class NamedBase < Base argument :name, type: :string - class_option :skip_namespace, type: :boolean, default: false, - desc: "Skip namespace (affects only isolated applications)" def initialize(args, *options) #:nodoc: @inside_template = nil # Unfreeze name in case it's given as a frozen string args[0] = args[0].dup if args[0].is_a?(String) && args[0].frozen? super - assign_names!(self.name) + assign_names!(name) parse_attributes! if respond_to?(:attributes) end @@ -26,180 +25,180 @@ module Rails super end end + + def js_template(source, destination) + template(source + ".js", destination + ".js") + end end - protected + private attr_reader :file_name # FIXME: We are avoiding to use alias because a bug on thor that make # this method public and add it to the task list. - def singular_name + def singular_name # :doc: file_name end - # Wrap block with namespace of current application - # if namespace exists and is not skipped - def module_namespacing(&block) - content = capture(&block) - content = wrap_with_namespace(content) if namespaced? - concat(content) - end - - def indent(content, multiplier = 2) - spaces = " " * multiplier - content.each_line.map {|line| line.blank? ? line : "#{spaces}#{line}" }.join - end - - def wrap_with_namespace(content) - content = indent(content).chomp - "module #{namespace.name}\n#{content}\nend\n" - end - - def inside_template + def inside_template # :doc: @inside_template = true yield ensure @inside_template = false end - def inside_template? + def inside_template? # :doc: @inside_template end - def namespace - Rails::Generators.namespace - end - - def namespaced? - !options[:skip_namespace] && namespace - end - - def file_path - @file_path ||= (class_path + [file_name]).join('/') + def file_path # :doc: + @file_path ||= (class_path + [file_name]).join("/") end - def class_path + def class_path # :doc: inside_template? || !namespaced? ? regular_class_path : namespaced_class_path end - def regular_class_path + def regular_class_path # :doc: @class_path end - def namespaced_file_path - @namespaced_file_path ||= namespaced_class_path.join("/") - end - - def namespaced_class_path - @namespaced_class_path ||= [namespaced_path] + @class_path + def namespaced_class_path # :doc: + @namespaced_class_path ||= namespace_dirs + @class_path end - def namespaced_path - @namespaced_path ||= namespace.name.split("::").first.underscore + def class_name # :doc: + (class_path + [file_name]).map!(&:camelize).join("::") end - def class_name - (class_path + [file_name]).map!(&:camelize).join('::') - end - - def human_name + def human_name # :doc: @human_name ||= singular_name.humanize end - def plural_name + def plural_name # :doc: @plural_name ||= singular_name.pluralize end - def i18n_scope - @i18n_scope ||= file_path.tr('/', '.') + def i18n_scope # :doc: + @i18n_scope ||= file_path.tr("/", ".") end - def table_name + def table_name # :doc: @table_name ||= begin base = pluralize_table_names? ? plural_name : singular_name - (class_path + [base]).join('_') + (class_path + [base]).join("_") end end - def uncountable? + def uncountable? # :doc: singular_name == plural_name end - def index_helper - uncountable? ? "#{plural_table_name}_index" : plural_table_name + def index_helper # :doc: + uncountable? ? "#{plural_route_name}_index" : plural_route_name end - def show_helper - "#{singular_table_name}_url(@#{singular_table_name})" + def show_helper # :doc: + "#{singular_route_name}_url(@#{singular_table_name})" end - def edit_helper + def edit_helper # :doc: "edit_#{show_helper}" end - def new_helper - "new_#{singular_table_name}_url" + def new_helper # :doc: + "new_#{singular_route_name}_url" end - def singular_table_name + def singular_table_name # :doc: @singular_table_name ||= (pluralize_table_names? ? table_name.singularize : table_name) end - def plural_table_name + def plural_table_name # :doc: @plural_table_name ||= (pluralize_table_names? ? table_name : table_name.pluralize) end - def plural_file_name + def plural_file_name # :doc: @plural_file_name ||= file_name.pluralize end - def fixture_file_name + def fixture_file_name # :doc: @fixture_file_name ||= (pluralize_table_names? ? plural_file_name : file_name) end - def route_url - @route_url ||= class_path.collect {|dname| "/" + dname }.join + "/" + plural_file_name + def route_url # :doc: + @route_url ||= class_path.collect { |dname| "/" + dname }.join + "/" + plural_file_name end - def url_helper_prefix - @url_helper_prefix ||= (class_path + [file_name]).join('_') + def url_helper_prefix # :doc: + @url_helper_prefix ||= (class_path + [file_name]).join("_") end # Tries to retrieve the application name or simply return application. - def application_name + def application_name # :doc: if defined?(Rails) && Rails.application - Rails.application.class.name.split('::').first.underscore + Rails.application.class.name.split("::").first.underscore else "application" end end - def assign_names!(name) #:nodoc: - @class_path = name.include?('/') ? name.split('/') : name.split('::') + def redirect_resource_name # :doc: + model_resource_name(prefix: "@") + end + + def model_resource_name(prefix: "") # :doc: + resource_name = "#{prefix}#{singular_table_name}" + if options[:model_name] + "[#{controller_class_path.map { |name| ":" + name }.join(", ")}, #{resource_name}]" + else + resource_name + end + end + + def singular_route_name # :doc: + if options[:model_name] + "#{controller_class_path.join('_')}_#{singular_table_name}" + else + singular_table_name + end + end + + def plural_route_name # :doc: + if options[:model_name] + "#{controller_class_path.join('_')}_#{plural_table_name}" + else + plural_table_name + end + end + + def assign_names!(name) + @class_path = name.include?("/") ? name.split("/") : name.split("::") @class_path.map!(&:underscore) @file_name = @class_path.pop end # Convert attributes array into GeneratedAttribute objects. - def parse_attributes! #:nodoc: + def parse_attributes! self.attributes = (attributes || []).map do |attr| Rails::Generators::GeneratedAttribute.parse(attr) end end - def attributes_names + def attributes_names # :doc: @attributes_names ||= attributes.each_with_object([]) do |a, names| + next if a.attachments? names << a.column_name - names << 'password_confirmation' if a.password_digest? + names << "password_confirmation" if a.password_digest? names << "#{a.name}_type" if a.polymorphic? end end - def pluralize_table_names? + def pluralize_table_names? # :doc: !defined?(ActiveRecord::Base) || ActiveRecord::Base.pluralize_table_names end - def mountable_engine? + def mountable_engine? # :doc: defined?(ENGINE_ROOT) && namespaced? end @@ -213,9 +212,9 @@ module Rails # If the generator is invoked with class name Admin, it will check for # the presence of "AdminDecorator". # - def self.check_class_collision(options={}) + def self.check_class_collision(options = {}) # :doc: define_method :check_class_collision do - name = if self.respond_to?(:controller_class_name) # for ScaffoldBase + name = if respond_to?(:controller_class_name) # for ResourceHelpers controller_class_name else class_name diff --git a/railties/lib/rails/generators/rails/app/app_generator.rb b/railties/lib/rails/generators/rails/app/app_generator.rb index f58e6ba653..f2f46d6e25 100644 --- a/railties/lib/rails/generators/rails/app/app_generator.rb +++ b/railties/lib/rails/generators/rails/app/app_generator.rb @@ -1,4 +1,6 @@ -require 'rails/generators/app_base' +# frozen_string_literal: true + +require "rails/generators/app_base" module Rails module ActionMethods # :nodoc: @@ -19,7 +21,6 @@ module Rails RUBY end - # TODO: Remove once this is fully in place def method_missing(meth, *args, &block) @generator.send(meth, *args, &block) end @@ -32,6 +33,14 @@ module Rails # This allows you to override entire operations, like the creation of the # Gemfile, README, or JavaScript files, without needing to know exactly # what those operations do so you can create another template action. + # + # class CustomAppBuilder < Rails::AppBuilder + # def test + # @generator.gem "rspec-rails", group: [:development, :test] + # run "bundle install" + # generate "rspec:install" + # end + # end class AppBuilder def rakefile template "Rakefile" @@ -41,6 +50,10 @@ module Rails copy_file "README.md", "README.md" end + def ruby_version + template "ruby-version", ".ruby-version" + end + def gemfile template "Gemfile" end @@ -53,14 +66,23 @@ module Rails template "gitignore", ".gitignore" end + def version_control + if !options[:skip_git] && !options[:pretend] + run "git init", capture: options[:quiet] + end + end + + def package_json + template "package.json" + end + def app - directory 'app' + directory "app" - keep_file 'app/assets/images' - empty_directory_with_keep_file 'app/assets/javascripts/channels' unless options[:skip_action_cable] + keep_file "app/assets/images" - keep_file 'app/controllers/concerns' - keep_file 'app/models/concerns' + keep_file "app/controllers/concerns" + keep_file "app/models/concerns" end def bin @@ -70,6 +92,14 @@ module Rails chmod "bin", 0755 & ~File.umask, verbose: false end + def bin_when_updating + bin + + if options[:skip_javascript] + remove_file "bin/yarn" + end + end + def config empty_directory "config" @@ -77,10 +107,10 @@ module Rails template "routes.rb" template "application.rb" template "environment.rb" - template "secrets.yml" template "cable.yml" unless options[:skip_action_cable] template "puma.rb" unless options[:skip_puma] template "spring.rb" if spring_install? + template "storage.yml" unless skip_active_storage? directory "environments" directory "initializers" @@ -89,40 +119,62 @@ module Rails end def config_when_updating - cookie_serializer_config_exist = File.exist?('config/initializers/cookies_serializer.rb') - callback_terminator_config_exist = File.exist?('config/initializers/callback_terminator.rb') - active_record_belongs_to_required_by_default_config_exist = File.exist?('config/initializers/active_record_belongs_to_required_by_default.rb') - action_cable_config_exist = File.exist?('config/cable.yml') - ssl_options_exist = File.exist?('config/initializers/ssl_options.rb') - rack_cors_config_exist = File.exist?('config/initializers/cors.rb') + cookie_serializer_config_exist = File.exist?("config/initializers/cookies_serializer.rb") + action_cable_config_exist = File.exist?("config/cable.yml") + active_storage_config_exist = File.exist?("config/storage.yml") + rack_cors_config_exist = File.exist?("config/initializers/cors.rb") + assets_config_exist = File.exist?("config/initializers/assets.rb") + csp_config_exist = File.exist?("config/initializers/content_security_policy.rb") - config - - gsub_file 'config/environments/development.rb', /^(\s+)config\.file_watcher/, '\1# config.file_watcher' + @config_target_version = Rails.application.config.loaded_config_version || "5.0" - unless callback_terminator_config_exist - remove_file 'config/initializers/callback_terminator.rb' - end + config unless cookie_serializer_config_exist - gsub_file 'config/initializers/cookies_serializer.rb', /json(?!,)/, 'marshal' + gsub_file "config/initializers/cookies_serializer.rb", /json(?!,)/, "marshal" end - unless active_record_belongs_to_required_by_default_config_exist - remove_file 'config/initializers/active_record_belongs_to_required_by_default.rb' + if !options[:skip_action_cable] && !action_cable_config_exist + template "config/cable.yml" end - unless action_cable_config_exist - template 'config/cable.yml' + if !skip_active_storage? && !active_storage_config_exist + template "config/storage.yml" end - unless ssl_options_exist - remove_file 'config/initializers/ssl_options.rb' + if options[:skip_sprockets] && !assets_config_exist + remove_file "config/initializers/assets.rb" end unless rack_cors_config_exist - remove_file 'config/initializers/cors.rb' + remove_file "config/initializers/cors.rb" end + + if options[:api] + unless cookie_serializer_config_exist + remove_file "config/initializers/cookies_serializer.rb" + end + + unless csp_config_exist + remove_file "config/initializers/content_security_policy.rb" + end + end + end + + def master_key + return if options[:pretend] || options[:dummy_app] + + require "rails/generators/rails/master_key/master_key_generator" + master_key_generator = Rails::Generators::MasterKeyGenerator.new([], quiet: options[:quiet], force: options[:force]) + master_key_generator.add_master_key_file_silently + master_key_generator.ignore_master_key_file_silently + end + + def credentials + return if options[:pretend] || options[:dummy_app] + + require "rails/generators/rails/credentials/credentials_generator" + Rails::Generators::CredentialsGenerator.new([], quiet: options[:quiet]).add_credentials_file_silently end def database_yml @@ -134,29 +186,41 @@ module Rails end def lib - empty_directory 'lib' - empty_directory_with_keep_file 'lib/tasks' - empty_directory_with_keep_file 'lib/assets' + empty_directory "lib" + empty_directory_with_keep_file "lib/tasks" + empty_directory_with_keep_file "lib/assets" end def log - empty_directory_with_keep_file 'log' + empty_directory_with_keep_file "log" end def public_directory directory "public", "public", recursive: false end + def storage + empty_directory_with_keep_file "storage" + empty_directory_with_keep_file "tmp/storage" + end + def test - empty_directory_with_keep_file 'test/fixtures' - empty_directory_with_keep_file 'test/fixtures/files' - empty_directory_with_keep_file 'test/controllers' - empty_directory_with_keep_file 'test/mailers' - empty_directory_with_keep_file 'test/models' - empty_directory_with_keep_file 'test/helpers' - empty_directory_with_keep_file 'test/integration' - - template 'test/test_helper.rb' + empty_directory_with_keep_file "test/fixtures" + empty_directory_with_keep_file "test/fixtures/files" + empty_directory_with_keep_file "test/controllers" + empty_directory_with_keep_file "test/mailers" + empty_directory_with_keep_file "test/models" + empty_directory_with_keep_file "test/helpers" + empty_directory_with_keep_file "test/integration" + + template "test/channels/application_cable/connection_test.rb" + template "test/test_helper.rb" + end + + def system_test + empty_directory_with_keep_file "test/system" + + template "test/application_system_test_case.rb" end def tmp @@ -166,51 +230,54 @@ module Rails end def vendor - vendor_javascripts - vendor_stylesheets + empty_directory_with_keep_file "vendor" end - def vendor_javascripts - unless options[:skip_javascript] - empty_directory_with_keep_file 'vendor/assets/javascripts' - end - end - - def vendor_stylesheets - empty_directory_with_keep_file 'vendor/assets/stylesheets' + def config_target_version + defined?(@config_target_version) ? @config_target_version : Rails::VERSION::STRING.to_f end end module Generators # We need to store the RAILS_DEV_PATH in a constant, otherwise the path # can change in Ruby 1.8.7 when we FileUtils.cd. - RAILS_DEV_PATH = File.expand_path("../../../../../..", File.dirname(__FILE__)) - RESERVED_NAMES = %w[application destroy plugin runner test] + RAILS_DEV_PATH = File.expand_path("../../../../../..", __dir__) class AppGenerator < AppBase # :nodoc: + WEBPACKS = %w( react vue angular elm stimulus ) + add_shared_options_for "application" - # Add bin/rails options + # Add rails command options class_option :version, type: :boolean, aliases: "-v", group: :rails, desc: "Show Rails version number and quit" class_option :api, type: :boolean, desc: "Preconfigure smaller stack for API only apps" + class_option :skip_bundle, type: :boolean, aliases: "-B", default: false, + desc: "Don't run bundle install" + + class_option :webpack, type: :string, aliases: "--webpacker", default: nil, + desc: "Preconfigure Webpack with a particular framework (options: #{WEBPACKS.join(", ")})" + + class_option :skip_webpack_install, type: :boolean, default: false, + desc: "Don't run Webpack install" + def initialize(*args) super - unless app_path - raise Error, "Application name should be provided in arguments. For details run: rails --help" - end - if !options[:skip_active_record] && !DATABASES.include?(options[:database]) - raise Error, "Invalid value for --database option. Supported for preconfiguration are: #{DATABASES.join(", ")}." + raise Error, "Invalid value for --database option. Supported preconfigurations are: #{DATABASES.join(", ")}." end - # Force sprockets to be skipped when generating API only apps. + # Force sprockets and yarn to be skipped when generating API only apps. # Can't modify options hash as it's frozen by default. - self.options = options.merge(skip_sprockets: true, skip_javascript: true).freeze if options[:api] + if options[:api] + self.options = options.merge(skip_sprockets: true, skip_javascript: true).freeze + end + + @after_bundle_callbacks = [] end public_task :set_default_accessors! @@ -219,9 +286,12 @@ module Rails def create_root_files build(:readme) build(:rakefile) + build(:ruby_version) build(:configru) - build(:gitignore) unless options[:skip_git] - build(:gemfile) unless options[:skip_gemfile] + build(:gitignore) unless options[:skip_git] + build(:gemfile) unless options[:skip_gemfile] + build(:version_control) + build(:package_json) unless options[:skip_javascript] end def create_app_files @@ -232,6 +302,18 @@ module Rails build(:bin) end + def update_bin_files + build(:bin_when_updating) + end + remove_task :update_bin_files + + def update_active_storage + unless skip_active_storage? + rails_command "active_storage:update" + end + end + remove_task :update_active_storage + def create_config_files build(:config) end @@ -241,6 +323,19 @@ module Rails end remove_task :update_config_files + def create_master_key + build(:master_key) + end + + def create_credentials + build(:credentials) + end + + def display_upgrade_guide_info + say "\nAfter this, check Rails upgrade guide at https://guides.rubyonrails.org/upgrading_ruby_on_rails.html for more details about upgrading your app." + end + remove_task :display_upgrade_guide_info + def create_boot_file template "config/boot.rb" end @@ -251,6 +346,7 @@ module Rails end def create_db_files + return if options[:skip_active_record] build(:db) end @@ -266,10 +362,6 @@ module Rails build(:public_directory) end - def create_test_files - build(:test) unless options[:skip_test] - end - def create_tmp_files build(:tmp) end @@ -278,157 +370,143 @@ module Rails build(:vendor) end + def create_test_files + build(:test) unless options[:skip_test] + end + + def create_system_test_files + build(:system_test) if depends_on_system_test? + end + + def create_storage_files + build(:storage) unless skip_active_storage? + end + def delete_app_assets_if_api_option if options[:api] - remove_dir 'app/assets' - remove_dir 'lib/assets' - remove_dir 'tmp/cache/assets' - remove_dir 'vendor/assets' + remove_dir "app/assets" + remove_dir "lib/assets" + remove_dir "tmp/cache/assets" end end def delete_app_helpers_if_api_option if options[:api] - remove_dir 'app/helpers' - remove_dir 'test/helpers' + remove_dir "app/helpers" + remove_dir "test/helpers" end end - def delete_application_layout_file_if_api_option + def delete_app_views_if_api_option if options[:api] - remove_file 'app/views/layouts/application.html.erb' + if options[:skip_action_mailer] + remove_dir "app/views" + else + remove_file "app/views/layouts/application.html.erb" + end + end + end + + def delete_public_files_if_api_option + if options[:api] + remove_file "public/404.html" + remove_file "public/422.html" + remove_file "public/500.html" + remove_file "public/apple-touch-icon-precomposed.png" + remove_file "public/apple-touch-icon.png" + remove_file "public/favicon.ico" end end def delete_js_folder_skipping_javascript if options[:skip_javascript] - remove_dir 'app/assets/javascripts' + remove_dir "app/javascript" end end def delete_assets_initializer_skipping_sprockets if options[:skip_sprockets] - remove_file 'config/initializers/assets.rb' + remove_file "config/initializers/assets.rb" end end def delete_application_record_skipping_active_record if options[:skip_active_record] - remove_file 'app/models/application_record.rb' + remove_file "app/models/application_record.rb" end end def delete_action_mailer_files_skipping_action_mailer if options[:skip_action_mailer] - remove_file 'app/mailers/application_mailer.rb' - remove_file 'app/views/layouts/mailer.html.erb' - remove_file 'app/views/layouts/mailer.text.erb' - end - end - - def delete_active_record_initializers_skipping_active_record - if options[:skip_active_record] - remove_file 'config/initializers/active_record_belongs_to_required_by_default.rb' + remove_file "app/views/layouts/mailer.html.erb" + remove_file "app/views/layouts/mailer.text.erb" + remove_dir "app/mailers" + remove_dir "test/mailers" end end def delete_action_cable_files_skipping_action_cable if options[:skip_action_cable] - remove_file 'config/cable.yml' - remove_file 'app/assets/javascripts/cable.js' - remove_dir 'app/channels' + remove_dir "app/javascript/channels" + remove_dir "app/channels" + remove_dir "test/channels" end end def delete_non_api_initializers_if_api_option if options[:api] - remove_file 'config/initializers/session_store.rb' - remove_file 'config/initializers/cookies_serializer.rb' - remove_file 'config/initializers/request_forgery_protection.rb' - remove_file 'config/initializers/per_form_csrf_tokens.rb' + remove_file "config/initializers/cookies_serializer.rb" + remove_file "config/initializers/content_security_policy.rb" end end def delete_api_initializers unless options[:api] - remove_file 'config/initializers/cors.rb' + remove_file "config/initializers/cors.rb" + end + end + + def delete_new_framework_defaults + unless options[:update] + remove_file "config/initializers/new_framework_defaults_6_0.rb" end end + def delete_bin_yarn + remove_file "bin/yarn" if options[:skip_javascript] + end + def finish_template build(:leftovers) end public_task :apply_rails_template, :run_bundle - public_task :generate_spring_binstubs + public_task :generate_bundler_binstub, :generate_spring_binstubs + public_task :run_webpack def run_after_bundle_callbacks @after_bundle_callbacks.each(&:call) end - protected - def self.banner - "rails new #{self.arguments.map(&:usage).join(' ')} [options]" + "rails new #{arguments.map(&:usage).join(' ')} [options]" end + private + # Define file as an alias to create_file for backwards compatibility. def file(*args, &block) create_file(*args, &block) end - def app_name - @app_name ||= (defined_app_const_base? ? defined_app_name : File.basename(destination_root)).tr('\\', '').tr(". ", "_") - end - - def defined_app_name - defined_app_const_base.underscore - end - - def defined_app_const_base - Rails.respond_to?(:application) && defined?(Rails::Application) && - Rails.application.is_a?(Rails::Application) && Rails.application.class.name.sub(/::Application$/, "") - end - - alias :defined_app_const_base? :defined_app_const_base - - def app_const_base - @app_const_base ||= defined_app_const_base || app_name.gsub(/\W/, '_').squeeze('_').camelize - end - alias :camelized :app_const_base - - def app_const - @app_const ||= "#{app_const_base}::Application" - end - - def valid_const? - if app_const =~ /^\d/ - raise Error, "Invalid application name #{app_name}. Please give a name which does not start with numbers." - elsif RESERVED_NAMES.include?(app_name) - raise Error, "Invalid application name #{app_name}. Please give a " \ - "name which does not match one of the reserved rails " \ - "words: #{RESERVED_NAMES.join(", ")}" - elsif Object.const_defined?(app_const_base) - raise Error, "Invalid application name #{app_name}, constant #{app_const_base} is already in use. Please choose another application name." - end - end - - def app_secret - SecureRandom.hex(64) - end - - def mysql_socket - @mysql_socket ||= [ - "/tmp/mysql.sock", # default - "/var/run/mysqld/mysqld.sock", # debian/gentoo - "/var/tmp/mysql.sock", # freebsd - "/var/lib/mysql/mysql.sock", # fedora - "/opt/local/lib/mysql/mysql.sock", # fedora - "/opt/local/var/run/mysqld/mysqld.sock", # mac + darwinports + mysql - "/opt/local/var/run/mysql4/mysqld.sock", # mac + darwinports + mysql4 - "/opt/local/var/run/mysql5/mysqld.sock", # mac + darwinports + mysql5 - "/opt/lampp/var/mysql/mysql.sock" # xampp for linux - ].find { |f| File.exist?(f) } unless RbConfig::CONFIG['host_os'] =~ /mswin|mingw/ + # Registers a callback to be executed after bundle and spring binstubs + # have run. + # + # after_bundle do + # git add: '.' + # end + def after_bundle(&block) # :doc: + @after_bundle_callbacks << block end def get_builder_class @@ -456,14 +534,14 @@ module Rails end def self.default_rc_file - File.expand_path('~/.railsrc') + File.expand_path("~/.railsrc") end private def handle_version_request!(argument) - if ['--version', '-v'].include?(argument) - require 'rails/version' + if ["--version", "-v"].include?(argument) + require "rails/version" puts "Rails #{Rails::VERSION::STRING}" exit(0) end @@ -473,20 +551,20 @@ module Rails if argument == "new" yield else - ['--help'] + argv.drop(1) + ["--help"] + argv.drop(1) end end def handle_rails_rc!(argv) - if argv.find { |arg| arg == '--no-rc' } - argv.reject { |arg| arg == '--no-rc' } + if argv.find { |arg| arg == "--no-rc" } + argv.reject { |arg| arg == "--no-rc" } else railsrc(argv) { |rc_argv, rc| insert_railsrc_into_argv!(rc_argv, rc) } end end def railsrc(argv) - if (customrc = argv.index{ |x| x.include?("--rc=") }) + if (customrc = argv.index { |x| x.include?("--rc=") }) fname = File.expand_path(argv[customrc].gsub(/--rc=/, "")) yield(argv.take(customrc) + argv.drop(customrc + 1), fname) else diff --git a/railties/lib/rails/generators/rails/app/templates/Gemfile b/railties/lib/rails/generators/rails/app/templates/Gemfile.tt index 86143ca1f1..d7221453e7 100644 --- a/railties/lib/rails/generators/rails/app/templates/Gemfile +++ b/railties/lib/rails/generators/rails/app/templates/Gemfile.tt @@ -1,5 +1,11 @@ source 'https://rubygems.org' +git_source(:github) { |repo| "https://github.com/#{repo}.git" } +ruby <%= "'#{RUBY_VERSION}'" -%> + +<% unless gemfile_entries.first.comment -%> + +<% end -%> <% gemfile_entries.each do |gem| -%> <% if gem.comment -%> @@ -12,12 +18,19 @@ source 'https://rubygems.org' <% end -%> <% end -%> -# Use ActiveModel has_secure_password +# Use Active Model has_secure_password # gem 'bcrypt', '~> 3.1.7' +<% unless skip_active_storage? -%> -# Use Capistrano for deployment -# gem 'capistrano-rails', group: :development +# Use Active Storage variant +# gem 'image_processing', '~> 1.2' +<% end -%> + +<% if depend_on_bootsnap? -%> +# Reduces boot times through caching; required in config/boot.rb +gem 'bootsnap', '>= 1.4.2', require: false +<%- end -%> <%- if options.api? -%> # Use Rack CORS for handling Cross-Origin Resource Sharing (CORS), making cross-origin AJAX possible # gem 'rack-cors' @@ -26,20 +39,21 @@ source 'https://rubygems.org' <% if RUBY_ENGINE == 'ruby' -%> group :development, :test do # Call 'byebug' anywhere in the code to stop execution and get a debugger console - gem 'byebug', platform: :mri + gem 'byebug', platforms: [:mri, :mingw, :x64_mingw] end +<% end -%> group :development do <%- unless options.api? -%> - # Access an IRB console on exception pages or by using <%%= console %> anywhere in the code. + # Access an interactive console on exception pages or by calling 'console' anywhere in the code. <%- if options.dev? || options.edge? -%> gem 'web-console', github: 'rails/web-console' <%- else -%> - gem 'web-console' + gem 'web-console', '>= 3.3.0' <%- end -%> <%- end -%> <% if depend_on_listen? -%> - gem 'listen', '~> 3.0.5' + gem 'listen', '>= 3.0.5', '< 3.2' <% end -%> <% if spring_install? -%> # Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring @@ -49,7 +63,16 @@ group :development do <% end -%> <% end -%> end -<% end -%> + +<%- if depends_on_system_test? -%> +group :test do + # Adds support for Capybara system testing and selenium driver + gem 'capybara', '>= 2.15' + gem 'selenium-webdriver' + # Easy installation and use of web drivers to run system tests with browsers + gem 'webdrivers' +end +<%- end -%> # Windows does not include zoneinfo files, so bundle the tzinfo-data gem gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby] diff --git a/railties/lib/rails/generators/rails/app/templates/README.md b/railties/lib/rails/generators/rails/app/templates/README.md.tt index 7db80e4ca1..7db80e4ca1 100644 --- a/railties/lib/rails/generators/rails/app/templates/README.md +++ b/railties/lib/rails/generators/rails/app/templates/README.md.tt diff --git a/railties/lib/rails/generators/rails/app/templates/Rakefile b/railties/lib/rails/generators/rails/app/templates/Rakefile.tt index e85f913914..e85f913914 100644 --- a/railties/lib/rails/generators/rails/app/templates/Rakefile +++ b/railties/lib/rails/generators/rails/app/templates/Rakefile.tt diff --git a/railties/lib/rails/generators/rails/app/templates/app/assets/config/manifest.js.tt b/railties/lib/rails/generators/rails/app/templates/app/assets/config/manifest.js.tt index f4ee1409af..591819335f 100644 --- a/railties/lib/rails/generators/rails/app/templates/app/assets/config/manifest.js.tt +++ b/railties/lib/rails/generators/rails/app/templates/app/assets/config/manifest.js.tt @@ -1,7 +1,2 @@ -<% unless options.api? -%> //= link_tree ../images -<% end -%> -<% unless options.skip_javascript -%> -//= link_directory ../javascripts .js -<% end -%> //= link_directory ../stylesheets .css diff --git a/railties/lib/rails/generators/rails/app/templates/app/assets/javascripts/application.js.tt b/railties/lib/rails/generators/rails/app/templates/app/assets/javascripts/application.js.tt deleted file mode 100644 index c88426ec06..0000000000 --- a/railties/lib/rails/generators/rails/app/templates/app/assets/javascripts/application.js.tt +++ /dev/null @@ -1,20 +0,0 @@ -// This is a manifest file that'll be compiled into application.js, which will include all the files -// listed below. -// -// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts, -// or any plugin's vendor/assets/javascripts directory can be referenced here using a relative path. -// -// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the -// compiled file. JavaScript code in this file should be added after the last require_* statement. -// -// Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details -// about supported directives. -// -<% unless options[:skip_javascript] -%> -//= require <%= options[:javascript] %> -//= require <%= options[:javascript] %>_ujs -<% if gemfile_entries.any? { |m| m.name == "turbolinks" } -%> -//= require turbolinks -<% end -%> -<% end -%> -//= require_tree . diff --git a/railties/lib/rails/generators/rails/app/templates/app/assets/javascripts/cable.js b/railties/lib/rails/generators/rails/app/templates/app/assets/javascripts/cable.js deleted file mode 100644 index 71ee1e66de..0000000000 --- a/railties/lib/rails/generators/rails/app/templates/app/assets/javascripts/cable.js +++ /dev/null @@ -1,13 +0,0 @@ -// Action Cable provides the framework to deal with WebSockets in Rails. -// You can generate new channels where WebSocket features live using the rails generate channel command. -// -//= require action_cable -//= require_self -//= require_tree ./channels - -(function() { - this.App || (this.App = {}); - - App.cable = ActionCable.createConsumer(); - -}).call(this); diff --git a/railties/lib/rails/generators/rails/app/templates/app/assets/stylesheets/application.css b/railties/lib/rails/generators/rails/app/templates/app/assets/stylesheets/application.css.tt index 0ebd7fe829..d05ea0f511 100644 --- a/railties/lib/rails/generators/rails/app/templates/app/assets/stylesheets/application.css +++ b/railties/lib/rails/generators/rails/app/templates/app/assets/stylesheets/application.css.tt @@ -2,8 +2,8 @@ * This is a manifest file that'll be compiled into application.css, which will include all the files * listed below. * - * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets, - * or any plugin's vendor/assets/stylesheets directory can be referenced here using a relative path. + * Any CSS and SCSS file within this directory, lib/assets/stylesheets, or any plugin's + * vendor/assets/stylesheets directory can be referenced here using a relative path. * * You're free to add application-wide styles to this file and they'll appear at the bottom of the * compiled file so the styles you add here take precedence over styles defined in any other CSS/SCSS diff --git a/railties/lib/rails/generators/rails/app/templates/app/channels/application_cable/channel.rb b/railties/lib/rails/generators/rails/app/templates/app/channels/application_cable/channel.rb deleted file mode 100644 index d56fa30f4d..0000000000 --- a/railties/lib/rails/generators/rails/app/templates/app/channels/application_cable/channel.rb +++ /dev/null @@ -1,5 +0,0 @@ -# Be sure to restart your server when you modify this file. Action Cable runs in a loop that does not support auto reloading. -module ApplicationCable - class Channel < ActionCable::Channel::Base - end -end diff --git a/railties/lib/rails/generators/rails/app/templates/app/channels/application_cable/channel.rb.tt b/railties/lib/rails/generators/rails/app/templates/app/channels/application_cable/channel.rb.tt new file mode 100644 index 0000000000..d672697283 --- /dev/null +++ b/railties/lib/rails/generators/rails/app/templates/app/channels/application_cable/channel.rb.tt @@ -0,0 +1,4 @@ +module ApplicationCable + class Channel < ActionCable::Channel::Base + end +end diff --git a/railties/lib/rails/generators/rails/app/templates/app/channels/application_cable/connection.rb b/railties/lib/rails/generators/rails/app/templates/app/channels/application_cable/connection.rb deleted file mode 100644 index b4f41389ad..0000000000 --- a/railties/lib/rails/generators/rails/app/templates/app/channels/application_cable/connection.rb +++ /dev/null @@ -1,5 +0,0 @@ -# Be sure to restart your server when you modify this file. Action Cable runs in a loop that does not support auto reloading. -module ApplicationCable - class Connection < ActionCable::Connection::Base - end -end diff --git a/railties/lib/rails/generators/rails/app/templates/app/channels/application_cable/connection.rb.tt b/railties/lib/rails/generators/rails/app/templates/app/channels/application_cable/connection.rb.tt new file mode 100644 index 0000000000..0ff5442f47 --- /dev/null +++ b/railties/lib/rails/generators/rails/app/templates/app/channels/application_cable/connection.rb.tt @@ -0,0 +1,4 @@ +module ApplicationCable + class Connection < ActionCable::Connection::Base + end +end diff --git a/railties/lib/rails/generators/rails/app/templates/app/controllers/application_controller.rb.tt b/railties/lib/rails/generators/rails/app/templates/app/controllers/application_controller.rb.tt index f726fd6305..938eff8ed0 100644 --- a/railties/lib/rails/generators/rails/app/templates/app/controllers/application_controller.rb.tt +++ b/railties/lib/rails/generators/rails/app/templates/app/controllers/application_controller.rb.tt @@ -1,7 +1,2 @@ -class ApplicationController < ActionController::<%= options[:api] ? "API" : "Base" %> -<%- unless options[:api] -%> - # Prevent CSRF attacks by raising an exception. - # For APIs, you may want to use :null_session instead. - protect_from_forgery with: :exception -<%- end -%> +class ApplicationController < ActionController::<%= options.api? ? "API" : "Base" %> end diff --git a/railties/lib/rails/generators/rails/app/templates/app/helpers/application_helper.rb b/railties/lib/rails/generators/rails/app/templates/app/helpers/application_helper.rb.tt index de6be7945c..de6be7945c 100644 --- a/railties/lib/rails/generators/rails/app/templates/app/helpers/application_helper.rb +++ b/railties/lib/rails/generators/rails/app/templates/app/helpers/application_helper.rb.tt diff --git a/railties/lib/rails/generators/rails/app/templates/app/javascript/channels/consumer.js b/railties/lib/rails/generators/rails/app/templates/app/javascript/channels/consumer.js new file mode 100644 index 0000000000..0eceb59b18 --- /dev/null +++ b/railties/lib/rails/generators/rails/app/templates/app/javascript/channels/consumer.js @@ -0,0 +1,6 @@ +// Action Cable provides the framework to deal with WebSockets in Rails. +// You can generate new channels where WebSocket features live using the `rails generate channel` command. + +import { createConsumer } from "@rails/actioncable" + +export default createConsumer() diff --git a/railties/lib/rails/generators/rails/app/templates/app/javascript/channels/index.js b/railties/lib/rails/generators/rails/app/templates/app/javascript/channels/index.js new file mode 100644 index 0000000000..0cfcf74919 --- /dev/null +++ b/railties/lib/rails/generators/rails/app/templates/app/javascript/channels/index.js @@ -0,0 +1,5 @@ +// Load all the channels within this directory and all subdirectories. +// Channel files must be named *_channel.js. + +const channels = require.context('.', true, /_channel\.js$/) +channels.keys().forEach(channels) diff --git a/railties/lib/rails/generators/rails/app/templates/app/javascript/packs/application.js.tt b/railties/lib/rails/generators/rails/app/templates/app/javascript/packs/application.js.tt new file mode 100644 index 0000000000..e67e742263 --- /dev/null +++ b/railties/lib/rails/generators/rails/app/templates/app/javascript/packs/application.js.tt @@ -0,0 +1,23 @@ +// This file is automatically compiled by Webpack, along with any other files +// present in this directory. You're encouraged to place your actual application logic in +// a relevant structure within app/javascript and only use these pack files to reference +// that code so it'll be compiled. + +require("@rails/ujs").start() +<%- unless options[:skip_turbolinks] -%> +require("turbolinks").start() +<%- end -%> +<%- unless skip_active_storage? -%> +require("@rails/activestorage").start() +<%- end -%> +<%- unless options[:skip_action_cable] -%> +require("channels") +<%- end -%> + + +// Uncomment to copy all static images under ../images to the output folder and reference +// them with the image_pack_tag helper in views (e.g <%%= image_pack_tag 'rails.png' %>) +// or the `imagePath` JavaScript helper below. +// +// const images = require.context('../images', true) +// const imagePath = (name) => images(name, true) diff --git a/railties/lib/rails/generators/rails/app/templates/app/jobs/application_job.rb b/railties/lib/rails/generators/rails/app/templates/app/jobs/application_job.rb deleted file mode 100644 index a009ace51c..0000000000 --- a/railties/lib/rails/generators/rails/app/templates/app/jobs/application_job.rb +++ /dev/null @@ -1,2 +0,0 @@ -class ApplicationJob < ActiveJob::Base -end diff --git a/railties/lib/rails/generators/rails/app/templates/app/jobs/application_job.rb.tt b/railties/lib/rails/generators/rails/app/templates/app/jobs/application_job.rb.tt new file mode 100644 index 0000000000..d394c3d106 --- /dev/null +++ b/railties/lib/rails/generators/rails/app/templates/app/jobs/application_job.rb.tt @@ -0,0 +1,7 @@ +class ApplicationJob < ActiveJob::Base + # Automatically retry jobs that encountered a deadlock + # retry_on ActiveRecord::Deadlocked + + # Most jobs are safe to ignore if the underlying records are no longer available + # discard_on ActiveJob::DeserializationError +end diff --git a/railties/lib/rails/generators/rails/app/templates/app/mailers/application_mailer.rb b/railties/lib/rails/generators/rails/app/templates/app/mailers/application_mailer.rb.tt index 286b2239d1..286b2239d1 100644 --- a/railties/lib/rails/generators/rails/app/templates/app/mailers/application_mailer.rb +++ b/railties/lib/rails/generators/rails/app/templates/app/mailers/application_mailer.rb.tt diff --git a/railties/lib/rails/generators/rails/app/templates/app/models/application_record.rb b/railties/lib/rails/generators/rails/app/templates/app/models/application_record.rb.tt index 10a4cba84d..10a4cba84d 100644 --- a/railties/lib/rails/generators/rails/app/templates/app/models/application_record.rb +++ b/railties/lib/rails/generators/rails/app/templates/app/models/application_record.rb.tt diff --git a/railties/lib/rails/generators/rails/app/templates/app/views/layouts/application.html.erb.tt b/railties/lib/rails/generators/rails/app/templates/app/views/layouts/application.html.erb.tt index 72258cc96b..9a7267c783 100644 --- a/railties/lib/rails/generators/rails/app/templates/app/views/layouts/application.html.erb.tt +++ b/railties/lib/rails/generators/rails/app/templates/app/views/layouts/application.html.erb.tt @@ -3,16 +3,17 @@ <head> <title><%= camelized %></title> <%%= csrf_meta_tags %> + <%%= csp_meta_tag %> <%- if options[:skip_javascript] -%> <%%= stylesheet_link_tag 'application', media: 'all' %> <%- else -%> - <%- if gemfile_entries.any? { |m| m.name == 'turbolinks' } -%> - <%%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track' => 'reload' %> - <%%= javascript_include_tag 'application', 'data-turbolinks-track' => 'reload' %> + <%- unless options[:skip_turbolinks] -%> + <%%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %> + <%%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %> <%- else -%> - <%%= stylesheet_link_tag 'application', media: 'all' %> - <%%= javascript_include_tag 'application' %> + <%%= stylesheet_link_tag 'application', media: 'all' %> + <%%= javascript_pack_tag 'application' %> <%- end -%> <%- end -%> </head> diff --git a/railties/lib/rails/generators/rails/app/templates/bin/bundle b/railties/lib/rails/generators/rails/app/templates/bin/bundle deleted file mode 100644 index 1123dcf501..0000000000 --- a/railties/lib/rails/generators/rails/app/templates/bin/bundle +++ /dev/null @@ -1,2 +0,0 @@ -ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__) -load Gem.bin_path('bundler', 'bundle') diff --git a/railties/lib/rails/generators/rails/app/templates/bin/rails b/railties/lib/rails/generators/rails/app/templates/bin/rails.tt index 513a2e0183..513a2e0183 100644 --- a/railties/lib/rails/generators/rails/app/templates/bin/rails +++ b/railties/lib/rails/generators/rails/app/templates/bin/rails.tt diff --git a/railties/lib/rails/generators/rails/app/templates/bin/rake b/railties/lib/rails/generators/rails/app/templates/bin/rake.tt index d14fc8395b..d14fc8395b 100644 --- a/railties/lib/rails/generators/rails/app/templates/bin/rake +++ b/railties/lib/rails/generators/rails/app/templates/bin/rake.tt diff --git a/railties/lib/rails/generators/rails/app/templates/bin/setup b/railties/lib/rails/generators/rails/app/templates/bin/setup.tt index acae810c1a..3f73bae3da 100644 --- a/railties/lib/rails/generators/rails/app/templates/bin/setup +++ b/railties/lib/rails/generators/rails/app/templates/bin/setup.tt @@ -1,29 +1,34 @@ -require 'pathname' require 'fileutils' -include FileUtils # path to your application root. -APP_ROOT = Pathname.new File.expand_path('../../', __FILE__) +APP_ROOT = File.expand_path('..', __dir__) def system!(*args) system(*args) || abort("\n== Command #{args} failed ==") end -chdir APP_ROOT do +FileUtils.chdir APP_ROOT do # This script is a starting point to setup your application. # Add necessary setup steps to this file. puts '== Installing dependencies ==' system! 'gem install bundler --conservative' system('bundle check') || system!('bundle install') +<% unless options.skip_javascript? -%> + + # Install JavaScript dependencies + # system('bin/yarn') +<% end -%> +<% unless options.skip_active_record? -%> # puts "\n== Copying sample files ==" # unless File.exist?('config/database.yml') - # cp 'config/database.yml.sample', 'config/database.yml' + # FileUtils.cp 'config/database.yml.sample', 'config/database.yml' # end puts "\n== Preparing database ==" system! 'bin/rails db:setup' +<% end -%> puts "\n== Removing old logs and tempfiles ==" system! 'bin/rails log:clear tmp:clear' diff --git a/railties/lib/rails/generators/rails/app/templates/bin/update b/railties/lib/rails/generators/rails/app/templates/bin/update.tt index 770a605fed..03b77d0d46 100644 --- a/railties/lib/rails/generators/rails/app/templates/bin/update +++ b/railties/lib/rails/generators/rails/app/templates/bin/update.tt @@ -1,28 +1,33 @@ -require 'pathname' require 'fileutils' -include FileUtils # path to your application root. -APP_ROOT = Pathname.new File.expand_path('../../', __FILE__) +APP_ROOT = File.expand_path('..', __dir__) def system!(*args) system(*args) || abort("\n== Command #{args} failed ==") end -chdir APP_ROOT do +FileUtils.chdir APP_ROOT do # This script is a way to update your development environment automatically. # Add necessary update steps to this file. puts '== Installing dependencies ==' system! 'gem install bundler --conservative' system('bundle check') || system!('bundle install') +<% unless options.skip_javascript? -%> + + # Install JavaScript dependencies + # system('bin/yarn') +<% end -%> +<% unless options.skip_active_record? -%> puts "\n== Updating database ==" - system! 'bin/rails db:migrate' + system! 'rails db:migrate' +<% end -%> puts "\n== Removing old logs and tempfiles ==" - system! 'bin/rails log:clear tmp:clear' + system! 'rails log:clear tmp:clear' puts "\n== Restarting application server ==" - system! 'bin/rails restart' + system! 'rails restart' end diff --git a/railties/lib/rails/generators/rails/app/templates/bin/yarn.tt b/railties/lib/rails/generators/rails/app/templates/bin/yarn.tt new file mode 100644 index 0000000000..90ddcc520e --- /dev/null +++ b/railties/lib/rails/generators/rails/app/templates/bin/yarn.tt @@ -0,0 +1,10 @@ +APP_ROOT = File.expand_path('..', __dir__) +Dir.chdir(APP_ROOT) do + begin + exec "yarnpkg", *ARGV + rescue Errno::ENOENT + $stderr.puts "Yarn executable was not detected in the system." + $stderr.puts "Download Yarn at https://yarnpkg.com/en/docs/install" + exit 1 + end +end diff --git a/railties/lib/rails/generators/rails/app/templates/config.ru b/railties/lib/rails/generators/rails/app/templates/config.ru.tt index f7ba0b527b..f7ba0b527b 100644 --- a/railties/lib/rails/generators/rails/app/templates/config.ru +++ b/railties/lib/rails/generators/rails/app/templates/config.ru.tt diff --git a/railties/lib/rails/generators/rails/app/templates/config/application.rb b/railties/lib/rails/generators/rails/app/templates/config/application.rb.tt index c0a0bd0a3e..1b0ee54071 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/application.rb +++ b/railties/lib/rails/generators/rails/app/templates/config/application.rb.tt @@ -8,8 +8,11 @@ require "rails" require "active_model/railtie" require "active_job/railtie" <%= comment_if :skip_active_record %>require "active_record/railtie" +<%= comment_if :skip_active_storage %>require "active_storage/engine" require "action_controller/railtie" <%= comment_if :skip_action_mailer %>require "action_mailer/railtie" +<%= comment_if :skip_action_mailbox %>require "action_mailbox/engine" +<%= comment_if :skip_action_text %>require "action_text/engine" require "action_view/railtie" <%= comment_if :skip_action_cable %>require "action_cable/engine" <%= comment_if :skip_sprockets %>require "sprockets/railtie" @@ -22,15 +25,23 @@ Bundler.require(*Rails.groups) module <%= app_const_base %> class Application < Rails::Application + # Initialize configuration defaults for originally generated Rails version. + config.load_defaults <%= build(:config_target_version) %> + # Settings in config/environments/* take precedence over those specified here. - # Application configuration should go into files in config/initializers - # -- all .rb files in that directory are automatically loaded. -<%- if options[:api] -%> + # Application configuration can go into files in config/initializers + # -- all .rb files in that directory are automatically loaded after loading + # the framework and any gems in your application. +<%- if options.api? -%> # Only loads a smaller set of middleware suitable for API only apps. # Middleware like session, flash, cookies can be added back manually. # Skip views, helpers and assets when generating a new resource. config.api_only = true +<%- elsif !depends_on_system_test? -%> + + # Don't generate system test files. + config.generators.system_tests = nil <%- end -%> end end diff --git a/railties/lib/rails/generators/rails/app/templates/config/boot.rb b/railties/lib/rails/generators/rails/app/templates/config/boot.rb.tt index 30f5120df6..42d46b8175 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/boot.rb +++ b/railties/lib/rails/generators/rails/app/templates/config/boot.rb.tt @@ -1,3 +1,6 @@ ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__) require 'bundler/setup' # Set up gems listed in the Gemfile. +<% if depend_on_bootsnap? -%> +require 'bootsnap/setup' # Speed up boot time by caching expensive operations. +<%- end -%> diff --git a/railties/lib/rails/generators/rails/app/templates/config/cable.yml b/railties/lib/rails/generators/rails/app/templates/config/cable.yml deleted file mode 100644 index aa4e832748..0000000000 --- a/railties/lib/rails/generators/rails/app/templates/config/cable.yml +++ /dev/null @@ -1,10 +0,0 @@ -# Action Cable uses Redis by default to administer connections, channels, and sending/receiving messages over the WebSocket. -production: - adapter: redis - url: redis://localhost:6379/1 - -development: - adapter: async - -test: - adapter: async diff --git a/railties/lib/rails/generators/rails/app/templates/config/cable.yml.tt b/railties/lib/rails/generators/rails/app/templates/config/cable.yml.tt new file mode 100644 index 0000000000..f69dc91b92 --- /dev/null +++ b/railties/lib/rails/generators/rails/app/templates/config/cable.yml.tt @@ -0,0 +1,10 @@ +development: + adapter: async + +test: + adapter: test + +production: + adapter: redis + url: <%%= ENV.fetch("REDIS_URL") { "redis://localhost:6379/1" } %> + channel_prefix: <%= app_name %>_production diff --git a/railties/lib/rails/generators/rails/app/templates/config/databases/frontbase.yml b/railties/lib/rails/generators/rails/app/templates/config/databases/frontbase.yml.tt index 34fc0e3465..6ab4a26084 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/databases/frontbase.yml +++ b/railties/lib/rails/generators/rails/app/templates/config/databases/frontbase.yml.tt @@ -8,6 +8,7 @@ # default: &default adapter: frontbase + pool: <%%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> host: localhost username: <%= app_name %> password: '' @@ -23,12 +24,12 @@ test: <<: *default database: <%= app_name %>_test -# As with config/secrets.yml, you never want to store sensitive information, +# As with config/credentials.yml, you never want to store sensitive information, # like your database password, in your source code. If your source code is # ever seen by anyone, they now have access to your database. # # Instead, provide the password as a unix environment variable when you boot -# the app. Read http://guides.rubyonrails.org/configuring.html#configuring-a-database +# the app. Read https://guides.rubyonrails.org/configuring.html#configuring-a-database # for a full rundown on how to provide these environment variables in a # production deployment. # diff --git a/railties/lib/rails/generators/rails/app/templates/config/databases/ibm_db.yml b/railties/lib/rails/generators/rails/app/templates/config/databases/ibm_db.yml.tt index 187ff01bac..e422aa31fc 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/databases/ibm_db.yml +++ b/railties/lib/rails/generators/rails/app/templates/config/databases/ibm_db.yml.tt @@ -34,6 +34,7 @@ # default: &default adapter: ibm_db + pool: <%%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> username: db2inst1 password: #schema: db2inst1 @@ -59,12 +60,12 @@ test: <<: *default database: <%= app_name[0,4] %>_tst -# As with config/secrets.yml, you never want to store sensitive information, +# As with config/credentials.yml, you never want to store sensitive information, # like your database password, in your source code. If your source code is # ever seen by anyone, they now have access to your database. # # Instead, provide the password as a unix environment variable when you boot -# the app. Read http://guides.rubyonrails.org/configuring.html#configuring-a-database +# the app. Read https://guides.rubyonrails.org/configuring.html#configuring-a-database # for a full rundown on how to provide these environment variables in a # production deployment. # diff --git a/railties/lib/rails/generators/rails/app/templates/config/databases/jdbc.yml b/railties/lib/rails/generators/rails/app/templates/config/databases/jdbc.yml.tt index db0a429753..678455c622 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/databases/jdbc.yml +++ b/railties/lib/rails/generators/rails/app/templates/config/databases/jdbc.yml.tt @@ -38,6 +38,7 @@ default: &default adapter: jdbc + pool: <%%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> username: <%= app_name %> password: driver: @@ -53,12 +54,12 @@ test: <<: *default url: jdbc:db://localhost/<%= app_name %>_test -# As with config/secrets.yml, you never want to store sensitive information, +# As with config/credentials.yml, you never want to store sensitive information, # like your database password, in your source code. If your source code is # ever seen by anyone, they now have access to your database. # # Instead, provide the password as a unix environment variable when you boot -# the app. Read http://guides.rubyonrails.org/configuring.html#configuring-a-database +# the app. Read https://guides.rubyonrails.org/configuring.html#configuring-a-database # for a full rundown on how to provide these environment variables in a # production deployment. # diff --git a/railties/lib/rails/generators/rails/app/templates/config/databases/jdbcmysql.yml b/railties/lib/rails/generators/rails/app/templates/config/databases/jdbcmysql.yml.tt index f2c4922e7d..b5a0efef47 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/databases/jdbcmysql.yml +++ b/railties/lib/rails/generators/rails/app/templates/config/databases/jdbcmysql.yml.tt @@ -1,4 +1,4 @@ -# MySQL. Versions 5.0 and up are supported. +# MySQL. Versions 5.5.8 and up are supported. # # Install the MySQL driver: # gem install activerecord-jdbcmysql-adapter @@ -7,10 +7,11 @@ # gem 'activerecord-jdbcmysql-adapter' # # And be sure to use new-style password hashing: -# http://dev.mysql.com/doc/refman/5.7/en/old-client.html +# https://dev.mysql.com/doc/refman/5.7/en/password-hashing.html # default: &default adapter: mysql + pool: <%%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> username: root password: host: localhost @@ -26,12 +27,12 @@ test: <<: *default database: <%= app_name %>_test -# As with config/secrets.yml, you never want to store sensitive information, +# As with config/credentials.yml, you never want to store sensitive information, # like your database password, in your source code. If your source code is # ever seen by anyone, they now have access to your database. # # Instead, provide the password as a unix environment variable when you boot -# the app. Read http://guides.rubyonrails.org/configuring.html#configuring-a-database +# the app. Read https://guides.rubyonrails.org/configuring.html#configuring-a-database # for a full rundown on how to provide these environment variables in a # production deployment. # diff --git a/railties/lib/rails/generators/rails/app/templates/config/databases/jdbcpostgresql.yml b/railties/lib/rails/generators/rails/app/templates/config/databases/jdbcpostgresql.yml.tt index 80ceb9df92..009a81a6b8 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/databases/jdbcpostgresql.yml +++ b/railties/lib/rails/generators/rails/app/templates/config/databases/jdbcpostgresql.yml.tt @@ -1,4 +1,4 @@ -# PostgreSQL. Versions 9.1 and up are supported. +# PostgreSQL. Versions 9.3 and up are supported. # # Configure Using Gemfile # gem 'activerecord-jdbcpostgresql-adapter' @@ -6,6 +6,7 @@ default: &default adapter: postgresql encoding: unicode + pool: <%%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> development: <<: *default @@ -42,12 +43,12 @@ test: <<: *default database: <%= app_name %>_test -# As with config/secrets.yml, you never want to store sensitive information, +# As with config/credentials.yml, you never want to store sensitive information, # like your database password, in your source code. If your source code is # ever seen by anyone, they now have access to your database. # # Instead, provide the password as a unix environment variable when you boot -# the app. Read http://guides.rubyonrails.org/configuring.html#configuring-a-database +# the app. Read https://guides.rubyonrails.org/configuring.html#configuring-a-database # for a full rundown on how to provide these environment variables in a # production deployment. # diff --git a/railties/lib/rails/generators/rails/app/templates/config/databases/jdbcsqlite3.yml b/railties/lib/rails/generators/rails/app/templates/config/databases/jdbcsqlite3.yml.tt index 28c36eb82f..371415e6a8 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/databases/jdbcsqlite3.yml +++ b/railties/lib/rails/generators/rails/app/templates/config/databases/jdbcsqlite3.yml.tt @@ -6,6 +6,7 @@ # default: &default adapter: sqlite3 + pool: <%%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> development: <<: *default diff --git a/railties/lib/rails/generators/rails/app/templates/config/databases/mysql.yml b/railties/lib/rails/generators/rails/app/templates/config/databases/mysql.yml.tt index 193423e84a..386eb511e5 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/databases/mysql.yml +++ b/railties/lib/rails/generators/rails/app/templates/config/databases/mysql.yml.tt @@ -1,4 +1,4 @@ -# MySQL. Versions 5.0 and up are supported. +# MySQL. Versions 5.5.8 and up are supported. # # Install the MySQL driver # gem install mysql2 @@ -7,12 +7,12 @@ # gem 'mysql2' # # And be sure to use new-style password hashing: -# http://dev.mysql.com/doc/refman/5.7/en/old-client.html +# https://dev.mysql.com/doc/refman/5.7/en/password-hashing.html # default: &default adapter: mysql2 - encoding: utf8 - pool: 5 + encoding: utf8mb4 + pool: <%%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> username: root password: <% if mysql_socket -%> @@ -32,12 +32,12 @@ test: <<: *default database: <%= app_name %>_test -# As with config/secrets.yml, you never want to store sensitive information, +# As with config/credentials.yml, you never want to store sensitive information, # like your database password, in your source code. If your source code is # ever seen by anyone, they now have access to your database. # # Instead, provide the password as a unix environment variable when you boot -# the app. Read http://guides.rubyonrails.org/configuring.html#configuring-a-database +# the app. Read https://guides.rubyonrails.org/configuring.html#configuring-a-database # for a full rundown on how to provide these environment variables in a # production deployment. # diff --git a/railties/lib/rails/generators/rails/app/templates/config/databases/oracle.yml b/railties/lib/rails/generators/rails/app/templates/config/databases/oracle.yml.tt index 9aedcc15cb..f7b6dfafab 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/databases/oracle.yml +++ b/railties/lib/rails/generators/rails/app/templates/config/databases/oracle.yml.tt @@ -1,4 +1,4 @@ -# Oracle/OCI 8i, 9, 10g +# Oracle/OCI 11g or higher recommended # # Requires Ruby/OCI8: # https://github.com/kubo/ruby-oci8 @@ -17,7 +17,8 @@ # cursor_sharing: similar # default: &default - adapter: oracle + adapter: oracle_enhanced + pool: <%%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> username: <%= app_name %> password: @@ -32,19 +33,21 @@ test: <<: *default database: <%= app_name %>_test -# As with config/secrets.yml, you never want to store sensitive information, +# As with config/credentials.yml, you never want to store sensitive information, # like your database password, in your source code. If your source code is # ever seen by anyone, they now have access to your database. # # Instead, provide the password as a unix environment variable when you boot -# the app. Read http://guides.rubyonrails.org/configuring.html#configuring-a-database +# the app. Read https://guides.rubyonrails.org/configuring.html#configuring-a-database # for a full rundown on how to provide these environment variables in a # production deployment. # # On Heroku and other platform providers, you may have a full connection URL # available as an environment variable. For example: # -# DATABASE_URL="oracle://myuser:mypass@localhost/somedatabase" +# DATABASE_URL="oracle-enhanced://myuser:mypass@localhost/somedatabase" +# +# Note that the adapter name uses a dash instead of an underscore. # # You can use this database configuration with: # diff --git a/railties/lib/rails/generators/rails/app/templates/config/databases/postgresql.yml b/railties/lib/rails/generators/rails/app/templates/config/databases/postgresql.yml.tt index bd5c0b10f6..44dafbd0c0 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/databases/postgresql.yml +++ b/railties/lib/rails/generators/rails/app/templates/config/databases/postgresql.yml.tt @@ -1,10 +1,10 @@ -# PostgreSQL. Versions 9.1 and up are supported. +# PostgreSQL. Versions 9.3 and up are supported. # # Install the pg driver: # gem install pg -# On OS X with Homebrew: +# On macOS with Homebrew: # gem install pg -- --with-pg-config=/usr/local/bin/pg_config -# On OS X with MacPorts: +# On macOS with MacPorts: # gem install pg -- --with-pg-config=/opt/local/lib/postgresql84/bin/pg_config # On Windows: # gem install pg @@ -17,8 +17,8 @@ default: &default adapter: postgresql encoding: unicode - # For details on connection pooling, see rails configuration guide - # http://guides.rubyonrails.org/configuring.html#database-pooling + # For details on connection pooling, see Rails configuration guide + # https://guides.rubyonrails.org/configuring.html#database-pooling pool: <%%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> development: @@ -59,12 +59,12 @@ test: <<: *default database: <%= app_name %>_test -# As with config/secrets.yml, you never want to store sensitive information, +# As with config/credentials.yml, you never want to store sensitive information, # like your database password, in your source code. If your source code is # ever seen by anyone, they now have access to your database. # # Instead, provide the password as a unix environment variable when you boot -# the app. Read http://guides.rubyonrails.org/configuring.html#configuring-a-database +# the app. Read https://guides.rubyonrails.org/configuring.html#configuring-a-database # for a full rundown on how to provide these environment variables in a # production deployment. # diff --git a/railties/lib/rails/generators/rails/app/templates/config/databases/sqlite3.yml b/railties/lib/rails/generators/rails/app/templates/config/databases/sqlite3.yml.tt index 1c1a37ca8d..9510568124 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/databases/sqlite3.yml +++ b/railties/lib/rails/generators/rails/app/templates/config/databases/sqlite3.yml.tt @@ -6,7 +6,7 @@ # default: &default adapter: sqlite3 - pool: 5 + pool: <%%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> timeout: 5000 development: diff --git a/railties/lib/rails/generators/rails/app/templates/config/databases/sqlserver.yml b/railties/lib/rails/generators/rails/app/templates/config/databases/sqlserver.yml.tt index 30b0df34a8..27e8f2f35d 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/databases/sqlserver.yml +++ b/railties/lib/rails/generators/rails/app/templates/config/databases/sqlserver.yml.tt @@ -1,4 +1,4 @@ -# SQL Server (2005 or higher recommended) +# SQL Server (2012 or higher required) # # Install the adapters and driver # gem install tiny_tds @@ -8,28 +8,12 @@ # gem 'tiny_tds' # gem 'activerecord-sqlserver-adapter' # -# You should make sure freetds is configured correctly first. -# freetds.conf contains host/port/protocol_versions settings. -# http://freetds.schemamania.org/userguide/freetdsconf.htm -# -# A typical Microsoft server -# [mssql] -# host = mssqlserver.yourdomain.com -# port = 1433 -# tds version = 7.1 - -# If you can connect with "tsql -S servername", your basic FreeTDS installation is working. -# 'man tsql' for more info -# Set timeout to a larger number if valid queries against a live db fail -# default: &default adapter: sqlserver encoding: utf8 - reconnect: false - username: <%= app_name %> - password: - timeout: 25 - dataserver: from_freetds.conf + username: sa + password: <%%= ENV['SA_PASSWORD'] %> + host: localhost development: <<: *default @@ -42,12 +26,12 @@ test: <<: *default database: <%= app_name %>_test -# As with config/secrets.yml, you never want to store sensitive information, +# As with config/credentials.yml, you never want to store sensitive information, # like your database password, in your source code. If your source code is # ever seen by anyone, they now have access to your database. # # Instead, provide the password as a unix environment variable when you boot -# the app. Read http://guides.rubyonrails.org/configuring.html#configuring-a-database +# the app. Read https://guides.rubyonrails.org/configuring.html#configuring-a-database # for a full rundown on how to provide these environment variables in a # production deployment. # diff --git a/railties/lib/rails/generators/rails/app/templates/config/environment.rb b/railties/lib/rails/generators/rails/app/templates/config/environment.rb.tt index 426333bb46..426333bb46 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/environment.rb +++ b/railties/lib/rails/generators/rails/app/templates/config/environment.rb.tt diff --git a/railties/lib/rails/generators/rails/app/templates/config/environments/development.rb.tt b/railties/lib/rails/generators/rails/app/templates/config/environments/development.rb.tt index 7a537610e9..2887bc2d67 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/environments/development.rb.tt +++ b/railties/lib/rails/generators/rails/app/templates/config/environments/development.rb.tt @@ -13,18 +13,25 @@ Rails.application.configure do config.consider_all_requests_local = true # Enable/disable caching. By default caching is disabled. - if Rails.root.join('tmp/caching-dev.txt').exist? + # Run rails dev:cache to toggle caching. + if Rails.root.join('tmp', 'caching-dev.txt').exist? config.action_controller.perform_caching = true + config.action_controller.enable_fragment_cache_logging = true config.cache_store = :memory_store config.public_file_server.headers = { - 'Cache-Control' => 'public, max-age=172800' + 'Cache-Control' => "public, max-age=#{2.days.to_i}" } else config.action_controller.perform_caching = false config.cache_store = :null_store end + <%- unless skip_active_storage? -%> + + # Store uploaded files on the local file system (see config/storage.yml for options). + config.active_storage.service = :local + <%- end -%> <%- unless options.skip_action_mailer? -%> # Don't care if the mailer can't send. @@ -40,15 +47,21 @@ Rails.application.configure do # Raise an error on page load if there are pending migrations. config.active_record.migration_error = :page_load + # Highlight code that triggered database queries in logs. + config.active_record.verbose_query_logs = true + <%- end -%> <%- unless options.skip_sprockets? -%> # Debug mode disables concatenation and preprocessing of assets. # This option may cause significant delays in view rendering with a large # number of complex assets. config.assets.debug = true + + # Suppress logger output for asset requests. + config.assets.quiet = true <%- end -%> - # Raises error for missing translations + # Raises error for missing translations. # config.action_view.raise_on_missing_translations = true # Use an evented file watcher to asynchronously detect changes in source code, diff --git a/railties/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt b/railties/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt index 6bd5e42251..ed1cf09eeb 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt +++ b/railties/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt @@ -14,21 +14,22 @@ Rails.application.configure do config.consider_all_requests_local = false config.action_controller.perform_caching = true + # Ensures that a master key has been made available in either ENV["RAILS_MASTER_KEY"] + # or in config/master.key. This key is used to decrypt credentials (and other encrypted files). + # config.require_master_key = true + # Disable serving static files from the `/public` folder by default since # Apache or NGINX already handles this. config.public_file_server.enabled = ENV['RAILS_SERVE_STATIC_FILES'].present? <%- unless options.skip_sprockets? -%> - # Compress JavaScripts and CSS. - config.assets.js_compressor = :uglifier + # Compress CSS using a preprocessor. # config.assets.css_compressor = :sass # Do not fallback to assets pipeline if a precompiled asset is missed. config.assets.compile = false - # `config.assets.precompile` and `config.assets.version` have moved to config/initializers/assets.rb <%- end -%> - # Enable serving of images, stylesheets, and JavaScripts from an asset server. # config.action_controller.asset_host = 'http://assets.example.com' @@ -36,15 +37,18 @@ Rails.application.configure do # config.action_dispatch.x_sendfile_header = 'X-Sendfile' # for Apache # config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for NGINX + <%- unless skip_active_storage? -%> + # Store uploaded files on the local file system (see config/storage.yml for options). + config.active_storage.service = :local + + <%- end -%> <%- unless options[:skip_action_cable] -%> - # Action Cable endpoint configuration + # Mount Action Cable outside main process or domain. + # config.action_cable.mount_path = nil # config.action_cable.url = 'wss://example.com/cable' # config.action_cable.allowed_request_origins = [ 'http://example.com', /http:\/\/example.*/ ] - # Don't mount Action Cable in the main server process. - # config.action_cable.mount_path = nil <%- end -%> - # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. # config.force_ssl = true @@ -58,17 +62,18 @@ Rails.application.configure do # Use a different cache store in production. # config.cache_store = :mem_cache_store - # Use a real queuing backend for Active Job (and separate queues per environment) + # Use a real queuing backend for Active Job (and separate queues per environment). # config.active_job.queue_adapter = :resque - # config.active_job.queue_name_prefix = "<%= app_name %>_#{Rails.env}" + # config.active_job.queue_name_prefix = "<%= app_name %>_production" + <%- unless options.skip_action_mailer? -%> config.action_mailer.perform_caching = false # Ignore bad email addresses and do not raise email delivery errors. # Set this to true and configure the email server for immediate delivery to raise delivery errors. # config.action_mailer.raise_delivery_errors = false - <%- end -%> + <%- end -%> # Enable locale fallbacks for I18n (makes lookups for any locale fall back to # the I18n.default_locale when a translation cannot be found). config.i18n.fallbacks = true @@ -86,11 +91,32 @@ Rails.application.configure do if ENV["RAILS_LOG_TO_STDOUT"].present? logger = ActiveSupport::Logger.new(STDOUT) logger.formatter = config.log_formatter - config.logger = ActiveSupport::TaggedLogging.new(logger) + config.logger = ActiveSupport::TaggedLogging.new(logger) end <%- unless options.skip_active_record? -%> # Do not dump schema after migrations. config.active_record.dump_schema_after_migration = false <%- end -%> + + # Inserts middleware to perform automatic connection switching. + # The `database_selector` hash is used to pass options to the DatabaseSelector + # middleware. The `delay` is used to determine how long to wait after a write + # to send a subsequent read to the primary. + # + # The `database_resolver` class is used by the middleware to determine which + # database is appropriate to use based on the time delay. + # + # The `database_resolver_context` class is used by the middleware to set + # timestamps for the last write to the primary. The resolver uses the context + # class timestamps to determine how long to wait before reading from the + # replica. + # + # By default Rails will store a last write timestamp in the session. The + # DatabaseSelector middleware is designed as such you can define your own + # strategy for connection switching and pass that into the middleware through + # these configuration options. + # config.active_record.database_selector = { delay: 2.seconds } + # config.active_record.database_resolver = ActiveRecord::Middleware::DatabaseSelector::Resolver + # config.active_record.database_resolver_context = ActiveRecord::Middleware::DatabaseSelector::Resolver::Session end diff --git a/railties/lib/rails/generators/rails/app/templates/config/environments/test.rb.tt b/railties/lib/rails/generators/rails/app/templates/config/environments/test.rb.tt index 42fee3b036..63ed3fa952 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/environments/test.rb.tt +++ b/railties/lib/rails/generators/rails/app/templates/config/environments/test.rb.tt @@ -15,18 +15,25 @@ Rails.application.configure do # Configure public file server for tests with Cache-Control for performance. config.public_file_server.enabled = true config.public_file_server.headers = { - 'Cache-Control' => 'public, max-age=3600' + 'Cache-Control' => "public, max-age=#{1.hour.to_i}" } # Show full error reports and disable caching. config.consider_all_requests_local = true config.action_controller.perform_caching = false + config.cache_store = :null_store # Raise exceptions instead of rendering exception templates. config.action_dispatch.show_exceptions = false # Disable request forgery protection in test environment. config.action_controller.allow_forgery_protection = false + + <%- unless skip_active_storage? -%> + # Store uploaded files on the local file system in a temporary directory. + config.active_storage.service = :test + + <%- end -%> <%- unless options.skip_action_mailer? -%> config.action_mailer.perform_caching = false @@ -34,11 +41,11 @@ Rails.application.configure do # The :test delivery method accumulates sent emails in the # ActionMailer::Base.deliveries array. config.action_mailer.delivery_method = :test - <%- end -%> + <%- end -%> # Print deprecation notices to the stderr. config.active_support.deprecation = :stderr - # Raises error for missing translations + # Raises error for missing translations. # config.action_view.raise_on_missing_translations = true end diff --git a/railties/lib/rails/generators/rails/app/templates/config/initializers/active_record_belongs_to_required_by_default.rb b/railties/lib/rails/generators/rails/app/templates/config/initializers/active_record_belongs_to_required_by_default.rb deleted file mode 100644 index f613b40f80..0000000000 --- a/railties/lib/rails/generators/rails/app/templates/config/initializers/active_record_belongs_to_required_by_default.rb +++ /dev/null @@ -1,6 +0,0 @@ -# Be sure to restart your server when you modify this file. - -# Require `belongs_to` associations by default. This is a new Rails 5.0 -# default, so it is introduced as a configuration option to ensure that apps -# made on earlier versions of Rails are not affected when upgrading. -Rails.application.config.active_record.belongs_to_required_by_default = true diff --git a/railties/lib/rails/generators/rails/app/templates/config/initializers/application_controller_renderer.rb b/railties/lib/rails/generators/rails/app/templates/config/initializers/application_controller_renderer.rb deleted file mode 100644 index 51639b67a0..0000000000 --- a/railties/lib/rails/generators/rails/app/templates/config/initializers/application_controller_renderer.rb +++ /dev/null @@ -1,6 +0,0 @@ -# Be sure to restart your server when you modify this file. - -# ApplicationController.renderer.defaults.merge!( -# http_host: 'example.org', -# https: false -# ) diff --git a/railties/lib/rails/generators/rails/app/templates/config/initializers/application_controller_renderer.rb.tt b/railties/lib/rails/generators/rails/app/templates/config/initializers/application_controller_renderer.rb.tt new file mode 100644 index 0000000000..89d2efab2b --- /dev/null +++ b/railties/lib/rails/generators/rails/app/templates/config/initializers/application_controller_renderer.rb.tt @@ -0,0 +1,8 @@ +# Be sure to restart your server when you modify this file. + +# ActiveSupport::Reloader.to_prepare do +# ApplicationController.renderer.defaults.merge!( +# http_host: 'example.org', +# https: false +# ) +# end diff --git a/railties/lib/rails/generators/rails/app/templates/config/initializers/assets.rb.tt b/railties/lib/rails/generators/rails/app/templates/config/initializers/assets.rb.tt index 01ef3e6630..e92382f2d9 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/initializers/assets.rb.tt +++ b/railties/lib/rails/generators/rails/app/templates/config/initializers/assets.rb.tt @@ -3,9 +3,14 @@ # Version of your assets, change this if you want to expire all your assets. Rails.application.config.assets.version = '1.0' -# Add additional assets to the asset load path +# Add additional assets to the asset load path. # Rails.application.config.assets.paths << Emoji.images_path +<%- unless options[:skip_javascript] -%> +# Add Yarn node_modules folder to the asset load path. +Rails.application.config.assets.paths << Rails.root.join('node_modules') +<%- end -%> # Precompile additional assets. -# application.js, application.css, and all non-JS/CSS in app/assets folder are already added. -# Rails.application.config.assets.precompile += %w( search.js ) +# application.js, application.css, and all non-JS/CSS in the app/assets +# folder are already added. +# Rails.application.config.assets.precompile += %w( admin.js admin.css ) diff --git a/railties/lib/rails/generators/rails/app/templates/config/initializers/backtrace_silencers.rb b/railties/lib/rails/generators/rails/app/templates/config/initializers/backtrace_silencers.rb.tt index 59385cdf37..59385cdf37 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/initializers/backtrace_silencers.rb +++ b/railties/lib/rails/generators/rails/app/templates/config/initializers/backtrace_silencers.rb.tt diff --git a/railties/lib/rails/generators/rails/app/templates/config/initializers/callback_terminator.rb b/railties/lib/rails/generators/rails/app/templates/config/initializers/callback_terminator.rb deleted file mode 100644 index 649e82280e..0000000000 --- a/railties/lib/rails/generators/rails/app/templates/config/initializers/callback_terminator.rb +++ /dev/null @@ -1,6 +0,0 @@ -# Be sure to restart your server when you modify this file. - -# Do not halt callback chains when a callback returns false. This is a new -# Rails 5.0 default, so it is introduced as a configuration option to ensure -# that apps made with earlier versions of Rails are not affected when upgrading. -ActiveSupport.halt_callback_chains_on_return_false = false diff --git a/railties/lib/rails/generators/rails/app/templates/config/initializers/content_security_policy.rb.tt b/railties/lib/rails/generators/rails/app/templates/config/initializers/content_security_policy.rb.tt new file mode 100644 index 0000000000..c517b0f96b --- /dev/null +++ b/railties/lib/rails/generators/rails/app/templates/config/initializers/content_security_policy.rb.tt @@ -0,0 +1,29 @@ +# Be sure to restart your server when you modify this file. + +# Define an application-wide content security policy +# For further information see the following documentation +# https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy + +# Rails.application.config.content_security_policy do |policy| +# policy.default_src :self, :https +# policy.font_src :self, :https, :data +# policy.img_src :self, :https, :data +# policy.object_src :none +# policy.script_src :self, :https +# policy.style_src :self, :https +<%- unless options[:skip_javascript] -%> +# # If you are using webpack-dev-server then specify webpack-dev-server host +# policy.connect_src :self, :https, "http://localhost:3035", "ws://localhost:3035" if Rails.env.development? +<%- end -%> + +# # Specify URI for violation reports +# # policy.report_uri "/csp-violation-report-endpoint" +# end + +# If you are using UJS then enable automatic nonce generation +# Rails.application.config.content_security_policy_nonce_generator = -> request { SecureRandom.base64(16) } + +# Report CSP violations to a specified URI +# For further information see the following documentation: +# https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy-Report-Only +# Rails.application.config.content_security_policy_report_only = true diff --git a/railties/lib/rails/generators/rails/app/templates/config/initializers/cookies_serializer.rb b/railties/lib/rails/generators/rails/app/templates/config/initializers/cookies_serializer.rb.tt index 5a6a32d371..5a6a32d371 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/initializers/cookies_serializer.rb +++ b/railties/lib/rails/generators/rails/app/templates/config/initializers/cookies_serializer.rb.tt diff --git a/railties/lib/rails/generators/rails/app/templates/config/initializers/cors.rb b/railties/lib/rails/generators/rails/app/templates/config/initializers/cors.rb.tt index 3b1c1b5ed1..3b1c1b5ed1 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/initializers/cors.rb +++ b/railties/lib/rails/generators/rails/app/templates/config/initializers/cors.rb.tt diff --git a/railties/lib/rails/generators/rails/app/templates/config/initializers/filter_parameter_logging.rb b/railties/lib/rails/generators/rails/app/templates/config/initializers/filter_parameter_logging.rb.tt index 4a994e1e7b..4a994e1e7b 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/initializers/filter_parameter_logging.rb +++ b/railties/lib/rails/generators/rails/app/templates/config/initializers/filter_parameter_logging.rb.tt diff --git a/railties/lib/rails/generators/rails/app/templates/config/initializers/inflections.rb b/railties/lib/rails/generators/rails/app/templates/config/initializers/inflections.rb.tt index ac033bf9dc..ac033bf9dc 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/initializers/inflections.rb +++ b/railties/lib/rails/generators/rails/app/templates/config/initializers/inflections.rb.tt diff --git a/railties/lib/rails/generators/rails/app/templates/config/initializers/mime_types.rb b/railties/lib/rails/generators/rails/app/templates/config/initializers/mime_types.rb.tt index dc1899682b..dc1899682b 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/initializers/mime_types.rb +++ b/railties/lib/rails/generators/rails/app/templates/config/initializers/mime_types.rb.tt diff --git a/railties/lib/rails/generators/rails/app/templates/config/initializers/new_framework_defaults_6_0.rb.tt b/railties/lib/rails/generators/rails/app/templates/config/initializers/new_framework_defaults_6_0.rb.tt new file mode 100644 index 0000000000..d25552e923 --- /dev/null +++ b/railties/lib/rails/generators/rails/app/templates/config/initializers/new_framework_defaults_6_0.rb.tt @@ -0,0 +1,33 @@ +# Be sure to restart your server when you modify this file. +# +# This file contains migration options to ease your Rails 6.0 upgrade. +# +# Once upgraded flip defaults one by one to migrate to the new default. +# +# Read the Guide for Upgrading Ruby on Rails for more info on each option. + +# Don't force requests from old versions of IE to be UTF-8 encoded. +# Rails.application.config.action_view.default_enforce_utf8 = false + +# Embed purpose and expiry metadata inside signed and encrypted +# cookies for increased security. +# +# This option is not backwards compatible with earlier Rails versions. +# It's best enabled when your entire app is migrated and stable on 6.0. +# Rails.application.config.action_dispatch.use_cookies_with_metadata = true + +# Return false instead of self when enqueuing is aborted from a callback. +# Rails.application.config.active_job.return_false_on_aborted_enqueue = true + +# Send Active Storage analysis and purge jobs to dedicated queues. +# Rails.application.config.active_storage.queues.analysis = :active_storage_analysis +# Rails.application.config.active_storage.queues.purge = :active_storage_purge + +# Use ActionMailer::MailDeliveryJob for sending parameterized and normal mail. +# +# The default delivery jobs (ActionMailer::Parameterized::DeliveryJob, ActionMailer::DeliveryJob), +# will be removed in Rails 6.1. This setting is not backwards compatible with earlier Rails versions. +# If you send mail in the background, job workers need to have a copy of +# MailDeliveryJob to ensure all delivery jobs are processed properly. +# Make sure your entire app is migrated and stable on 6.0 before using this setting. +# Rails.application.config.action_mailer.delivery_job = "ActionMailer::MailDeliveryJob" diff --git a/railties/lib/rails/generators/rails/app/templates/config/initializers/per_form_csrf_tokens.rb b/railties/lib/rails/generators/rails/app/templates/config/initializers/per_form_csrf_tokens.rb deleted file mode 100644 index 1f569dedfd..0000000000 --- a/railties/lib/rails/generators/rails/app/templates/config/initializers/per_form_csrf_tokens.rb +++ /dev/null @@ -1,4 +0,0 @@ -# Be sure to restart your server when you modify this file. - -# Enable per-form CSRF tokens. -Rails.application.config.action_controller.per_form_csrf_tokens = true diff --git a/railties/lib/rails/generators/rails/app/templates/config/initializers/request_forgery_protection.rb b/railties/lib/rails/generators/rails/app/templates/config/initializers/request_forgery_protection.rb deleted file mode 100644 index 3eab78a885..0000000000 --- a/railties/lib/rails/generators/rails/app/templates/config/initializers/request_forgery_protection.rb +++ /dev/null @@ -1,4 +0,0 @@ -# Be sure to restart your server when you modify this file. - -# Enable origin-checking CSRF mitigation. -Rails.application.config.action_controller.forgery_protection_origin_check = true diff --git a/railties/lib/rails/generators/rails/app/templates/config/initializers/session_store.rb.tt b/railties/lib/rails/generators/rails/app/templates/config/initializers/session_store.rb.tt deleted file mode 100644 index 2bb9b82c61..0000000000 --- a/railties/lib/rails/generators/rails/app/templates/config/initializers/session_store.rb.tt +++ /dev/null @@ -1,3 +0,0 @@ -# Be sure to restart your server when you modify this file. - -Rails.application.config.session_store :cookie_store, key: <%= "'_#{app_name}_session'" %> diff --git a/railties/lib/rails/generators/rails/app/templates/config/initializers/ssl_options.rb b/railties/lib/rails/generators/rails/app/templates/config/initializers/ssl_options.rb deleted file mode 100644 index 1775dea1e7..0000000000 --- a/railties/lib/rails/generators/rails/app/templates/config/initializers/ssl_options.rb +++ /dev/null @@ -1,4 +0,0 @@ -# Be sure to restart your server when you modify this file. - -# Configure SSL options to enable HSTS with subdomains. -Rails.application.config.ssl_options = { hsts: { subdomains: true } } diff --git a/railties/lib/rails/generators/rails/app/templates/config/locales/en.yml b/railties/lib/rails/generators/rails/app/templates/config/locales/en.yml index 0653957166..cf9b342d0a 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/locales/en.yml +++ b/railties/lib/rails/generators/rails/app/templates/config/locales/en.yml @@ -16,8 +16,18 @@ # # This would use the information in config/locales/es.yml. # +# The following keys must be escaped otherwise they will not be retrieved by +# the default I18n backend: +# +# true, false, on, off, yes, no +# +# Instead, surround them with single quotes. +# +# en: +# 'true': 'foo' +# # To learn more, please read the Rails Internationalization guide -# available at http://guides.rubyonrails.org/i18n.html. +# available at https://guides.rubyonrails.org/i18n.html. en: hello: "Hello world" diff --git a/railties/lib/rails/generators/rails/app/templates/config/puma.rb b/railties/lib/rails/generators/rails/app/templates/config/puma.rb.tt index c7f311f811..649253aeca 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/puma.rb +++ b/railties/lib/rails/generators/rails/app/templates/config/puma.rb.tt @@ -1,13 +1,14 @@ # Puma can serve each request in a thread from an internal thread pool. -# The `threads` method setting takes two numbers a minimum and maximum. +# The `threads` method setting takes two numbers: a minimum and maximum. # Any libraries that use thread pools should be configured to match # the maximum value specified for Puma. Default is set to 5 threads for minimum -# and maximum, this matches the default thread size of Active Record. +# and maximum; this matches the default thread size of Active Record. # -threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 }.to_i -threads threads_count, threads_count +max_threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 } +min_threads_count = ENV.fetch("RAILS_MIN_THREADS") { max_threads_count } +threads min_threads_count, max_threads_count -# Specifies the `port` that Puma will listen on to receive requests, default is 3000. +# Specifies the `port` that Puma will listen on to receive requests; default is 3000. # port ENV.fetch("PORT") { 3000 } @@ -16,7 +17,7 @@ port ENV.fetch("PORT") { 3000 } environment ENV.fetch("RAILS_ENV") { "development" } # Specifies the number of `workers` to boot in clustered mode. -# Workers are forked webserver processes. If using threads and workers together +# Workers are forked web server processes. If using threads and workers together # the concurrency of the application would be max `threads` * `workers`. # Workers do not work on JRuby or Windows (both of which do not support # processes). @@ -26,22 +27,9 @@ environment ENV.fetch("RAILS_ENV") { "development" } # Use the `preload_app!` method when specifying a `workers` number. # This directive tells Puma to first boot the application and load code # before forking the application. This takes advantage of Copy On Write -# process behavior so workers use less memory. If you use this option -# you need to make sure to reconnect any threads in the `on_worker_boot` -# block. +# process behavior so workers use less memory. # # preload_app! -# The code in the `on_worker_boot` will be called if you are using -# clustered mode by specifying a number of `workers`. After each worker -# process is booted this block will be run, if you are using `preload_app!` -# option you will want to use this block to reconnect to any threads -# or connections that may have been created at application boot, Ruby -# cannot share connections between processes. -# -# on_worker_boot do -# ActiveRecord::Base.establish_connection if defined?(ActiveRecord) -# end - # Allow puma to be restarted by `rails restart` command. plugin :tmp_restart diff --git a/railties/lib/rails/generators/rails/app/templates/config/routes.rb b/railties/lib/rails/generators/rails/app/templates/config/routes.rb deleted file mode 100644 index 787824f888..0000000000 --- a/railties/lib/rails/generators/rails/app/templates/config/routes.rb +++ /dev/null @@ -1,3 +0,0 @@ -Rails.application.routes.draw do - # For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html -end diff --git a/railties/lib/rails/generators/rails/app/templates/config/routes.rb.tt b/railties/lib/rails/generators/rails/app/templates/config/routes.rb.tt new file mode 100644 index 0000000000..c06383a172 --- /dev/null +++ b/railties/lib/rails/generators/rails/app/templates/config/routes.rb.tt @@ -0,0 +1,3 @@ +Rails.application.routes.draw do + # For details on the DSL available within this file, see https://guides.rubyonrails.org/routing.html +end diff --git a/railties/lib/rails/generators/rails/app/templates/config/secrets.yml b/railties/lib/rails/generators/rails/app/templates/config/secrets.yml deleted file mode 100644 index cdea2fd060..0000000000 --- a/railties/lib/rails/generators/rails/app/templates/config/secrets.yml +++ /dev/null @@ -1,22 +0,0 @@ -# Be sure to restart your server when you modify this file. - -# Your secret key is used for verifying the integrity of signed cookies. -# If you change this key, all old signed cookies will become invalid! - -# Make sure the secret is at least 30 characters and all random, -# no regular words or you'll be exposed to dictionary attacks. -# You can use `rails secret` to generate a secure secret key. - -# Make sure the secrets in this file are kept private -# if you're sharing your code publicly. - -development: - secret_key_base: <%= app_secret %> - -test: - secret_key_base: <%= app_secret %> - -# Do not keep production secrets in the repository, -# instead read values from the environment. -production: - secret_key_base: <%%= ENV["SECRET_KEY_BASE"] %> diff --git a/railties/lib/rails/generators/rails/app/templates/config/spring.rb b/railties/lib/rails/generators/rails/app/templates/config/spring.rb deleted file mode 100644 index c9119b40c0..0000000000 --- a/railties/lib/rails/generators/rails/app/templates/config/spring.rb +++ /dev/null @@ -1,6 +0,0 @@ -%w( - .ruby-version - .rbenv-vars - tmp/restart.txt - tmp/caching-dev.txt -).each { |path| Spring.watch(path) } diff --git a/railties/lib/rails/generators/rails/app/templates/config/spring.rb.tt b/railties/lib/rails/generators/rails/app/templates/config/spring.rb.tt new file mode 100644 index 0000000000..db5bf1307a --- /dev/null +++ b/railties/lib/rails/generators/rails/app/templates/config/spring.rb.tt @@ -0,0 +1,6 @@ +Spring.watch( + ".ruby-version", + ".rbenv-vars", + "tmp/restart.txt", + "tmp/caching-dev.txt" +) diff --git a/railties/lib/rails/generators/rails/app/templates/config/storage.yml.tt b/railties/lib/rails/generators/rails/app/templates/config/storage.yml.tt new file mode 100644 index 0000000000..7207c75086 --- /dev/null +++ b/railties/lib/rails/generators/rails/app/templates/config/storage.yml.tt @@ -0,0 +1,34 @@ +test: + service: Disk + root: <%%= Rails.root.join("tmp/storage") %> + +local: + service: Disk + root: <%%= Rails.root.join("storage") %> + +# Use rails credentials:edit to set the AWS secrets (as aws:access_key_id|secret_access_key) +# amazon: +# service: S3 +# access_key_id: <%%= Rails.application.credentials.dig(:aws, :access_key_id) %> +# secret_access_key: <%%= Rails.application.credentials.dig(:aws, :secret_access_key) %> +# region: us-east-1 +# bucket: your_own_bucket + +# Remember not to checkin your GCS keyfile to a repository +# google: +# service: GCS +# project: your_project +# credentials: <%%= Rails.root.join("path/to/gcs.keyfile") %> +# bucket: your_own_bucket + +# Use rails credentials:edit to set the Azure Storage secret (as azure_storage:storage_access_key) +# microsoft: +# service: AzureStorage +# storage_account_name: your_account_name +# storage_access_key: <%%= Rails.application.credentials.dig(:azure_storage, :storage_access_key) %> +# container: your_container_name + +# mirror: +# service: Mirror +# primary: local +# mirrors: [ amazon, google, microsoft ] diff --git a/railties/lib/rails/generators/rails/app/templates/gitignore b/railties/lib/rails/generators/rails/app/templates/gitignore.tt index 0e66cc4237..860baa1595 100644 --- a/railties/lib/rails/generators/rails/app/templates/gitignore +++ b/railties/lib/rails/generators/rails/app/templates/gitignore.tt @@ -21,5 +21,15 @@ !/tmp/.keep <% end -%> -# Ignore Byebug command history file. +<% unless skip_active_storage? -%> +# Ignore uploaded files in development. +/storage/* +<% if keeps? -%> +!/storage/.keep +<% end -%> +<% end -%> +<% unless options.api? -%> + +/public/assets +<% end -%> .byebug_history diff --git a/railties/lib/rails/generators/rails/app/templates/package.json.tt b/railties/lib/rails/generators/rails/app/templates/package.json.tt new file mode 100644 index 0000000000..07207e1747 --- /dev/null +++ b/railties/lib/rails/generators/rails/app/templates/package.json.tt @@ -0,0 +1,11 @@ +{ + "name": "<%= app_name %>", + "private": true, + "dependencies": { + "@rails/ujs": "^6.0.0-alpha"<% unless options[:skip_turbolinks] %>, + "turbolinks": "^5.2.0"<% end -%><% unless skip_active_storage? %>, + "@rails/activestorage": "^6.0.0-alpha"<% end -%><% unless options[:skip_action_cable] %>, + "@rails/actioncable": "^6.0.0-alpha"<% end %> + }, + "version": "0.1.0" +} diff --git a/railties/lib/rails/generators/rails/app/templates/public/404.html b/railties/lib/rails/generators/rails/app/templates/public/404.html index b612547fc2..2be3af26fc 100644 --- a/railties/lib/rails/generators/rails/app/templates/public/404.html +++ b/railties/lib/rails/generators/rails/app/templates/public/404.html @@ -4,7 +4,7 @@ <title>The page you were looking for doesn't exist (404)</title> <meta name="viewport" content="width=device-width,initial-scale=1"> <style> - body { + .rails-default-error-page { background-color: #EFEFEF; color: #2E2F30; text-align: center; @@ -12,13 +12,13 @@ margin: 0; } - div.dialog { + .rails-default-error-page div.dialog { width: 95%; max-width: 33em; margin: 4em auto 0; } - div.dialog > div { + .rails-default-error-page div.dialog > div { border: 1px solid #CCC; border-right-color: #999; border-left-color: #999; @@ -31,13 +31,13 @@ box-shadow: 0 3px 8px rgba(50, 50, 50, 0.17); } - h1 { + .rails-default-error-page h1 { font-size: 100%; color: #730E15; line-height: 1.5em; } - div.dialog > p { + .rails-default-error-page div.dialog > p { margin: 0 0 1em; padding: 1em; background-color: #F7F7F7; @@ -54,7 +54,7 @@ </style> </head> -<body> +<body class="rails-default-error-page"> <!-- This file lives in public/404.html --> <div class="dialog"> <div> diff --git a/railties/lib/rails/generators/rails/app/templates/public/422.html b/railties/lib/rails/generators/rails/app/templates/public/422.html index a21f82b3bd..c08eac0d1d 100644 --- a/railties/lib/rails/generators/rails/app/templates/public/422.html +++ b/railties/lib/rails/generators/rails/app/templates/public/422.html @@ -4,7 +4,7 @@ <title>The change you wanted was rejected (422)</title> <meta name="viewport" content="width=device-width,initial-scale=1"> <style> - body { + .rails-default-error-page { background-color: #EFEFEF; color: #2E2F30; text-align: center; @@ -12,13 +12,13 @@ margin: 0; } - div.dialog { + .rails-default-error-page div.dialog { width: 95%; max-width: 33em; margin: 4em auto 0; } - div.dialog > div { + .rails-default-error-page div.dialog > div { border: 1px solid #CCC; border-right-color: #999; border-left-color: #999; @@ -31,13 +31,13 @@ box-shadow: 0 3px 8px rgba(50, 50, 50, 0.17); } - h1 { + .rails-default-error-page h1 { font-size: 100%; color: #730E15; line-height: 1.5em; } - div.dialog > p { + .rails-default-error-page div.dialog > p { margin: 0 0 1em; padding: 1em; background-color: #F7F7F7; @@ -54,7 +54,7 @@ </style> </head> -<body> +<body class="rails-default-error-page"> <!-- This file lives in public/422.html --> <div class="dialog"> <div> diff --git a/railties/lib/rails/generators/rails/app/templates/public/500.html b/railties/lib/rails/generators/rails/app/templates/public/500.html index 061abc587d..78a030af22 100644 --- a/railties/lib/rails/generators/rails/app/templates/public/500.html +++ b/railties/lib/rails/generators/rails/app/templates/public/500.html @@ -4,7 +4,7 @@ <title>We're sorry, but something went wrong (500)</title> <meta name="viewport" content="width=device-width,initial-scale=1"> <style> - body { + .rails-default-error-page { background-color: #EFEFEF; color: #2E2F30; text-align: center; @@ -12,13 +12,13 @@ margin: 0; } - div.dialog { + .rails-default-error-page div.dialog { width: 95%; max-width: 33em; margin: 4em auto 0; } - div.dialog > div { + .rails-default-error-page div.dialog > div { border: 1px solid #CCC; border-right-color: #999; border-left-color: #999; @@ -31,13 +31,13 @@ box-shadow: 0 3px 8px rgba(50, 50, 50, 0.17); } - h1 { + .rails-default-error-page h1 { font-size: 100%; color: #730E15; line-height: 1.5em; } - div.dialog > p { + .rails-default-error-page div.dialog > p { margin: 0 0 1em; padding: 1em; background-color: #F7F7F7; @@ -54,7 +54,7 @@ </style> </head> -<body> +<body class="rails-default-error-page"> <!-- This file lives in public/500.html --> <div class="dialog"> <div> diff --git a/railties/lib/rails/generators/rails/app/templates/public/robots.txt b/railties/lib/rails/generators/rails/app/templates/public/robots.txt index 3c9c7c01f3..37b576a4a0 100644 --- a/railties/lib/rails/generators/rails/app/templates/public/robots.txt +++ b/railties/lib/rails/generators/rails/app/templates/public/robots.txt @@ -1,5 +1 @@ # See http://www.robotstxt.org/robotstxt.html for documentation on how to use the robots.txt file -# -# To ban all spiders from the entire site uncomment the next two lines: -# User-agent: * -# Disallow: / diff --git a/railties/lib/rails/generators/rails/app/templates/ruby-version.tt b/railties/lib/rails/generators/rails/app/templates/ruby-version.tt new file mode 100644 index 0000000000..096cfd36a8 --- /dev/null +++ b/railties/lib/rails/generators/rails/app/templates/ruby-version.tt @@ -0,0 +1 @@ +<%= ENV["RBENV_VERSION"] || ENV["rvm_ruby_string"] || "#{RUBY_ENGINE}-#{RUBY_ENGINE_VERSION}" %> diff --git a/railties/lib/rails/generators/rails/app/templates/test/application_system_test_case.rb.tt b/railties/lib/rails/generators/rails/app/templates/test/application_system_test_case.rb.tt new file mode 100644 index 0000000000..d19212abd5 --- /dev/null +++ b/railties/lib/rails/generators/rails/app/templates/test/application_system_test_case.rb.tt @@ -0,0 +1,5 @@ +require "test_helper" + +class ApplicationSystemTestCase < ActionDispatch::SystemTestCase + driven_by :selenium, using: :chrome, screen_size: [1400, 1400] +end diff --git a/railties/lib/rails/generators/rails/app/templates/test/channels/application_cable/connection_test.rb.tt b/railties/lib/rails/generators/rails/app/templates/test/channels/application_cable/connection_test.rb.tt new file mode 100644 index 0000000000..800405f15e --- /dev/null +++ b/railties/lib/rails/generators/rails/app/templates/test/channels/application_cable/connection_test.rb.tt @@ -0,0 +1,11 @@ +require "test_helper" + +class ApplicationCable::ConnectionTest < ActionCable::Connection::TestCase + # test "connects with cookies" do + # cookies.signed[:user_id] = 42 + # + # connect + # + # assert_equal connection.user_id, "42" + # end +end diff --git a/railties/lib/rails/generators/rails/app/templates/test/test_helper.rb b/railties/lib/rails/generators/rails/app/templates/test/test_helper.rb.tt index 87b8fe3516..47b4cf745c 100644 --- a/railties/lib/rails/generators/rails/app/templates/test/test_helper.rb +++ b/railties/lib/rails/generators/rails/app/templates/test/test_helper.rb.tt @@ -1,8 +1,15 @@ ENV['RAILS_ENV'] ||= 'test' -require File.expand_path('../../config/environment', __FILE__) +require_relative '../config/environment' require 'rails/test_help' class ActiveSupport::TestCase + # Run tests in parallel with specified workers +<% if defined?(JRUBY_VERSION) || Gem.win_platform? -%> + parallelize(workers: :number_of_processors, with: :threads) +<%- else -%> + parallelize(workers: :number_of_processors) +<% end -%> + <% unless options[:skip_active_record] -%> # Setup all fixtures in test/fixtures/*.yml for all tests in alphabetical order. fixtures :all diff --git a/railties/lib/rails/generators/rails/application_record/application_record_generator.rb b/railties/lib/rails/generators/rails/application_record/application_record_generator.rb new file mode 100644 index 0000000000..f6b6e76b1d --- /dev/null +++ b/railties/lib/rails/generators/rails/application_record/application_record_generator.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +module Rails + module Generators + class ApplicationRecordGenerator < Base # :nodoc: + hook_for :orm, required: true, desc: "ORM to be invoked" + end + end +end diff --git a/railties/lib/rails/generators/rails/assets/USAGE b/railties/lib/rails/generators/rails/assets/USAGE index d2e5ed4482..ee73d05808 100644 --- a/railties/lib/rails/generators/rails/assets/USAGE +++ b/railties/lib/rails/generators/rails/assets/USAGE @@ -5,16 +5,13 @@ Description: To create an asset within a folder, specify the asset's name as a path like 'parent/name'. - This generates a JavaScript stub in app/assets/javascripts and a stylesheet - stub in app/assets/stylesheets. + This generates a stylesheet stub in app/assets/stylesheets. - If CoffeeScript is available, JavaScripts will be generated with the .coffee extension. If Sass 3 is available, stylesheets will be generated with the .scss extension. Example: `rails generate assets posts` Posts assets. - JavaScript: app/assets/javascripts/posts.js Stylesheet: app/assets/stylesheets/posts.css diff --git a/railties/lib/rails/generators/rails/assets/assets_generator.rb b/railties/lib/rails/generators/rails/assets/assets_generator.rb index 6f4b86e708..9ce8570172 100644 --- a/railties/lib/rails/generators/rails/assets/assets_generator.rb +++ b/railties/lib/rails/generators/rails/assets/assets_generator.rb @@ -1,25 +1,19 @@ +# frozen_string_literal: true + module Rails module Generators class AssetsGenerator < NamedBase # :nodoc: - class_option :javascripts, type: :boolean, desc: "Generate JavaScripts" class_option :stylesheets, type: :boolean, desc: "Generate Stylesheets" - - class_option :javascript_engine, desc: "Engine for JavaScripts" class_option :stylesheet_engine, desc: "Engine for Stylesheets" - protected - - def asset_name - file_name - end - - hook_for :javascript_engine do |javascript_engine| - invoke javascript_engine, [name] if options[:javascripts] - end + private + def asset_name + file_name + end - hook_for :stylesheet_engine do |stylesheet_engine| - invoke stylesheet_engine, [name] if options[:stylesheets] - end + hook_for :stylesheet_engine do |stylesheet_engine| + invoke stylesheet_engine, [name] if options[:stylesheets] + end end end end diff --git a/railties/lib/rails/generators/rails/assets/templates/javascript.js b/railties/lib/rails/generators/rails/assets/templates/javascript.js deleted file mode 100644 index dee720facd..0000000000 --- a/railties/lib/rails/generators/rails/assets/templates/javascript.js +++ /dev/null @@ -1,2 +0,0 @@ -// Place all the behaviors and hooks related to the matching controller here. -// All this logic will automatically be available in application.js. diff --git a/railties/lib/rails/generators/rails/assets/templates/stylesheet.css b/railties/lib/rails/generators/rails/assets/templates/stylesheet.css index 7594abf268..afad32db02 100644 --- a/railties/lib/rails/generators/rails/assets/templates/stylesheet.css +++ b/railties/lib/rails/generators/rails/assets/templates/stylesheet.css @@ -1,4 +1,4 @@ -/* +/* Place all the styles related to the matching controller here. They will automatically be included in application.css. */ diff --git a/railties/lib/rails/generators/rails/controller/controller_generator.rb b/railties/lib/rails/generators/rails/controller/controller_generator.rb index 0a4c509a31..eb75e7e661 100644 --- a/railties/lib/rails/generators/rails/controller/controller_generator.rb +++ b/railties/lib/rails/generators/rails/controller/controller_generator.rb @@ -1,59 +1,76 @@ +# frozen_string_literal: true + module Rails module Generators class ControllerGenerator < NamedBase # :nodoc: argument :actions, type: :array, default: [], banner: "action action" class_option :skip_routes, type: :boolean, desc: "Don't add routes to config/routes.rb." + class_option :helper, type: :boolean + class_option :assets, type: :boolean check_class_collision suffix: "Controller" def create_controller_files - template 'controller.rb', File.join('app/controllers', class_path, "#{file_name}_controller.rb") + template "controller.rb", File.join("app/controllers", class_path, "#{file_name}_controller.rb") end def add_routes - unless options[:skip_routes] - actions.reverse_each do |action| - # route prepends two spaces onto the front of the string that is passed, this corrects that. - route generate_routing_code(action)[2..-1] - end - end + return if options[:skip_routes] + return if actions.empty? + route generate_routing_code end - hook_for :template_engine, :test_framework - hook_for :helper, :assets, hide: true + hook_for :template_engine, :test_framework, :helper, :assets do |generator| + invoke generator, [ remove_possible_suffix(name), actions ] + end private + def file_name + @_file_name ||= remove_possible_suffix(super) + end + + def remove_possible_suffix(name) + name.sub(/_?controller$/i, "") + end + # This method creates nested route entry for namespaced resources. - # For eg. rails g controller foo/bar/baz index + # For eg. rails g controller foo/bar/baz index show # Will generate - # namespace :foo do # namespace :bar do # get 'baz/index' + # get 'baz/show' # end # end - def generate_routing_code(action) - depth = regular_class_path.length + def generate_routing_code + depth = 0 + lines = [] + # Create 'namespace' ladder # namespace :foo do # namespace :bar do - namespace_ladder = regular_class_path.each_with_index.map do |ns, i| - indent(" namespace :#{ns} do\n", i * 2) - end.join + regular_class_path.each do |ns| + lines << indent("namespace :#{ns} do\n", depth * 2) + depth += 1 + end # Create route # get 'baz/index' - route = indent(%{ get '#{file_name}/#{action}'\n}, depth * 2) + # get 'baz/show' + actions.each do |action| + lines << indent(%{get '#{file_name}/#{action}'\n}, depth * 2) + end # Create `end` ladder # end # end - end_ladder = (1..depth).reverse_each.map do |i| - indent("end\n", i * 2) - end.join + until depth.zero? + depth -= 1 + lines << indent("end\n", depth * 2) + end - # Combine the 3 parts to generate complete route entry - namespace_ladder + route + end_ladder + lines.join end end end diff --git a/railties/lib/rails/generators/rails/controller/templates/controller.rb b/railties/lib/rails/generators/rails/controller/templates/controller.rb.tt index 633e0b3177..633e0b3177 100644 --- a/railties/lib/rails/generators/rails/controller/templates/controller.rb +++ b/railties/lib/rails/generators/rails/controller/templates/controller.rb.tt diff --git a/railties/lib/rails/generators/rails/credentials/credentials_generator.rb b/railties/lib/rails/generators/rails/credentials/credentials_generator.rb new file mode 100644 index 0000000000..99b935aa6a --- /dev/null +++ b/railties/lib/rails/generators/rails/credentials/credentials_generator.rb @@ -0,0 +1,56 @@ +# frozen_string_literal: true + +require "rails/generators/base" +require "rails/generators/rails/master_key/master_key_generator" +require "active_support/encrypted_configuration" + +module Rails + module Generators + class CredentialsGenerator < Base # :nodoc: + def add_credentials_file + unless credentials.content_path.exist? + template = credentials_template + + say "Adding #{credentials.content_path} to store encrypted credentials." + say "" + say "The following content has been encrypted with the Rails master key:" + say "" + say template, :on_green + say "" + + add_credentials_file_silently(template) + + say "You can edit encrypted credentials with `rails credentials:edit`." + say "" + end + end + + def add_credentials_file_silently(template = nil) + unless credentials.content_path.exist? + credentials.write(credentials_template) + end + end + + private + def credentials + ActiveSupport::EncryptedConfiguration.new( + config_path: "config/credentials.yml.enc", + key_path: "config/master.key", + env_key: "RAILS_MASTER_KEY", + raise_if_missing_key: true + ) + end + + def credentials_template + <<~YAML + # aws: + # access_key_id: 123 + # secret_access_key: 345 + + # Used as the base secret for all MessageVerifiers in Rails, including the one protecting cookies. + secret_key_base: #{SecureRandom.hex(64)} + YAML + end + end + end +end diff --git a/railties/lib/rails/generators/rails/db/system/change/change_generator.rb b/railties/lib/rails/generators/rails/db/system/change/change_generator.rb new file mode 100644 index 0000000000..24db92fad7 --- /dev/null +++ b/railties/lib/rails/generators/rails/db/system/change/change_generator.rb @@ -0,0 +1,65 @@ +# frozen_string_literal: true + +require "rails/generators/base" + +module Rails + module Generators + module Db + module System + class ChangeGenerator < Base # :nodoc: + include Database + include AppName + + class_option :to, required: true, + desc: "The database system to switch to." + + def self.default_generator_root + path = File.expand_path(File.join(base_name, "app"), base_root) + path if File.exist?(path) + end + + def initialize(*) + super + + unless DATABASES.include?(options[:to]) + raise Error, "Invalid value for --to option. Supported preconfigurations are: #{DATABASES.join(", ")}." + end + + opt = options.dup + opt[:database] ||= opt[:to] + self.options = opt.freeze + end + + def edit_database_config + template("config/databases/#{options[:database]}.yml", "config/database.yml") + end + + def edit_gemfile + name, version = gem_for_database + gsub_file("Gemfile", all_database_gems_regex, name) + gsub_file("Gemfile", gem_entry_regex_for(name), gem_entry_for(name, *version)) + end + + private + def all_database_gems + DATABASES.map { |database| gem_for_database(database) } + end + + def all_database_gems_regex + all_database_gem_names = all_database_gems.map(&:first) + /(\b#{all_database_gem_names.join('\b|\b')}\b)/ + end + + def gem_entry_regex_for(gem_name) + /^gem.*\b#{gem_name}\b.*/ + end + + def gem_entry_for(*gem_name_and_version) + gem_name_and_version.map! { |segment| "'#{segment}'" } + "gem #{gem_name_and_version.join(", ")}" + end + end + end + end + end +end diff --git a/railties/lib/rails/generators/rails/encrypted_file/encrypted_file_generator.rb b/railties/lib/rails/generators/rails/encrypted_file/encrypted_file_generator.rb new file mode 100644 index 0000000000..867e28c6db --- /dev/null +++ b/railties/lib/rails/generators/rails/encrypted_file/encrypted_file_generator.rb @@ -0,0 +1,27 @@ +# frozen_string_literal: true + +require "rails/generators/base" +require "active_support/encrypted_file" + +module Rails + module Generators + class EncryptedFileGenerator < Base # :nodoc: + def add_encrypted_file_silently(file_path, key_path, template = encrypted_file_template) + unless File.exist?(file_path) + setup = { content_path: file_path, key_path: key_path, env_key: "RAILS_MASTER_KEY", raise_if_missing_key: true } + ActiveSupport::EncryptedFile.new(setup).write(template) + end + end + + private + def encrypted_file_template + <<~YAML + # aws: + # access_key_id: 123 + # secret_access_key: 345 + + YAML + end + end + end +end diff --git a/railties/lib/rails/generators/rails/encryption_key_file/encryption_key_file_generator.rb b/railties/lib/rails/generators/rails/encryption_key_file/encryption_key_file_generator.rb new file mode 100644 index 0000000000..e2359e9ded --- /dev/null +++ b/railties/lib/rails/generators/rails/encryption_key_file/encryption_key_file_generator.rb @@ -0,0 +1,58 @@ +# frozen_string_literal: true + +require "pathname" +require "rails/generators/base" +require "active_support/encrypted_file" + +module Rails + module Generators + class EncryptionKeyFileGenerator < Base # :nodoc: + def add_key_file(key_path) + key_path = Pathname.new(key_path) + + unless key_path.exist? + key = ActiveSupport::EncryptedFile.generate_key + + log "Adding #{key_path} to store the encryption key: #{key}" + log "" + log "Save this in a password manager your team can access." + log "" + log "If you lose the key, no one, including you, can access anything encrypted with it." + + log "" + add_key_file_silently(key_path, key) + log "" + end + end + + def add_key_file_silently(key_path, key = nil) + create_file key_path, key || ActiveSupport::EncryptedFile.generate_key + key_path.chmod 0600 + end + + def ignore_key_file(key_path, ignore: key_ignore(key_path)) + if File.exist?(".gitignore") + unless File.read(".gitignore").include?(ignore) + log "Ignoring #{key_path} so it won't end up in Git history:" + log "" + append_to_file ".gitignore", ignore + log "" + end + else + log "IMPORTANT: Don't commit #{key_path}. Add this to your ignore file:" + log ignore, :on_green + log "" + end + end + + def ignore_key_file_silently(key_path, ignore: key_ignore(key_path)) + append_to_file ".gitignore", ignore if File.exist?(".gitignore") + end + + private + def key_ignore(key_path) + [ "", "/#{key_path}", "" ].join("\n") + end + end + end +end diff --git a/railties/lib/rails/generators/rails/generator/generator_generator.rb b/railties/lib/rails/generators/rails/generator/generator_generator.rb index 15d88f06ac..747acd68d1 100644 --- a/railties/lib/rails/generators/rails/generator/generator_generator.rb +++ b/railties/lib/rails/generators/rails/generator/generator_generator.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Rails module Generators class GeneratorGenerator < NamedBase # :nodoc: @@ -7,12 +9,12 @@ module Rails desc: "Namespace generator under lib/generators/name" def create_generator_files - directory '.', generator_dir + directory ".", generator_dir end hook_for :test_framework - protected + private def generator_dir if options[:namespace] @@ -21,7 +23,6 @@ module Rails File.join("lib", "generators", regular_class_path) end end - end end end diff --git a/railties/lib/rails/generators/rails/generator/templates/%file_name%_generator.rb.tt b/railties/lib/rails/generators/rails/generator/templates/%file_name%_generator.rb.tt index d0575772bc..178d5c3f9f 100644 --- a/railties/lib/rails/generators/rails/generator/templates/%file_name%_generator.rb.tt +++ b/railties/lib/rails/generators/rails/generator/templates/%file_name%_generator.rb.tt @@ -1,3 +1,3 @@ class <%= class_name %>Generator < Rails::Generators::NamedBase - source_root File.expand_path('../templates', __FILE__) + source_root File.expand_path('templates', __dir__) end diff --git a/railties/lib/rails/generators/rails/helper/helper_generator.rb b/railties/lib/rails/generators/rails/helper/helper_generator.rb index 5ff38e4111..542eb4c9e8 100644 --- a/railties/lib/rails/generators/rails/helper/helper_generator.rb +++ b/railties/lib/rails/generators/rails/helper/helper_generator.rb @@ -1,13 +1,20 @@ +# frozen_string_literal: true + module Rails module Generators class HelperGenerator < NamedBase # :nodoc: check_class_collision suffix: "Helper" def create_helper_files - template 'helper.rb', File.join('app/helpers', class_path, "#{file_name}_helper.rb") + template "helper.rb", File.join("app/helpers", class_path, "#{file_name}_helper.rb") end hook_for :test_framework + + private + def file_name + @_file_name ||= super.sub(/_helper\z/i, "") + end end end end diff --git a/railties/lib/rails/generators/rails/helper/templates/helper.rb b/railties/lib/rails/generators/rails/helper/templates/helper.rb.tt index b4173151b4..b4173151b4 100644 --- a/railties/lib/rails/generators/rails/helper/templates/helper.rb +++ b/railties/lib/rails/generators/rails/helper/templates/helper.rb.tt diff --git a/railties/lib/rails/generators/rails/integration_test/integration_test_generator.rb b/railties/lib/rails/generators/rails/integration_test/integration_test_generator.rb index 70770ddcb8..975dd8b90c 100644 --- a/railties/lib/rails/generators/rails/integration_test/integration_test_generator.rb +++ b/railties/lib/rails/generators/rails/integration_test/integration_test_generator.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Rails module Generators class IntegrationTestGenerator < NamedBase # :nodoc: diff --git a/railties/lib/rails/generators/rails/master_key/master_key_generator.rb b/railties/lib/rails/generators/rails/master_key/master_key_generator.rb new file mode 100644 index 0000000000..21664ea86d --- /dev/null +++ b/railties/lib/rails/generators/rails/master_key/master_key_generator.rb @@ -0,0 +1,53 @@ +# frozen_string_literal: true + +require "pathname" +require "rails/generators/base" +require "rails/generators/rails/encryption_key_file/encryption_key_file_generator" +require "active_support/encrypted_file" + +module Rails + module Generators + class MasterKeyGenerator < Base # :nodoc: + MASTER_KEY_PATH = Pathname.new("config/master.key") + + def add_master_key_file + unless MASTER_KEY_PATH.exist? + key = ActiveSupport::EncryptedFile.generate_key + + log "Adding #{MASTER_KEY_PATH} to store the master encryption key: #{key}" + log "" + log "Save this in a password manager your team can access." + log "" + log "If you lose the key, no one, including you, can access anything encrypted with it." + + log "" + add_master_key_file_silently(key) + log "" + end + end + + def add_master_key_file_silently(key = nil) + unless MASTER_KEY_PATH.exist? + key_file_generator.add_key_file_silently(MASTER_KEY_PATH, key) + end + end + + def ignore_master_key_file + key_file_generator.ignore_key_file(MASTER_KEY_PATH, ignore: key_ignore) + end + + def ignore_master_key_file_silently + key_file_generator.ignore_key_file_silently(MASTER_KEY_PATH, ignore: key_ignore) + end + + private + def key_file_generator + EncryptionKeyFileGenerator.new([], options) + end + + def key_ignore + [ "", "# Ignore master key for decrypting credentials and more.", "/#{MASTER_KEY_PATH}", "" ].join("\n") + end + end + end +end diff --git a/railties/lib/rails/generators/rails/migration/migration_generator.rb b/railties/lib/rails/generators/rails/migration/migration_generator.rb index fca2a8fef4..c331c135e3 100644 --- a/railties/lib/rails/generators/rails/migration/migration_generator.rb +++ b/railties/lib/rails/generators/rails/migration/migration_generator.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Rails module Generators class MigrationGenerator < NamedBase # :nodoc: diff --git a/railties/lib/rails/generators/rails/model/model_generator.rb b/railties/lib/rails/generators/rails/model/model_generator.rb index ec78fd855d..de4de2cae2 100644 --- a/railties/lib/rails/generators/rails/model/model_generator.rb +++ b/railties/lib/rails/generators/rails/model/model_generator.rb @@ -1,4 +1,6 @@ -require 'rails/generators/model_helpers' +# frozen_string_literal: true + +require "rails/generators/model_helpers" module Rails module Generators diff --git a/railties/lib/rails/generators/rails/plugin/plugin_generator.rb b/railties/lib/rails/generators/rails/plugin/plugin_generator.rb index 56efd35a95..79a06648b5 100644 --- a/railties/lib/rails/generators/rails/plugin/plugin_generator.rb +++ b/railties/lib/rails/generators/rails/plugin/plugin_generator.rb @@ -1,6 +1,7 @@ -require 'active_support/core_ext/hash/slice' +# frozen_string_literal: true + require "rails/generators/rails/app/app_generator" -require 'date' +require "date" module Rails # The plugin builder allows you to override elements of the plugin @@ -18,20 +19,20 @@ module Rails def app if mountable? if api? - directory 'app', exclude_pattern: %r{app/(views|helpers)} + directory "app", exclude_pattern: %r{app/(views|helpers)} else - directory 'app' + directory "app" empty_directory_with_keep_file "app/assets/images/#{namespaced_name}" end elsif full? - empty_directory_with_keep_file 'app/models' - empty_directory_with_keep_file 'app/controllers' - empty_directory_with_keep_file 'app/mailers' + empty_directory_with_keep_file "app/models" + empty_directory_with_keep_file "app/controllers" + empty_directory_with_keep_file "app/mailers" unless api? empty_directory_with_keep_file "app/assets/images/#{namespaced_name}" - empty_directory_with_keep_file 'app/helpers' - empty_directory_with_keep_file 'app/views' + empty_directory_with_keep_file "app/helpers" + empty_directory_with_keep_file "app/views" end end end @@ -60,7 +61,12 @@ module Rails template "lib/%namespaced_name%.rb" template "lib/tasks/%namespaced_name%_tasks.rake" template "lib/%namespaced_name%/version.rb" - template "lib/%namespaced_name%/engine.rb" if engine? + + if engine? + template "lib/%namespaced_name%/engine.rb" + else + template "lib/%namespaced_name%/railtie.rb" + end end def config @@ -71,8 +77,8 @@ module Rails template "test/test_helper.rb" template "test/%namespaced_name%_test.rb" append_file "Rakefile", <<-EOF -#{rakefile_test_tasks} +#{rakefile_test_tasks} task default: :test EOF if engine? @@ -81,16 +87,19 @@ task default: :test end PASSTHROUGH_OPTIONS = [ - :skip_active_record, :skip_action_mailer, :skip_javascript, :database, - :javascript, :quiet, :pretend, :force, :skip + :skip_active_record, :skip_active_storage, :skip_action_mailer, :skip_javascript, :skip_action_cable, :skip_sprockets, :database, + :api, :quiet, :pretend, :skip ] def generate_test_dummy(force = false) - opts = (options || {}).slice(*PASSTHROUGH_OPTIONS) + opts = (options.dup || {}).keep_if { |k, _| PASSTHROUGH_OPTIONS.map(&:to_s).include?(k) } opts[:force] = force opts[:skip_bundle] = true - opts[:api] = options.api? opts[:skip_listen] = true + opts[:skip_git] = true + opts[:skip_turbolinks] = true + opts[:skip_webpack_install] = true + opts[:dummy_app] = true invoke Rails::Generators::AppGenerator, [ File.expand_path(dummy_path, destination_root) ], opts @@ -105,16 +114,14 @@ task default: :test end def test_dummy_assets - template "rails/javascripts.js", "#{dummy_path}/app/assets/javascripts/application.js", force: true + template "rails/javascripts.js", "#{dummy_path}/app/javascript/packs/application.js", force: true template "rails/stylesheets.css", "#{dummy_path}/app/assets/stylesheets/application.css", force: true template "rails/dummy_manifest.js", "#{dummy_path}/app/assets/config/manifest.js", force: true end def test_dummy_clean inside dummy_path do - remove_file ".gitignore" remove_file "db/seeds.rb" - remove_file "doc" remove_file "Gemfile" remove_file "lib/tasks" remove_file "public/robots.txt" @@ -149,7 +156,7 @@ task default: :test end def bin(force = false) - bin_file = engine? ? 'bin/rails.tt' : 'bin/test.tt' + bin_file = engine? ? "bin/rails.tt" : "bin/test.tt" template bin_file, force: force do |content| "#{shebang}\n" + content end @@ -161,7 +168,7 @@ task default: :test gemfile_in_app_path = File.join(rails_app_path, "Gemfile") if File.exist? gemfile_in_app_path - entry = "gem '#{name}', path: '#{relative_path}'" + entry = "\ngem '#{name}', path: '#{relative_path}'" append_file gemfile_in_app_path, entry end end @@ -186,7 +193,7 @@ task default: :test desc: "Skip gemspec file" class_option :skip_gemfile_entry, type: :boolean, default: false, - desc: "If creating plugin in application's directory " + + desc: "If creating plugin in application's directory " \ "skip adding entry to Gemfile" class_option :api, type: :boolean, default: false, @@ -195,10 +202,6 @@ task default: :test def initialize(*args) @dummy_path = nil super - - unless plugin_path - raise Error, "Plugin name should be provided in arguments. For details run: rails plugin new --help" - end end public_task :set_default_accessors! @@ -258,20 +261,14 @@ task default: :test build(:leftovers) end - public_task :apply_rails_template, :run_bundle - - def run_after_bundle_callbacks - @after_bundle_callbacks.each do |callback| - callback.call - end - end + public_task :apply_rails_template def name @name ||= begin # same as ActiveSupport::Inflector#underscore except not replacing '-' underscored = original_name.dup - underscored.gsub!(/([A-Z]+)([A-Z][a-z])/,'\1_\2') - underscored.gsub!(/([a-z\d])([A-Z])/,'\1_\2') + underscored.gsub!(/([A-Z]+)([A-Z][a-z])/, '\1_\2') + underscored.gsub!(/([a-z\d])([A-Z])/, '\1_\2') underscored.downcase! underscored @@ -283,10 +280,10 @@ task default: :test end def namespaced_name - @namespaced_name ||= name.gsub('-', '/') + @namespaced_name ||= name.tr("-", "/") end - protected + private def create_dummy_app(path = nil) dummy_path(path) if path @@ -304,7 +301,7 @@ task default: :test end def engine? - full? || mountable? + full? || mountable? || options[:engine] end def full? @@ -320,7 +317,7 @@ task default: :test end def with_dummy_app? - options[:skip_test].blank? || options[:dummy_path] != 'test/dummy' + options[:skip_test].blank? || options[:dummy_path] != "test/dummy" end def api? @@ -328,7 +325,7 @@ task default: :test end def self.banner - "rails plugin new #{self.arguments.map(&:usage).join(' ')} [options]" + "rails plugin new #{arguments.map(&:usage).join(' ')} [options]" end def original_name @@ -340,11 +337,11 @@ task default: :test end def wrap_in_modules(unwrapped_code) - unwrapped_code = "#{unwrapped_code}".strip.gsub(/\s$\n/, '') + unwrapped_code = "#{unwrapped_code}".strip.gsub(/\s$\n/, "") modules.reverse.inject(unwrapped_code) do |content, mod| - str = "module #{mod}\n" - str += content.lines.map { |line| " #{line}" }.join - str += content.present? ? "\nend" : "end" + str = +"module #{mod}\n" + str << content.lines.map { |line| " #{line}" }.join + str << (content.present? ? "\nend" : "end") end end @@ -357,7 +354,7 @@ task default: :test end def camelized - @camelized ||= name.gsub(/\W/, '_').squeeze('_').camelize + @camelized ||= name.gsub(/\W/, "_").squeeze("_").camelize end def author @@ -379,11 +376,11 @@ task default: :test end def valid_const? - if original_name =~ /-\d/ + if /-\d/.match?(original_name) raise Error, "Invalid plugin name #{original_name}. Please give a name which does not contain a namespace starting with numeric characters." - elsif original_name =~ /[^\w-]+/ + elsif /[^\w-]+/.match?(original_name) raise Error, "Invalid plugin name #{original_name}. Please give a name which uses only alphabetic, numeric, \"_\" or \"-\" characters." - elsif camelized =~ /^\d/ + elsif /^\d/.match?(camelized) raise Error, "Invalid plugin name #{original_name}. Please give a name which does not start with numbers." elsif RESERVED_NAMES.include?(name) raise Error, "Invalid plugin name #{original_name}. Please give a " \ @@ -415,7 +412,6 @@ task default: :test require 'rake/testtask' Rake::TestTask.new(:test) do |t| - t.libs << 'lib' t.libs << 'test' t.pattern = 'test/**/*_test.rb' t.verbose = false @@ -437,12 +433,12 @@ end end def inside_application? - rails_app_path && app_path =~ /^#{rails_app_path}/ + rails_app_path && destination_root.start_with?(rails_app_path.to_s) end def relative_path return unless inside_application? - app_path.sub(/^#{rails_app_path}\//, '') + app_path.sub(/^#{rails_app_path}\//, "") end end end diff --git a/railties/lib/rails/generators/rails/plugin/templates/%name%.gemspec b/railties/lib/rails/generators/rails/plugin/templates/%name%.gemspec deleted file mode 100644 index d84d1aabdb..0000000000 --- a/railties/lib/rails/generators/rails/plugin/templates/%name%.gemspec +++ /dev/null @@ -1,24 +0,0 @@ -$:.push File.expand_path("../lib", __FILE__) - -# Maintain your gem's version: -require "<%= namespaced_name %>/version" - -# Describe your gem and declare its dependencies: -Gem::Specification.new do |s| - s.name = "<%= name %>" - s.version = <%= camelized_modules %>::VERSION - s.authors = ["<%= author %>"] - s.email = ["<%= email %>"] - s.homepage = "TODO" - s.summary = "TODO: Summary of <%= camelized_modules %>." - s.description = "TODO: Description of <%= camelized_modules %>." - s.license = "MIT" - - s.files = Dir["{app,config,db,lib}/**/*", "MIT-LICENSE", "Rakefile", "README.md"] - - <%= '# ' if options.dev? || options.edge? -%>s.add_dependency "rails", "<%= Array(rails_version_specifier).join('", "') %>" -<% unless options[:skip_active_record] -%> - - s.add_development_dependency "<%= gem_for_database[0] %>" -<% end -%> -end diff --git a/railties/lib/rails/generators/rails/plugin/templates/%name%.gemspec.tt b/railties/lib/rails/generators/rails/plugin/templates/%name%.gemspec.tt new file mode 100644 index 0000000000..405642c850 --- /dev/null +++ b/railties/lib/rails/generators/rails/plugin/templates/%name%.gemspec.tt @@ -0,0 +1,33 @@ +$:.push File.expand_path("lib", __dir__) + +# Maintain your gem's version: +require "<%= namespaced_name %>/version" + +# Describe your gem and declare its dependencies: +Gem::Specification.new do |spec| + spec.name = "<%= name %>" + spec.version = <%= camelized_modules %>::VERSION + spec.authors = ["<%= author %>"] + spec.email = ["<%= email %>"] + spec.homepage = "TODO" + spec.summary = "TODO: Summary of <%= camelized_modules %>." + spec.description = "TODO: Description of <%= camelized_modules %>." + spec.license = "MIT" + + # Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host' + # to allow pushing to a single host or delete this section to allow pushing to any host. + if spec.respond_to?(:metadata) + spec.metadata["allowed_push_host"] = "TODO: Set to 'http://mygemserver.com'" + else + raise "RubyGems 2.0 or newer is required to protect against " \ + "public gem pushes." + end + + spec.files = Dir["{app,config,db,lib}/**/*", "MIT-LICENSE", "Rakefile", "README.md"] + + <%= '# ' if options.dev? || options.edge? -%>spec.add_dependency "rails", "<%= Array(rails_version_specifier).join('", "') %>" +<% unless options[:skip_active_record] -%> + + spec.add_development_dependency "<%= gem_for_database[0] %>" +<% end -%> +end diff --git a/railties/lib/rails/generators/rails/plugin/templates/Gemfile b/railties/lib/rails/generators/rails/plugin/templates/Gemfile.tt index 22a4548ff2..290259b4db 100644 --- a/railties/lib/rails/generators/rails/plugin/templates/Gemfile +++ b/railties/lib/rails/generators/rails/plugin/templates/Gemfile.tt @@ -1,4 +1,5 @@ source 'https://rubygems.org' +git_source(:github) { |repo| "https://github.com/#{repo}.git" } <% if options[:skip_gemspec] -%> <%= '# ' if options.dev? || options.edge? -%>gem 'rails', '<%= Array(rails_version_specifier).join("', '") %>' diff --git a/railties/lib/rails/generators/rails/plugin/templates/MIT-LICENSE b/railties/lib/rails/generators/rails/plugin/templates/MIT-LICENSE.tt index ff2fb3ba4e..ff2fb3ba4e 100644 --- a/railties/lib/rails/generators/rails/plugin/templates/MIT-LICENSE +++ b/railties/lib/rails/generators/rails/plugin/templates/MIT-LICENSE.tt diff --git a/railties/lib/rails/generators/rails/plugin/templates/README.md b/railties/lib/rails/generators/rails/plugin/templates/README.md.tt index 9d2b74416e..1632409bea 100644 --- a/railties/lib/rails/generators/rails/plugin/templates/README.md +++ b/railties/lib/rails/generators/rails/plugin/templates/README.md.tt @@ -25,4 +25,4 @@ $ gem install <%= name %> Contribution directions go here. ## License -The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT). +The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT). diff --git a/railties/lib/rails/generators/rails/plugin/templates/Rakefile b/railties/lib/rails/generators/rails/plugin/templates/Rakefile.tt index f1943644e4..f3efe21cf1 100644 --- a/railties/lib/rails/generators/rails/plugin/templates/Rakefile +++ b/railties/lib/rails/generators/rails/plugin/templates/Rakefile.tt @@ -13,17 +13,16 @@ RDoc::Task.new(:rdoc) do |rdoc| rdoc.rdoc_files.include('README.md') rdoc.rdoc_files.include('lib/**/*.rb') end - <% if engine? && !options[:skip_active_record] && with_dummy_app? -%> -APP_RAKEFILE = File.expand_path("../<%= dummy_path -%>/Rakefile", __FILE__) -load 'rails/tasks/engine.rake' -<% end %> +APP_RAKEFILE = File.expand_path("<%= dummy_path -%>/Rakefile", __dir__) +load 'rails/tasks/engine.rake' +<% end -%> <% if engine? -%> -load 'rails/tasks/statistics.rake' -<% end %> +load 'rails/tasks/statistics.rake' +<% end -%> <% unless options[:skip_gemspec] -%> -Bundler::GemHelper.install_tasks -<% end %> +require 'bundler/gem_tasks' +<% end -%> diff --git a/railties/lib/rails/generators/rails/plugin/templates/app/controllers/%namespaced_name%/application_controller.rb.tt b/railties/lib/rails/generators/rails/plugin/templates/app/controllers/%namespaced_name%/application_controller.rb.tt index abbacd9bec..b86ef0f2f8 100644 --- a/railties/lib/rails/generators/rails/plugin/templates/app/controllers/%namespaced_name%/application_controller.rb.tt +++ b/railties/lib/rails/generators/rails/plugin/templates/app/controllers/%namespaced_name%/application_controller.rb.tt @@ -1,4 +1,4 @@ -<%= wrap_in_modules <<-rb.strip_heredoc +<%= wrap_in_modules <<~rb class ApplicationController < ActionController::#{api? ? "API" : "Base"} #{ api? ? '# ' : '' }protect_from_forgery with: :exception end diff --git a/railties/lib/rails/generators/rails/plugin/templates/app/helpers/%namespaced_name%/application_helper.rb.tt b/railties/lib/rails/generators/rails/plugin/templates/app/helpers/%namespaced_name%/application_helper.rb.tt index 25d692732d..be078f36de 100644 --- a/railties/lib/rails/generators/rails/plugin/templates/app/helpers/%namespaced_name%/application_helper.rb.tt +++ b/railties/lib/rails/generators/rails/plugin/templates/app/helpers/%namespaced_name%/application_helper.rb.tt @@ -1,4 +1,4 @@ -<%= wrap_in_modules <<-rb.strip_heredoc +<%= wrap_in_modules <<~rb module ApplicationHelper end rb diff --git a/railties/lib/rails/generators/rails/plugin/templates/app/jobs/%namespaced_name%/application_job.rb.tt b/railties/lib/rails/generators/rails/plugin/templates/app/jobs/%namespaced_name%/application_job.rb.tt index bad1ff2d16..846863bc13 100644 --- a/railties/lib/rails/generators/rails/plugin/templates/app/jobs/%namespaced_name%/application_job.rb.tt +++ b/railties/lib/rails/generators/rails/plugin/templates/app/jobs/%namespaced_name%/application_job.rb.tt @@ -1,4 +1,4 @@ -<%= wrap_in_modules <<-rb.strip_heredoc +<%= wrap_in_modules <<~rb class ApplicationJob < ActiveJob::Base end rb diff --git a/railties/lib/rails/generators/rails/plugin/templates/app/mailers/%namespaced_name%/application_mailer.rb.tt b/railties/lib/rails/generators/rails/plugin/templates/app/mailers/%namespaced_name%/application_mailer.rb.tt index 09aac13f42..246e274348 100644 --- a/railties/lib/rails/generators/rails/plugin/templates/app/mailers/%namespaced_name%/application_mailer.rb.tt +++ b/railties/lib/rails/generators/rails/plugin/templates/app/mailers/%namespaced_name%/application_mailer.rb.tt @@ -1,4 +1,4 @@ -<%= wrap_in_modules <<-rb.strip_heredoc +<%= wrap_in_modules <<~rb class ApplicationMailer < ActionMailer::Base default from: 'from@example.com' layout 'mailer' diff --git a/railties/lib/rails/generators/rails/plugin/templates/app/models/%namespaced_name%/application_record.rb.tt b/railties/lib/rails/generators/rails/plugin/templates/app/models/%namespaced_name%/application_record.rb.tt index 8aa3de78f1..21465278be 100644 --- a/railties/lib/rails/generators/rails/plugin/templates/app/models/%namespaced_name%/application_record.rb.tt +++ b/railties/lib/rails/generators/rails/plugin/templates/app/models/%namespaced_name%/application_record.rb.tt @@ -1,4 +1,4 @@ -<%= wrap_in_modules <<-rb.strip_heredoc +<%= wrap_in_modules <<~rb class ApplicationRecord < ActiveRecord::Base self.abstract_class = true end diff --git a/railties/lib/rails/generators/rails/plugin/templates/app/views/layouts/%namespaced_name%/application.html.erb.tt b/railties/lib/rails/generators/rails/plugin/templates/app/views/layouts/%namespaced_name%/application.html.erb.tt index 6bc480161d..6e54a1ce9d 100644 --- a/railties/lib/rails/generators/rails/plugin/templates/app/views/layouts/%namespaced_name%/application.html.erb.tt +++ b/railties/lib/rails/generators/rails/plugin/templates/app/views/layouts/%namespaced_name%/application.html.erb.tt @@ -2,9 +2,13 @@ <html> <head> <title><%= humanized %></title> + <%%= csrf_meta_tags %> + <%%= csp_meta_tag %> + <%%= stylesheet_link_tag "<%= namespaced_name %>/application", media: "all" %> + <%- unless options[:skip_javascript] -%> <%%= javascript_include_tag "<%= namespaced_name %>/application" %> - <%%= csrf_meta_tags %> + <%- end -%> </head> <body> diff --git a/railties/lib/rails/generators/rails/plugin/templates/bin/rails.tt b/railties/lib/rails/generators/rails/plugin/templates/bin/rails.tt index 3edaac35c9..ee8e469da2 100644 --- a/railties/lib/rails/generators/rails/plugin/templates/bin/rails.tt +++ b/railties/lib/rails/generators/rails/plugin/templates/bin/rails.tt @@ -1,11 +1,30 @@ -# This command will automatically be run when you run "rails" with Rails 4 gems installed from the root of your application. +# This command will automatically be run when you run "rails" with Rails gems +# installed from the root of your application. -ENGINE_ROOT = File.expand_path('../..', __FILE__) -ENGINE_PATH = File.expand_path('../../lib/<%= namespaced_name -%>/engine', __FILE__) +ENGINE_ROOT = File.expand_path('..', __dir__) +ENGINE_PATH = File.expand_path('../lib/<%= namespaced_name -%>/engine', __dir__) +<% if with_dummy_app? -%> +APP_PATH = File.expand_path('../<%= dummy_path -%>/config/application', __dir__) +<% end -%> # Set up gems listed in the Gemfile. -ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__) +ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__) require 'bundler/setup' if File.exist?(ENV['BUNDLE_GEMFILE']) +<% if include_all_railties? -%> require 'rails/all' +<% else -%> +require "rails" +# Pick the frameworks you want: +require "active_model/railtie" +require "active_job/railtie" +<%= comment_if :skip_active_record %>require "active_record/railtie" +<%= comment_if :skip_active_storage %>require "active_storage/engine" +require "action_controller/railtie" +<%= comment_if :skip_action_mailer %>require "action_mailer/railtie" +require "action_view/railtie" +<%= comment_if :skip_action_cable %>require "action_cable/engine" +<%= comment_if :skip_sprockets %>require "sprockets/railtie" +<%= comment_if :skip_test %>require "rails/test_unit/railtie" +<% end -%> require 'rails/engine/commands' diff --git a/railties/lib/rails/generators/rails/plugin/templates/bin/test.tt b/railties/lib/rails/generators/rails/plugin/templates/bin/test.tt index 62b94618fd..8e7d321626 100644 --- a/railties/lib/rails/generators/rails/plugin/templates/bin/test.tt +++ b/railties/lib/rails/generators/rails/plugin/templates/bin/test.tt @@ -1,8 +1,4 @@ -$: << File.expand_path(File.expand_path('../../test', __FILE__)) +$: << File.expand_path("../test", __dir__) -require 'bundler/setup' -require 'rails/test_unit/minitest_plugin' - -Rails::TestUnitReporter.executable = 'bin/test' - -exit Minitest.run(ARGV) +require "bundler/setup" +require "rails/plugin/test" diff --git a/railties/lib/rails/generators/rails/plugin/templates/config/routes.rb b/railties/lib/rails/generators/rails/plugin/templates/config/routes.rb.tt index 154452bfe5..154452bfe5 100644 --- a/railties/lib/rails/generators/rails/plugin/templates/config/routes.rb +++ b/railties/lib/rails/generators/rails/plugin/templates/config/routes.rb.tt diff --git a/railties/lib/rails/generators/rails/plugin/templates/gitignore b/railties/lib/rails/generators/rails/plugin/templates/gitignore deleted file mode 100644 index 54c78d7927..0000000000 --- a/railties/lib/rails/generators/rails/plugin/templates/gitignore +++ /dev/null @@ -1,9 +0,0 @@ -.bundle/ -log/*.log -pkg/ -<% unless options[:skip_test] && options[:dummy_path] == 'test/dummy' -%> -<%= dummy_path %>/db/*.sqlite3 -<%= dummy_path %>/db/*.sqlite3-journal -<%= dummy_path %>/log/*.log -<%= dummy_path %>/tmp/ -<% end -%> diff --git a/railties/lib/rails/generators/rails/plugin/templates/gitignore.tt b/railties/lib/rails/generators/rails/plugin/templates/gitignore.tt new file mode 100644 index 0000000000..0aabf09252 --- /dev/null +++ b/railties/lib/rails/generators/rails/plugin/templates/gitignore.tt @@ -0,0 +1,18 @@ +.bundle/ +log/*.log +pkg/ +<% if with_dummy_app? -%> +<% if sqlite3? -%> +<%= dummy_path %>/db/*.sqlite3 +<%= dummy_path %>/db/*.sqlite3-journal +<% end -%> +<%= dummy_path %>/log/*.log +<% unless options[:skip_javascript] -%> +<%= dummy_path %>/node_modules/ +<%= dummy_path %>/yarn-error.log +<% end -%> +<% unless skip_active_storage? -%> +<%= dummy_path %>/storage/ +<% end -%> +<%= dummy_path %>/tmp/ +<% end -%> diff --git a/railties/lib/rails/generators/rails/plugin/templates/lib/%namespaced_name%.rb b/railties/lib/rails/generators/rails/plugin/templates/lib/%namespaced_name%.rb.tt index 40b1c4cee7..3285055eb7 100644 --- a/railties/lib/rails/generators/rails/plugin/templates/lib/%namespaced_name%.rb +++ b/railties/lib/rails/generators/rails/plugin/templates/lib/%namespaced_name%.rb.tt @@ -1,5 +1,7 @@ <% if engine? -%> require "<%= namespaced_name %>/engine" - +<% else -%> +require "<%= namespaced_name %>/railtie" <% end -%> + <%= wrap_in_modules "# Your code goes here..." %> diff --git a/railties/lib/rails/generators/rails/plugin/templates/lib/%namespaced_name%/engine.rb b/railties/lib/rails/generators/rails/plugin/templates/lib/%namespaced_name%/engine.rb.tt index 8938770fc4..4ec1804940 100644 --- a/railties/lib/rails/generators/rails/plugin/templates/lib/%namespaced_name%/engine.rb +++ b/railties/lib/rails/generators/rails/plugin/templates/lib/%namespaced_name%/engine.rb.tt @@ -1,4 +1,4 @@ -<%= wrap_in_modules <<-rb.strip_heredoc +<%= wrap_in_modules <<~rb class Engine < ::Rails::Engine #{mountable? ? ' isolate_namespace ' + camelized_modules : ' '} #{api? ? " config.generators.api_only = true" : ' '} diff --git a/railties/lib/rails/generators/rails/plugin/templates/lib/%namespaced_name%/railtie.rb.tt b/railties/lib/rails/generators/rails/plugin/templates/lib/%namespaced_name%/railtie.rb.tt new file mode 100644 index 0000000000..b853fabcc3 --- /dev/null +++ b/railties/lib/rails/generators/rails/plugin/templates/lib/%namespaced_name%/railtie.rb.tt @@ -0,0 +1,5 @@ +<%= wrap_in_modules <<~rb + class Railtie < ::Rails::Railtie + end +rb +%> diff --git a/railties/lib/rails/generators/rails/plugin/templates/lib/%namespaced_name%/version.rb b/railties/lib/rails/generators/rails/plugin/templates/lib/%namespaced_name%/version.rb.tt index b08f4ef9ae..b08f4ef9ae 100644 --- a/railties/lib/rails/generators/rails/plugin/templates/lib/%namespaced_name%/version.rb +++ b/railties/lib/rails/generators/rails/plugin/templates/lib/%namespaced_name%/version.rb.tt diff --git a/railties/lib/rails/generators/rails/plugin/templates/lib/tasks/%namespaced_name%_tasks.rake b/railties/lib/rails/generators/rails/plugin/templates/lib/tasks/%namespaced_name%_tasks.rake.tt index 88a2c4120f..88a2c4120f 100644 --- a/railties/lib/rails/generators/rails/plugin/templates/lib/tasks/%namespaced_name%_tasks.rake +++ b/railties/lib/rails/generators/rails/plugin/templates/lib/tasks/%namespaced_name%_tasks.rake.tt diff --git a/railties/lib/rails/generators/rails/plugin/templates/rails/application.rb b/railties/lib/rails/generators/rails/plugin/templates/rails/application.rb.tt index d03b1be878..06ffe2f1ed 100644 --- a/railties/lib/rails/generators/rails/plugin/templates/rails/application.rb +++ b/railties/lib/rails/generators/rails/plugin/templates/rails/application.rb.tt @@ -3,15 +3,18 @@ require_relative 'boot' <% if include_all_railties? -%> require 'rails/all' <% else -%> +require "rails" # Pick the frameworks you want: +require "active_model/railtie" +require "active_job/railtie" <%= comment_if :skip_active_record %>require "active_record/railtie" +<%= comment_if :skip_active_storage %>require "active_storage/engine" require "action_controller/railtie" -require "action_view/railtie" <%= comment_if :skip_action_mailer %>require "action_mailer/railtie" -require "active_job/railtie" +require "action_view/railtie" <%= comment_if :skip_action_cable %>require "action_cable/engine" -<%= comment_if :skip_test %>require "rails/test_unit/railtie" <%= comment_if :skip_sprockets %>require "sprockets/railtie" +<%= comment_if :skip_test %>require "rails/test_unit/railtie" <% end -%> Bundler.require(*Rails.groups) diff --git a/railties/lib/rails/generators/rails/plugin/templates/rails/boot.rb b/railties/lib/rails/generators/rails/plugin/templates/rails/boot.rb.tt index c9aef85d40..c9aef85d40 100644 --- a/railties/lib/rails/generators/rails/plugin/templates/rails/boot.rb +++ b/railties/lib/rails/generators/rails/plugin/templates/rails/boot.rb.tt diff --git a/railties/lib/rails/generators/rails/plugin/templates/rails/dummy_manifest.js b/railties/lib/rails/generators/rails/plugin/templates/rails/dummy_manifest.js.tt index 8d21b2b6fb..03937cf8ff 100644 --- a/railties/lib/rails/generators/rails/plugin/templates/rails/dummy_manifest.js +++ b/railties/lib/rails/generators/rails/plugin/templates/rails/dummy_manifest.js.tt @@ -1,4 +1,3 @@ - <% unless api? -%> //= link_tree ../images <% end -%> diff --git a/railties/lib/rails/generators/rails/plugin/templates/rails/engine_manifest.js b/railties/lib/rails/generators/rails/plugin/templates/rails/engine_manifest.js.tt index 2f23844f5e..2f23844f5e 100644 --- a/railties/lib/rails/generators/rails/plugin/templates/rails/engine_manifest.js +++ b/railties/lib/rails/generators/rails/plugin/templates/rails/engine_manifest.js.tt diff --git a/railties/lib/rails/generators/rails/plugin/templates/rails/javascripts.js b/railties/lib/rails/generators/rails/plugin/templates/rails/javascripts.js.tt index e54c6461cc..51049826bf 100644 --- a/railties/lib/rails/generators/rails/plugin/templates/rails/javascripts.js +++ b/railties/lib/rails/generators/rails/plugin/templates/rails/javascripts.js.tt @@ -10,4 +10,8 @@ // Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details // about supported directives. // +//= require rails-ujs +<% unless skip_active_storage? -%> +//= require activestorage +<% end -%> //= require_tree . diff --git a/railties/lib/rails/generators/rails/plugin/templates/rails/routes.rb b/railties/lib/rails/generators/rails/plugin/templates/rails/routes.rb.tt index 694510edc0..694510edc0 100644 --- a/railties/lib/rails/generators/rails/plugin/templates/rails/routes.rb +++ b/railties/lib/rails/generators/rails/plugin/templates/rails/routes.rb.tt diff --git a/railties/lib/rails/generators/rails/plugin/templates/test/%namespaced_name%_test.rb b/railties/lib/rails/generators/rails/plugin/templates/test/%namespaced_name%_test.rb.tt index 1ee05d7871..1ee05d7871 100644 --- a/railties/lib/rails/generators/rails/plugin/templates/test/%namespaced_name%_test.rb +++ b/railties/lib/rails/generators/rails/plugin/templates/test/%namespaced_name%_test.rb.tt diff --git a/railties/lib/rails/generators/rails/plugin/templates/test/application_system_test_case.rb.tt b/railties/lib/rails/generators/rails/plugin/templates/test/application_system_test_case.rb.tt new file mode 100644 index 0000000000..d19212abd5 --- /dev/null +++ b/railties/lib/rails/generators/rails/plugin/templates/test/application_system_test_case.rb.tt @@ -0,0 +1,5 @@ +require "test_helper" + +class ApplicationSystemTestCase < ActionDispatch::SystemTestCase + driven_by :selenium, using: :chrome, screen_size: [1400, 1400] +end diff --git a/railties/lib/rails/generators/rails/plugin/templates/test/integration/navigation_test.rb b/railties/lib/rails/generators/rails/plugin/templates/test/integration/navigation_test.rb.tt index f5d1ec2046..29e59d8407 100644 --- a/railties/lib/rails/generators/rails/plugin/templates/test/integration/navigation_test.rb +++ b/railties/lib/rails/generators/rails/plugin/templates/test/integration/navigation_test.rb.tt @@ -5,4 +5,3 @@ class NavigationTest < ActionDispatch::IntegrationTest # assert true # end end - diff --git a/railties/lib/rails/generators/rails/plugin/templates/test/test_helper.rb b/railties/lib/rails/generators/rails/plugin/templates/test/test_helper.rb.tt index a5eebcb19f..4f7a8d3d6e 100644 --- a/railties/lib/rails/generators/rails/plugin/templates/test/test_helper.rb +++ b/railties/lib/rails/generators/rails/plugin/templates/test/test_helper.rb.tt @@ -1,27 +1,29 @@ # Configure Rails Environment ENV["RAILS_ENV"] = "test" -require File.expand_path("../../<%= options[:dummy_path] -%>/config/environment.rb", __FILE__) +require_relative "<%= File.join('..', options[:dummy_path], 'config/environment') -%>" <% unless options[:skip_active_record] -%> -ActiveRecord::Migrator.migrations_paths = [File.expand_path("../../<%= options[:dummy_path] -%>/db/migrate", __FILE__)] +ActiveRecord::Migrator.migrations_paths = [File.expand_path("../<%= options[:dummy_path] -%>/db/migrate", __dir__)] <% if options[:mountable] -%> -ActiveRecord::Migrator.migrations_paths << File.expand_path('../../db/migrate', __FILE__) +ActiveRecord::Migrator.migrations_paths << File.expand_path('../db/migrate', __dir__) <% end -%> <% end -%> require "rails/test_help" -# Filter out Minitest backtrace while allowing backtrace from other libraries -# to be shown. +# Filter out the backtrace from minitest while preserving the one from other libraries. Minitest.backtrace_filter = Minitest::BacktraceFilter.new <% unless engine? -%> +require "rails/test_unit/reporter" Rails::TestUnitReporter.executable = 'bin/test' <% end -%> +<% unless options[:skip_active_record] -%> # Load fixtures from the engine if ActiveSupport::TestCase.respond_to?(:fixture_path=) - ActiveSupport::TestCase.fixture_path = File.expand_path("../fixtures", __FILE__) + ActiveSupport::TestCase.fixture_path = File.expand_path("fixtures", __dir__) ActionDispatch::IntegrationTest.fixture_path = ActiveSupport::TestCase.fixture_path ActiveSupport::TestCase.file_fixture_path = ActiveSupport::TestCase.fixture_path + "/files" ActiveSupport::TestCase.fixtures :all end +<% end -%> diff --git a/railties/lib/rails/generators/rails/resource/USAGE b/railties/lib/rails/generators/rails/resource/USAGE index e359cd574f..66d0ee546a 100644 --- a/railties/lib/rails/generators/rails/resource/USAGE +++ b/railties/lib/rails/generators/rails/resource/USAGE @@ -1,6 +1,6 @@ Description: Stubs out a new resource including an empty model and controller suitable - for a restful, resource-oriented application. Pass the singular model name, + for a RESTful, resource-oriented application. Pass the singular model name, either CamelCased or under_scored, as the first argument, and an optional list of attribute pairs. diff --git a/railties/lib/rails/generators/rails/resource/resource_generator.rb b/railties/lib/rails/generators/rails/resource/resource_generator.rb index 3acf21df13..3ba25ef0fe 100644 --- a/railties/lib/rails/generators/rails/resource/resource_generator.rb +++ b/railties/lib/rails/generators/rails/resource/resource_generator.rb @@ -1,5 +1,7 @@ -require 'rails/generators/resource_helpers' -require 'rails/generators/rails/model/model_generator' +# frozen_string_literal: true + +require "rails/generators/resource_helpers" +require "rails/generators/rails/model/model_generator" module Rails module Generators diff --git a/railties/lib/rails/generators/rails/resource_route/resource_route_generator.rb b/railties/lib/rails/generators/rails/resource_route/resource_route_generator.rb index 42705107ae..9a92991efe 100644 --- a/railties/lib/rails/generators/rails/resource_route/resource_route_generator.rb +++ b/railties/lib/rails/generators/rails/resource_route/resource_route_generator.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Rails module Generators class ResourceRouteGenerator < NamedBase # :nodoc: @@ -15,37 +17,32 @@ module Rails def add_resource_route return if options[:actions].present? - # iterates over all namespaces and opens up blocks - regular_class_path.each_with_index do |namespace, index| - write("namespace :#{namespace} do", index + 1) + depth = 0 + lines = [] + + # Create 'namespace' ladder + # namespace :foo do + # namespace :bar do + regular_class_path.each do |ns| + lines << indent("namespace :#{ns} do\n", depth * 2) + depth += 1 end # inserts the primary resource - write("resources :#{file_name.pluralize}", route_length + 1) + # Create route + # resources 'products' + lines << indent(%{resources :#{file_name.pluralize}\n}, depth * 2) - # ends blocks - regular_class_path.each_index do |index| - write("end", route_length - index) + # Create `end` ladder + # end + # end + until depth.zero? + depth -= 1 + lines << indent("end\n", depth * 2) end - # route prepends two spaces onto the front of the string that is passed, this corrects that. - # Also it adds a \n to the end of each line, as route already adds that - # we need to correct that too. - route route_string[2..-2] + route lines.join end - - private - def route_string - @route_string ||= "" - end - - def write(str, indent) - route_string << "#{" " * indent}#{str}\n" - end - - def route_length - regular_class_path.length - end end end end diff --git a/railties/lib/rails/generators/rails/scaffold/scaffold_generator.rb b/railties/lib/rails/generators/rails/scaffold/scaffold_generator.rb index 17c32bfdb3..8beb7416c0 100644 --- a/railties/lib/rails/generators/rails/scaffold/scaffold_generator.rb +++ b/railties/lib/rails/generators/rails/scaffold/scaffold_generator.rb @@ -1,4 +1,6 @@ -require 'rails/generators/rails/resource/resource_generator' +# frozen_string_literal: true + +require "rails/generators/rails/resource/resource_generator" module Rails module Generators @@ -6,6 +8,7 @@ module Rails remove_hook_for :resource_controller remove_class_option :actions + class_option :api, type: :boolean class_option :stylesheets, type: :boolean, desc: "Generate Stylesheets" class_option :stylesheet_engine, desc: "Engine for Stylesheets" class_option :assets, type: :boolean diff --git a/railties/lib/rails/generators/rails/scaffold/templates/scaffold.css b/railties/lib/rails/generators/rails/scaffold/templates/scaffold.css index 79f8b7f96f..cd4f3de38d 100644 --- a/railties/lib/rails/generators/rails/scaffold/templates/scaffold.css +++ b/railties/lib/rails/generators/rails/scaffold/templates/scaffold.css @@ -1,13 +1,13 @@ body { background-color: #fff; color: #333; + margin: 33px; } body, p, ol, ul, td { font-family: verdana, arial, helvetica, sans-serif; font-size: 13px; line-height: 18px; - margin: 33px; } pre { @@ -34,9 +34,7 @@ th { } td { - padding-bottom: 7px; - padding-left: 5px; - padding-right: 5px; + padding: 0 5px 7px; } div.field, @@ -57,8 +55,7 @@ div.actions { #error_explanation { width: 450px; border: 2px solid red; - padding: 7px; - padding-bottom: 0; + padding: 7px 7px 0; margin-bottom: 20px; background-color: #f0f0f0; } @@ -68,8 +65,7 @@ div.actions { font-weight: bold; padding: 5px 5px 5px 15px; font-size: 12px; - margin: -7px; - margin-bottom: 0; + margin: -7px -7px 0; background-color: #c00; color: #fff; } diff --git a/railties/lib/rails/generators/rails/scaffold_controller/USAGE b/railties/lib/rails/generators/rails/scaffold_controller/USAGE index 8ba4c5ccbc..28f229510b 100644 --- a/railties/lib/rails/generators/rails/scaffold_controller/USAGE +++ b/railties/lib/rails/generators/rails/scaffold_controller/USAGE @@ -12,7 +12,7 @@ Description: Example: `rails generate scaffold_controller CreditCard` - Credit card controller with URLs like /credit_card/debit. + Credit card controller with URLs like /credit_cards. Controller: app/controllers/credit_cards_controller.rb Test: test/controllers/credit_cards_controller_test.rb Views: app/views/credit_cards/index.html.erb [...] diff --git a/railties/lib/rails/generators/rails/scaffold_controller/scaffold_controller_generator.rb b/railties/lib/rails/generators/rails/scaffold_controller/scaffold_controller_generator.rb index d0b8cad896..8b46eb88ae 100644 --- a/railties/lib/rails/generators/rails/scaffold_controller/scaffold_controller_generator.rb +++ b/railties/lib/rails/generators/rails/scaffold_controller/scaffold_controller_generator.rb @@ -1,4 +1,6 @@ -require 'rails/generators/resource_helpers' +# frozen_string_literal: true + +require "rails/generators/resource_helpers" module Rails module Generators @@ -17,15 +19,27 @@ module Rails def create_controller_files template_file = options.api? ? "api_controller.rb" : "controller.rb" - template template_file, File.join('app/controllers', controller_class_path, "#{controller_file_name}_controller.rb") + template template_file, File.join("app/controllers", controller_class_path, "#{controller_file_name}_controller.rb") + end + + hook_for :template_engine, as: :scaffold do |template_engine| + invoke template_engine unless options.api? end - hook_for :template_engine, :test_framework, as: :scaffold + hook_for :test_framework, as: :scaffold # Invoke the helper using the controller name (pluralized) hook_for :helper, as: :scaffold do |invoked| invoke invoked, [ controller_name ] end + + private + + def permitted_params + params = attributes_names.map { |name| ":#{name}" }.join(", ") + params += attributes.select(&:attachments?).map { |a| ", #{a.name}: []" }.join + params + end end end end diff --git a/railties/lib/rails/generators/rails/scaffold_controller/templates/api_controller.rb b/railties/lib/rails/generators/rails/scaffold_controller/templates/api_controller.rb.tt index 400afec6dc..bb26370276 100644 --- a/railties/lib/rails/generators/rails/scaffold_controller/templates/api_controller.rb +++ b/railties/lib/rails/generators/rails/scaffold_controller/templates/api_controller.rb.tt @@ -54,7 +54,7 @@ class <%= controller_class_name %>Controller < ApplicationController <%- if attributes_names.empty? -%> params.fetch(:<%= singular_table_name %>, {}) <%- else -%> - params.require(:<%= singular_table_name %>).permit(<%= attributes_names.map { |name| ":#{name}" }.join(', ') %>) + params.require(:<%= singular_table_name %>).permit(<%= permitted_params %>) <%- end -%> end end diff --git a/railties/lib/rails/generators/rails/scaffold_controller/templates/controller.rb b/railties/lib/rails/generators/rails/scaffold_controller/templates/controller.rb.tt index 42b9e34274..82b43987b4 100644 --- a/railties/lib/rails/generators/rails/scaffold_controller/templates/controller.rb +++ b/railties/lib/rails/generators/rails/scaffold_controller/templates/controller.rb.tt @@ -29,7 +29,7 @@ class <%= controller_class_name %>Controller < ApplicationController @<%= singular_table_name %> = <%= orm_class.build(class_name, "#{singular_table_name}_params") %> if @<%= orm_instance.save %> - redirect_to @<%= singular_table_name %>, notice: <%= "'#{human_name} was successfully created.'" %> + redirect_to <%= redirect_resource_name %>, notice: <%= "'#{human_name} was successfully created.'" %> else render :new end @@ -38,7 +38,7 @@ class <%= controller_class_name %>Controller < ApplicationController # PATCH/PUT <%= route_url %>/1 def update if @<%= orm_instance.update("#{singular_table_name}_params") %> - redirect_to @<%= singular_table_name %>, notice: <%= "'#{human_name} was successfully updated.'" %> + redirect_to <%= redirect_resource_name %>, notice: <%= "'#{human_name} was successfully updated.'" %> else render :edit end @@ -61,7 +61,7 @@ class <%= controller_class_name %>Controller < ApplicationController <%- if attributes_names.empty? -%> params.fetch(:<%= singular_table_name %>, {}) <%- else -%> - params.require(:<%= singular_table_name %>).permit(<%= attributes_names.map { |name| ":#{name}" }.join(', ') %>) + params.require(:<%= singular_table_name %>).permit(<%= permitted_params %>) <%- end -%> end end diff --git a/railties/lib/rails/generators/rails/system_test/USAGE b/railties/lib/rails/generators/rails/system_test/USAGE new file mode 100644 index 0000000000..f11a99e008 --- /dev/null +++ b/railties/lib/rails/generators/rails/system_test/USAGE @@ -0,0 +1,10 @@ +Description: + Stubs out a new system test. Pass the name of the test, either + CamelCased or under_scored, as an argument. + + This generator invokes the current system tool, which defaults to + TestUnit. + +Example: + `rails generate system_test GeneralStories` creates a GeneralStories + system test in test/system/general_stories_test.rb diff --git a/railties/lib/rails/generators/rails/system_test/system_test_generator.rb b/railties/lib/rails/generators/rails/system_test/system_test_generator.rb new file mode 100644 index 0000000000..7169e1bd3b --- /dev/null +++ b/railties/lib/rails/generators/rails/system_test/system_test_generator.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +module Rails + module Generators + class SystemTestGenerator < NamedBase # :nodoc: + hook_for :system_tests, as: :system + end + end +end diff --git a/railties/lib/rails/generators/rails/task/task_generator.rb b/railties/lib/rails/generators/rails/task/task_generator.rb index 754824ca0c..b7290a7447 100644 --- a/railties/lib/rails/generators/rails/task/task_generator.rb +++ b/railties/lib/rails/generators/rails/task/task_generator.rb @@ -1,12 +1,13 @@ +# frozen_string_literal: true + module Rails module Generators class TaskGenerator < NamedBase # :nodoc: argument :actions, type: :array, default: [], banner: "action action" def create_task_files - template 'task.rb', File.join('lib/tasks', "#{file_name}.rake") + template "task.rb", File.join("lib/tasks", "#{file_name}.rake") end - end end end diff --git a/railties/lib/rails/generators/rails/task/templates/task.rb b/railties/lib/rails/generators/rails/task/templates/task.rb.tt index 1e3ed5f158..1e3ed5f158 100644 --- a/railties/lib/rails/generators/rails/task/templates/task.rb +++ b/railties/lib/rails/generators/rails/task/templates/task.rb.tt diff --git a/railties/lib/rails/generators/resource_helpers.rb b/railties/lib/rails/generators/resource_helpers.rb index 9c2037783e..5675faff70 100644 --- a/railties/lib/rails/generators/resource_helpers.rb +++ b/railties/lib/rails/generators/resource_helpers.rb @@ -1,12 +1,13 @@ -require 'rails/generators/active_model' -require 'rails/generators/model_helpers' +# frozen_string_literal: true + +require "rails/generators/active_model" +require "rails/generators/model_helpers" module Rails module Generators # Deal with controller names on scaffold and add some helpers to deal with # ActiveModel. module ResourceHelpers # :nodoc: - def self.included(base) #:nodoc: base.include(Rails::Generators::ModelHelpers) base.class_option :model_name, type: :string, desc: "ModelName to be used" @@ -18,14 +19,13 @@ module Rails controller_name = name if options[:model_name] self.name = options[:model_name] - assign_names!(self.name) + assign_names!(name) end assign_controller_names!(controller_name.pluralize) end - protected - + private attr_reader :controller_name, :controller_file_name def controller_class_path @@ -38,25 +38,25 @@ module Rails def assign_controller_names!(name) @controller_name = name - @controller_class_path = name.include?('/') ? name.split('/') : name.split('::') + @controller_class_path = name.include?("/") ? name.split("/") : name.split("::") @controller_class_path.map!(&:underscore) @controller_file_name = @controller_class_path.pop end def controller_file_path - @controller_file_path ||= (controller_class_path + [controller_file_name]).join('/') + @controller_file_path ||= (controller_class_path + [controller_file_name]).join("/") end def controller_class_name - (controller_class_path + [controller_file_name]).map!(&:camelize).join('::') + (controller_class_path + [controller_file_name]).map!(&:camelize).join("::") end def controller_i18n_scope - @controller_i18n_scope ||= controller_file_path.tr('/', '.') + @controller_i18n_scope ||= controller_file_path.tr("/", ".") end # Loads the ORM::Generators::ActiveModel class. This class is responsible - # to tell scaffold entities how to generate an specific method for the + # to tell scaffold entities how to generate a specific method for the # ORM. Check Rails::Generators::ActiveModel for more information. def orm_class @orm_class ||= begin @@ -74,7 +74,7 @@ module Rails end # Initialize ORM::Generators::ActiveModel to access instance methods. - def orm_instance(name=singular_table_name) + def orm_instance(name = singular_table_name) @orm_instance ||= orm_class.new(name) end end diff --git a/railties/lib/rails/generators/test_case.rb b/railties/lib/rails/generators/test_case.rb index 58592b4f8e..5c71bf0be9 100644 --- a/railties/lib/rails/generators/test_case.rb +++ b/railties/lib/rails/generators/test_case.rb @@ -1,8 +1,10 @@ -require 'rails/generators' -require 'rails/generators/testing/behaviour' -require 'rails/generators/testing/setup_and_teardown' -require 'rails/generators/testing/assertions' -require 'fileutils' +# frozen_string_literal: true + +require "rails/generators" +require "rails/generators/testing/behaviour" +require "rails/generators/testing/setup_and_teardown" +require "rails/generators/testing/assertions" +require "fileutils" module Rails module Generators @@ -14,7 +16,7 @@ module Rails # # class AppGeneratorTest < Rails::Generators::TestCase # tests AppGenerator - # destination File.expand_path("../tmp", File.dirname(__FILE__)) + # destination File.expand_path("../tmp", __dir__) # end # # If you want to ensure your destination root is clean before running each test, @@ -22,7 +24,7 @@ module Rails # # class AppGeneratorTest < Rails::Generators::TestCase # tests AppGenerator - # destination File.expand_path("../tmp", File.dirname(__FILE__)) + # destination File.expand_path("../tmp", __dir__) # setup :prepare_destination # end class TestCase < ActiveSupport::TestCase @@ -30,7 +32,6 @@ module Rails include Rails::Generators::Testing::SetupAndTeardown include Rails::Generators::Testing::Assertions include FileUtils - end end end diff --git a/railties/lib/rails/generators/test_unit.rb b/railties/lib/rails/generators/test_unit.rb index fe45c9e15d..1005ac557c 100644 --- a/railties/lib/rails/generators/test_unit.rb +++ b/railties/lib/rails/generators/test_unit.rb @@ -1,4 +1,6 @@ -require 'rails/generators/named_base' +# frozen_string_literal: true + +require "rails/generators/named_base" module TestUnit # :nodoc: module Generators # :nodoc: diff --git a/railties/lib/rails/generators/test_unit/controller/controller_generator.rb b/railties/lib/rails/generators/test_unit/controller/controller_generator.rb index b5aa581769..1a9ac6bf2a 100644 --- a/railties/lib/rails/generators/test_unit/controller/controller_generator.rb +++ b/railties/lib/rails/generators/test_unit/controller/controller_generator.rb @@ -1,4 +1,6 @@ -require 'rails/generators/test_unit' +# frozen_string_literal: true + +require "rails/generators/test_unit" module TestUnit # :nodoc: module Generators # :nodoc: @@ -7,8 +9,8 @@ module TestUnit # :nodoc: check_class_collision suffix: "ControllerTest" def create_test_files - template 'functional_test.rb', - File.join('test/controllers', class_path, "#{file_name}_controller_test.rb") + template "functional_test.rb", + File.join("test/controllers", class_path, "#{file_name}_controller_test.rb") end end end diff --git a/railties/lib/rails/generators/test_unit/controller/templates/functional_test.rb b/railties/lib/rails/generators/test_unit/controller/templates/functional_test.rb.tt index ff41fef9e9..ff41fef9e9 100644 --- a/railties/lib/rails/generators/test_unit/controller/templates/functional_test.rb +++ b/railties/lib/rails/generators/test_unit/controller/templates/functional_test.rb.tt diff --git a/railties/lib/rails/generators/test_unit/generator/generator_generator.rb b/railties/lib/rails/generators/test_unit/generator/generator_generator.rb index d7307398ce..19be4f2f51 100644 --- a/railties/lib/rails/generators/test_unit/generator/generator_generator.rb +++ b/railties/lib/rails/generators/test_unit/generator/generator_generator.rb @@ -1,4 +1,6 @@ -require 'rails/generators/test_unit' +# frozen_string_literal: true + +require "rails/generators/test_unit" module TestUnit # :nodoc: module Generators # :nodoc: @@ -9,10 +11,10 @@ module TestUnit # :nodoc: desc: "Namespace generator under lib/generators/name" def create_generator_files - template 'generator_test.rb', File.join('test/lib/generators', class_path, "#{file_name}_generator_test.rb") + template "generator_test.rb", File.join("test/lib/generators", class_path, "#{file_name}_generator_test.rb") end - protected + private def generator_path if options[:namespace] diff --git a/railties/lib/rails/generators/test_unit/generator/templates/generator_test.rb b/railties/lib/rails/generators/test_unit/generator/templates/generator_test.rb.tt index a7f1fc4fba..a7f1fc4fba 100644 --- a/railties/lib/rails/generators/test_unit/generator/templates/generator_test.rb +++ b/railties/lib/rails/generators/test_unit/generator/templates/generator_test.rb.tt diff --git a/railties/lib/rails/generators/test_unit/helper/helper_generator.rb b/railties/lib/rails/generators/test_unit/helper/helper_generator.rb index bde4e88915..77308dcf7d 100644 --- a/railties/lib/rails/generators/test_unit/helper/helper_generator.rb +++ b/railties/lib/rails/generators/test_unit/helper/helper_generator.rb @@ -1,4 +1,6 @@ -require 'rails/generators/test_unit' +# frozen_string_literal: true + +require "rails/generators/test_unit" module TestUnit # :nodoc: module Generators # :nodoc: diff --git a/railties/lib/rails/generators/test_unit/integration/integration_generator.rb b/railties/lib/rails/generators/test_unit/integration/integration_generator.rb index e004835bd5..ba27ed329b 100644 --- a/railties/lib/rails/generators/test_unit/integration/integration_generator.rb +++ b/railties/lib/rails/generators/test_unit/integration/integration_generator.rb @@ -1,4 +1,6 @@ -require 'rails/generators/test_unit' +# frozen_string_literal: true + +require "rails/generators/test_unit" module TestUnit # :nodoc: module Generators # :nodoc: @@ -6,8 +8,14 @@ module TestUnit # :nodoc: check_class_collision suffix: "Test" def create_test_files - template 'integration_test.rb', File.join('test/integration', class_path, "#{file_name}_test.rb") + template "integration_test.rb", File.join("test/integration", class_path, "#{file_name}_test.rb") end + + private + + def file_name + @_file_name ||= super.sub(/_test\z/i, "") + end end end end diff --git a/railties/lib/rails/generators/test_unit/integration/templates/integration_test.rb b/railties/lib/rails/generators/test_unit/integration/templates/integration_test.rb.tt index dea7e22196..118e0f1271 100644 --- a/railties/lib/rails/generators/test_unit/integration/templates/integration_test.rb +++ b/railties/lib/rails/generators/test_unit/integration/templates/integration_test.rb.tt @@ -1,7 +1,9 @@ require 'test_helper' +<% module_namespacing do -%> class <%= class_name %>Test < ActionDispatch::IntegrationTest # test "the truth" do # assert true # end end +<% end -%> diff --git a/railties/lib/rails/generators/test_unit/job/job_generator.rb b/railties/lib/rails/generators/test_unit/job/job_generator.rb index 566b61ca66..1dae3cb6a5 100644 --- a/railties/lib/rails/generators/test_unit/job/job_generator.rb +++ b/railties/lib/rails/generators/test_unit/job/job_generator.rb @@ -1,13 +1,20 @@ -require 'rails/generators/test_unit' +# frozen_string_literal: true + +require "rails/generators/test_unit" module TestUnit # :nodoc: module Generators # :nodoc: class JobGenerator < Base # :nodoc: - check_class_collision suffix: 'JobTest' + check_class_collision suffix: "JobTest" def create_test_file - template 'unit_test.rb.erb', File.join('test/jobs', class_path, "#{file_name}_job_test.rb") + template "unit_test.rb", File.join("test/jobs", class_path, "#{file_name}_job_test.rb") end + + private + def file_name + @_file_name ||= super.sub(/_job\z/i, "") + end end end end diff --git a/railties/lib/rails/generators/test_unit/job/templates/unit_test.rb.erb b/railties/lib/rails/generators/test_unit/job/templates/unit_test.rb.tt index f5351d0ec6..f5351d0ec6 100644 --- a/railties/lib/rails/generators/test_unit/job/templates/unit_test.rb.erb +++ b/railties/lib/rails/generators/test_unit/job/templates/unit_test.rb.tt diff --git a/railties/lib/rails/generators/test_unit/mailer/mailer_generator.rb b/railties/lib/rails/generators/test_unit/mailer/mailer_generator.rb index 76a0b79654..ab8331f31c 100644 --- a/railties/lib/rails/generators/test_unit/mailer/mailer_generator.rb +++ b/railties/lib/rails/generators/test_unit/mailer/mailer_generator.rb @@ -1,4 +1,6 @@ -require 'rails/generators/test_unit' +# frozen_string_literal: true + +require "rails/generators/test_unit" module TestUnit # :nodoc: module Generators # :nodoc: @@ -10,16 +12,16 @@ module TestUnit # :nodoc: end def create_test_files - template "functional_test.rb", File.join('test/mailers', class_path, "#{file_name}_mailer_test.rb") + template "functional_test.rb", File.join("test/mailers", class_path, "#{file_name}_mailer_test.rb") end def create_preview_files - template "preview.rb", File.join('test/mailers/previews', class_path, "#{file_name}_mailer_preview.rb") + template "preview.rb", File.join("test/mailers/previews", class_path, "#{file_name}_mailer_preview.rb") end - protected + private def file_name - @_file_name ||= super.gsub(/_mailer/i, '') + @_file_name ||= super.sub(/_mailer\z/i, "") end end end diff --git a/railties/lib/rails/generators/test_unit/mailer/templates/functional_test.rb b/railties/lib/rails/generators/test_unit/mailer/templates/functional_test.rb.tt index a2f2d30de5..a2f2d30de5 100644 --- a/railties/lib/rails/generators/test_unit/mailer/templates/functional_test.rb +++ b/railties/lib/rails/generators/test_unit/mailer/templates/functional_test.rb.tt diff --git a/railties/lib/rails/generators/test_unit/mailer/templates/preview.rb b/railties/lib/rails/generators/test_unit/mailer/templates/preview.rb.tt index b063cbc47b..b063cbc47b 100644 --- a/railties/lib/rails/generators/test_unit/mailer/templates/preview.rb +++ b/railties/lib/rails/generators/test_unit/mailer/templates/preview.rb.tt diff --git a/railties/lib/rails/generators/test_unit/model/model_generator.rb b/railties/lib/rails/generators/test_unit/model/model_generator.rb index 086588750e..02d7502592 100644 --- a/railties/lib/rails/generators/test_unit/model/model_generator.rb +++ b/railties/lib/rails/generators/test_unit/model/model_generator.rb @@ -1,9 +1,10 @@ -require 'rails/generators/test_unit' +# frozen_string_literal: true + +require "rails/generators/test_unit" module TestUnit # :nodoc: module Generators # :nodoc: class ModelGenerator < Base # :nodoc: - RESERVED_YAML_KEYWORDS = %w(y yes n no true false on off null) argument :attributes, type: :array, default: [], banner: "field:type field:type" @@ -12,14 +13,14 @@ module TestUnit # :nodoc: check_class_collision suffix: "Test" def create_test_file - template 'unit_test.rb', File.join('test/models', class_path, "#{file_name}_test.rb") + template "unit_test.rb", File.join("test/models", class_path, "#{file_name}_test.rb") end hook_for :fixture_replacement def create_fixture_file if options[:fixture] && options[:fixture_replacement].nil? - template 'fixtures.yml', File.join('test/fixtures', class_path, "#{fixture_file_name}.yml") + template "fixtures.yml", File.join("test/fixtures", class_path, "#{fixture_file_name}.yml") end end diff --git a/railties/lib/rails/generators/test_unit/model/templates/fixtures.yml b/railties/lib/rails/generators/test_unit/model/templates/fixtures.yml.tt index 0681780c97..0fd9f305d7 100644 --- a/railties/lib/rails/generators/test_unit/model/templates/fixtures.yml +++ b/railties/lib/rails/generators/test_unit/model/templates/fixtures.yml.tt @@ -1,4 +1,4 @@ -# Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html +# Read about fixtures at https://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html <% unless attributes.empty? -%> <% %w(one two).each do |name| %> <%= name %>: @@ -7,7 +7,7 @@ password_digest: <%%= BCrypt::Password.create('secret') %> <%- elsif attribute.reference? -%> <%= yaml_key_value(attribute.column_name.sub(/_id$/, ''), attribute.default || name) %> - <%- else -%> + <%- elsif !attribute.virtual? -%> <%= yaml_key_value(attribute.column_name, attribute.default) %> <%- end -%> <%- if attribute.polymorphic? -%> diff --git a/railties/lib/rails/generators/test_unit/model/templates/unit_test.rb b/railties/lib/rails/generators/test_unit/model/templates/unit_test.rb.tt index c9bc7d5b90..c9bc7d5b90 100644 --- a/railties/lib/rails/generators/test_unit/model/templates/unit_test.rb +++ b/railties/lib/rails/generators/test_unit/model/templates/unit_test.rb.tt diff --git a/railties/lib/rails/generators/test_unit/plugin/plugin_generator.rb b/railties/lib/rails/generators/test_unit/plugin/plugin_generator.rb index b5d4f38444..0657bc2389 100644 --- a/railties/lib/rails/generators/test_unit/plugin/plugin_generator.rb +++ b/railties/lib/rails/generators/test_unit/plugin/plugin_generator.rb @@ -1,4 +1,6 @@ -require 'rails/generators/test_unit' +# frozen_string_literal: true + +require "rails/generators/test_unit" module TestUnit # :nodoc: module Generators # :nodoc: @@ -6,7 +8,7 @@ module TestUnit # :nodoc: check_class_collision suffix: "Test" def create_test_files - directory '.', 'test' + directory ".", "test" end end end diff --git a/railties/lib/rails/generators/test_unit/scaffold/scaffold_generator.rb b/railties/lib/rails/generators/test_unit/scaffold/scaffold_generator.rb index 0171da7cc7..6df50c3217 100644 --- a/railties/lib/rails/generators/test_unit/scaffold/scaffold_generator.rb +++ b/railties/lib/rails/generators/test_unit/scaffold/scaffold_generator.rb @@ -1,5 +1,7 @@ -require 'rails/generators/test_unit' -require 'rails/generators/resource_helpers' +# frozen_string_literal: true + +require "rails/generators/test_unit" +require "rails/generators/resource_helpers" module TestUnit # :nodoc: module Generators # :nodoc: @@ -11,18 +13,25 @@ module TestUnit # :nodoc: class_option :api, type: :boolean, desc: "Generates API functional tests" + class_option :system_tests, type: :string, + desc: "Skip system test files" + argument :attributes, type: :array, default: [], banner: "field:type field:type" def create_test_files template_file = options.api? ? "api_functional_test.rb" : "functional_test.rb" template template_file, File.join("test/controllers", controller_class_path, "#{controller_file_name}_controller_test.rb") + + if !options.api? && options[:system_tests] + template "system_test.rb", File.join("test/system", class_path, "#{file_name.pluralize}_test.rb") + end end def fixture_name @fixture_name ||= if mountable_engine? - "%s_%s" % [namespaced_path, table_name] + (namespace_dirs + [table_name]).join("_") else table_name end @@ -30,16 +39,25 @@ module TestUnit # :nodoc: private + def attributes_string + attributes_hash.map { |k, v| "#{k}: #{v}" }.join(", ") + end + def attributes_hash - return if attributes_names.empty? + return {} if attributes_names.empty? attributes_names.map do |name| if %w(password password_confirmation).include?(name) && attributes.any?(&:password_digest?) - "#{name}: 'secret'" + ["#{name}", "'secret'"] else - "#{name}: @#{singular_table_name}.#{name}" + ["#{name}", "@#{singular_table_name}.#{name}"] end - end.sort.join(', ') + end.sort.to_h + end + + def boolean?(name) + attribute = attributes.find { |attr| attr.name == name } + attribute&.type == :boolean end end end diff --git a/railties/lib/rails/generators/test_unit/scaffold/templates/api_functional_test.rb b/railties/lib/rails/generators/test_unit/scaffold/templates/api_functional_test.rb.tt index 0d18478043..f21861d8e6 100644 --- a/railties/lib/rails/generators/test_unit/scaffold/templates/api_functional_test.rb +++ b/railties/lib/rails/generators/test_unit/scaffold/templates/api_functional_test.rb.tt @@ -11,31 +11,31 @@ class <%= controller_class_name %>ControllerTest < ActionDispatch::IntegrationTe end test "should get index" do - get <%= index_helper %>_url + get <%= index_helper %>_url, as: :json assert_response :success end test "should create <%= singular_table_name %>" do assert_difference('<%= class_name %>.count') do - post <%= index_helper %>_url, params: { <%= "#{singular_table_name}: { #{attributes_hash} }" %> } + post <%= index_helper %>_url, params: { <%= "#{singular_table_name}: { #{attributes_string} }" %> }, as: :json end assert_response 201 end test "should show <%= singular_table_name %>" do - get <%= show_helper %> + get <%= show_helper %>, as: :json assert_response :success end test "should update <%= singular_table_name %>" do - patch <%= show_helper %>, params: { <%= "#{singular_table_name}: { #{attributes_hash} }" %> } + patch <%= show_helper %>, params: { <%= "#{singular_table_name}: { #{attributes_string} }" %> }, as: :json assert_response 200 end test "should destroy <%= singular_table_name %>" do assert_difference('<%= class_name %>.count', -1) do - delete <%= show_helper %> + delete <%= show_helper %>, as: :json end assert_response 204 diff --git a/railties/lib/rails/generators/test_unit/scaffold/templates/functional_test.rb b/railties/lib/rails/generators/test_unit/scaffold/templates/functional_test.rb.tt index 0e6bef12fc..195d60be20 100644 --- a/railties/lib/rails/generators/test_unit/scaffold/templates/functional_test.rb +++ b/railties/lib/rails/generators/test_unit/scaffold/templates/functional_test.rb.tt @@ -22,10 +22,10 @@ class <%= controller_class_name %>ControllerTest < ActionDispatch::IntegrationTe test "should create <%= singular_table_name %>" do assert_difference('<%= class_name %>.count') do - post <%= index_helper %>_url, params: { <%= "#{singular_table_name}: { #{attributes_hash} }" %> } + post <%= index_helper %>_url, params: { <%= "#{singular_table_name}: { #{attributes_string} }" %> } end - assert_redirected_to <%= singular_table_name %>_path(<%= class_name %>.last) + assert_redirected_to <%= singular_table_name %>_url(<%= class_name %>.last) end test "should show <%= singular_table_name %>" do @@ -39,8 +39,8 @@ class <%= controller_class_name %>ControllerTest < ActionDispatch::IntegrationTe end test "should update <%= singular_table_name %>" do - patch <%= show_helper %>, params: { <%= "#{singular_table_name}: { #{attributes_hash} }" %> } - assert_redirected_to <%= singular_table_name %>_path(<%= "@#{singular_table_name}" %>) + patch <%= show_helper %>, params: { <%= "#{singular_table_name}: { #{attributes_string} }" %> } + assert_redirected_to <%= singular_table_name %>_url(<%= "@#{singular_table_name}" %>) end test "should destroy <%= singular_table_name %>" do @@ -48,7 +48,7 @@ class <%= controller_class_name %>ControllerTest < ActionDispatch::IntegrationTe delete <%= show_helper %> end - assert_redirected_to <%= index_helper %>_path + assert_redirected_to <%= index_helper %>_url end end <% end -%> diff --git a/railties/lib/rails/generators/test_unit/scaffold/templates/system_test.rb.tt b/railties/lib/rails/generators/test_unit/scaffold/templates/system_test.rb.tt new file mode 100644 index 0000000000..4f5bbf1108 --- /dev/null +++ b/railties/lib/rails/generators/test_unit/scaffold/templates/system_test.rb.tt @@ -0,0 +1,57 @@ +require "application_system_test_case" + +<% module_namespacing do -%> +class <%= class_name.pluralize %>Test < ApplicationSystemTestCase + setup do + @<%= singular_table_name %> = <%= fixture_name %>(:one) + end + + test "visiting the index" do + visit <%= plural_table_name %>_url + assert_selector "h1", text: "<%= class_name.pluralize.titleize %>" + end + + test "creating a <%= human_name %>" do + visit <%= plural_table_name %>_url + click_on "New <%= class_name.titleize %>" + + <%- attributes_hash.each do |attr, value| -%> + <%- if boolean?(attr) -%> + check "<%= attr.humanize %>" if <%= value %> + <%- else -%> + fill_in "<%= attr.humanize %>", with: <%= value %> + <%- end -%> + <%- end -%> + click_on "Create <%= human_name %>" + + assert_text "<%= human_name %> was successfully created" + click_on "Back" + end + + test "updating a <%= human_name %>" do + visit <%= plural_table_name %>_url + click_on "Edit", match: :first + + <%- attributes_hash.each do |attr, value| -%> + <%- if boolean?(attr) -%> + check "<%= attr.humanize %>" if <%= value %> + <%- else -%> + fill_in "<%= attr.humanize %>", with: <%= value %> + <%- end -%> + <%- end -%> + click_on "Update <%= human_name %>" + + assert_text "<%= human_name %> was successfully updated" + click_on "Back" + end + + test "destroying a <%= human_name %>" do + visit <%= plural_table_name %>_url + page.accept_confirm do + click_on "Destroy", match: :first + end + + assert_text "<%= human_name %> was successfully destroyed" + end +end +<% end -%> diff --git a/railties/lib/rails/generators/test_unit/system/system_generator.rb b/railties/lib/rails/generators/test_unit/system/system_generator.rb new file mode 100644 index 0000000000..adecf74b70 --- /dev/null +++ b/railties/lib/rails/generators/test_unit/system/system_generator.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true + +require "rails/generators/test_unit" + +module TestUnit # :nodoc: + module Generators # :nodoc: + class SystemGenerator < Base # :nodoc: + check_class_collision suffix: "Test" + + def create_test_files + if !File.exist?(File.join("test/application_system_test_case.rb")) + template "application_system_test_case.rb", File.join("test", "application_system_test_case.rb") + end + + template "system_test.rb", File.join("test/system", class_path, "#{file_name.pluralize}_test.rb") + end + + private + def file_name + @_file_name ||= super.sub(/_test\z/i, "") + end + end + end +end diff --git a/railties/lib/rails/generators/test_unit/system/templates/application_system_test_case.rb.tt b/railties/lib/rails/generators/test_unit/system/templates/application_system_test_case.rb.tt new file mode 100644 index 0000000000..d19212abd5 --- /dev/null +++ b/railties/lib/rails/generators/test_unit/system/templates/application_system_test_case.rb.tt @@ -0,0 +1,5 @@ +require "test_helper" + +class ApplicationSystemTestCase < ActionDispatch::SystemTestCase + driven_by :selenium, using: :chrome, screen_size: [1400, 1400] +end diff --git a/railties/lib/rails/generators/test_unit/system/templates/system_test.rb.tt b/railties/lib/rails/generators/test_unit/system/templates/system_test.rb.tt new file mode 100644 index 0000000000..b5ce2ba5c8 --- /dev/null +++ b/railties/lib/rails/generators/test_unit/system/templates/system_test.rb.tt @@ -0,0 +1,9 @@ +require "application_system_test_case" + +class <%= class_name.pluralize %>Test < ApplicationSystemTestCase + # test "visiting the index" do + # visit <%= plural_table_name %>_url + # + # assert_selector "h1", text: "<%= class_name %>" + # end +end diff --git a/railties/lib/rails/generators/testing/assertions.rb b/railties/lib/rails/generators/testing/assertions.rb index 76758df86d..c4cff9090b 100644 --- a/railties/lib/rails/generators/testing/assertions.rb +++ b/railties/lib/rails/generators/testing/assertions.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Rails module Generators module Testing @@ -29,10 +31,10 @@ module Rails contents.each do |content| case content - when String - assert_equal content, read - when Regexp - assert_match content, read + when String + assert_equal content, read + when Regexp + assert_match content, read end end end @@ -113,7 +115,11 @@ module Rails # # assert_field_default_value :string, "MyString" def assert_field_default_value(attribute_type, value) - assert_equal(value, create_generated_attribute(attribute_type).default) + if value.nil? + assert_nil(create_generated_attribute(attribute_type).default) + else + assert_equal(value, create_generated_attribute(attribute_type).default) + end end end end diff --git a/railties/lib/rails/generators/testing/behaviour.rb b/railties/lib/rails/generators/testing/behaviour.rb index 94b5e52224..ec29ad12ba 100644 --- a/railties/lib/rails/generators/testing/behaviour.rb +++ b/railties/lib/rails/generators/testing/behaviour.rb @@ -1,10 +1,12 @@ -require 'active_support/core_ext/class/attribute' -require 'active_support/core_ext/module/delegation' -require 'active_support/core_ext/hash/reverse_merge' -require 'active_support/core_ext/kernel/reporting' -require 'active_support/testing/stream' -require 'active_support/concern' -require 'rails/generators' +# frozen_string_literal: true + +require "active_support/core_ext/class/attribute" +require "active_support/core_ext/module/delegation" +require "active_support/core_ext/hash/reverse_merge" +require "active_support/core_ext/kernel/reporting" +require "active_support/testing/stream" +require "active_support/concern" +require "rails/generators" module Rails module Generators @@ -14,12 +16,12 @@ module Rails include ActiveSupport::Testing::Stream included do - class_attribute :destination_root, :current_path, :generator_class, :default_arguments - # Generators frequently change the current path using +FileUtils.cd+. # So we need to store the path at file load and revert back to it after each test. - self.current_path = File.expand_path(Dir.pwd) - self.default_arguments = [] + class_attribute :current_path, default: File.expand_path(Dir.pwd) + class_attribute :default_arguments, default: [] + class_attribute :destination_root + class_attribute :generator_class end module ClassMethods @@ -40,7 +42,7 @@ module Rails # Sets the destination of generator files: # - # destination File.expand_path("../tmp", File.dirname(__FILE__)) + # destination File.expand_path("../tmp", __dir__) def destination(path) self.destination_root = path end @@ -51,7 +53,7 @@ module Rails # # class AppGeneratorTest < Rails::Generators::TestCase # tests AppGenerator - # destination File.expand_path("../tmp", File.dirname(__FILE__)) + # destination File.expand_path("../tmp", __dir__) # setup :prepare_destination # # test "database.yml is not created when skipping Active Record" do @@ -62,48 +64,50 @@ module Rails # # You can provide a configuration hash as second argument. This method returns the output # printed by the generator. - def run_generator(args=self.default_arguments, config={}) + def run_generator(args = default_arguments, config = {}) capture(:stdout) do - args += ['--skip-bundle'] unless args.include? '--dev' - self.generator_class.start(args, config.reverse_merge(destination_root: destination_root)) + args += ["--skip-bundle"] unless args.include? "--dev" + args |= ["--skip-bootsnap"] unless args.include? "--no-skip-bootsnap" + args |= ["--skip-webpack-install"] unless args.include? "--no-skip-webpack-install" + + generator_class.start(args, config.reverse_merge(destination_root: destination_root)) end end # Instantiate the generator. - def generator(args=self.default_arguments, options={}, config={}) - @generator ||= self.generator_class.new(args, options, config.reverse_merge(destination_root: destination_root)) + def generator(args = default_arguments, options = {}, config = {}) + @generator ||= generator_class.new(args, options, config.reverse_merge(destination_root: destination_root)) end # Create a Rails::Generators::GeneratedAttribute by supplying the # attribute type and, optionally, the attribute name: # # create_generated_attribute(:string, 'name') - def create_generated_attribute(attribute_type, name = 'test', index = nil) - Rails::Generators::GeneratedAttribute.parse([name, attribute_type, index].compact.join(':')) + def create_generated_attribute(attribute_type, name = "test", index = nil) + Rails::Generators::GeneratedAttribute.parse([name, attribute_type, index].compact.join(":")) end - protected + private - def destination_root_is_set? # :nodoc: + def destination_root_is_set? raise "You need to configure your Rails::Generators::TestCase destination root." unless destination_root end - def ensure_current_path # :nodoc: + def ensure_current_path cd current_path end # Clears all files and directories in destination. - def prepare_destination + def prepare_destination # :doc: rm_rf(destination_root) mkdir_p(destination_root) end - def migration_file_name(relative) # :nodoc: + def migration_file_name(relative) absolute = File.expand_path(relative, destination_root) - dirname, file_name = File.dirname(absolute), File.basename(absolute).sub(/\.rb$/, '') + dirname, file_name = File.dirname(absolute), File.basename(absolute).sub(/\.rb$/, "") Dir.glob("#{dirname}/[0-9]*_*.rb").grep(/\d+_#{file_name}.rb$/).first end - end end end diff --git a/railties/lib/rails/generators/testing/setup_and_teardown.rb b/railties/lib/rails/generators/testing/setup_and_teardown.rb index 73102a283f..4374aa5b8c 100644 --- a/railties/lib/rails/generators/testing/setup_and_teardown.rb +++ b/railties/lib/rails/generators/testing/setup_and_teardown.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Rails module Generators module Testing |