diff options
Diffstat (limited to 'railties/lib')
39 files changed, 393 insertions, 97 deletions
diff --git a/railties/lib/rails.rb b/railties/lib/rails.rb index ea82327365..be7570a5ba 100644 --- a/railties/lib/rails.rb +++ b/railties/lib/rails.rb @@ -25,6 +25,7 @@ module Rails autoload :Info autoload :InfoController + autoload :MailersController autoload :WelcomeController class << self diff --git a/railties/lib/rails/application.rb b/railties/lib/rails/application.rb index e45bfaf6fc..05acd78d98 100644 --- a/railties/lib/rails/application.rb +++ b/railties/lib/rails/application.rb @@ -1,4 +1,5 @@ require 'fileutils' +require 'active_support/core_ext/hash/keys' require 'active_support/core_ext/object/blank' require 'active_support/key_generator' require 'active_support/message_verifier' @@ -104,7 +105,7 @@ module Rails delegate :default_url_options, :default_url_options=, to: :routes INITIAL_VARIABLES = [:config, :railties, :routes_reloader, :reloaders, - :routes, :helpers, :app_env_config] # :nodoc: + :routes, :helpers, :app_env_config, :secrets] # :nodoc: def initialize(initial_variable_values = {}, &block) super() @@ -151,8 +152,8 @@ module Rails # number of iterations selected based on consultation with the google security # team. Details at https://github.com/rails/rails/pull/6952#issuecomment-7661220 @caching_key_generator ||= begin - if config.secret_key_base - key_generator = ActiveSupport::KeyGenerator.new(config.secret_key_base, iterations: 1000) + if secrets.secret_key_base + key_generator = ActiveSupport::KeyGenerator.new(secrets.secret_key_base, iterations: 1000) ActiveSupport::CachingKeyGenerator.new(key_generator) else ActiveSupport::LegacyKeyGenerator.new(config.secret_token) @@ -169,18 +170,18 @@ module Rails # # ==== Parameters # - # * +salt+ - the salt that will be used to generate the secret key of the verifier. + # * +verifier_name+ - the name of the message verifier. # # ==== Examples # - # message = Rails.application.message_verifier('salt').generate('my sensible data') - # Rails.application.message_verifier('salt').verify(message) + # message = Rails.application.message_verifier('sensitive_data').generate('my sensible data') + # Rails.application.message_verifier('sensitive_data').verify(message) # # => 'my sensible data' # # See the +ActiveSupport::MessageVerifier+ documentation for more information. - def message_verifier(salt) - @message_verifiers[salt] ||= begin - secret = key_generator.generate_key(salt) + def message_verifier(verifier_name) + @message_verifiers[verifier_name] ||= begin + secret = key_generator.generate_key(verifier_name.to_s) ActiveSupport::MessageVerifier.new(secret) end end @@ -195,7 +196,7 @@ module Rails "action_dispatch.parameter_filter" => config.filter_parameters, "action_dispatch.redirect_filter" => config.filter_redirect, "action_dispatch.secret_token" => config.secret_token, - "action_dispatch.secret_key_base" => config.secret_key_base, + "action_dispatch.secret_key_base" => secrets.secret_key_base, "action_dispatch.show_exceptions" => config.action_dispatch.show_exceptions, "action_dispatch.show_detailed_exceptions" => config.consider_all_requests_local, "action_dispatch.logger" => Rails.logger, @@ -300,6 +301,27 @@ module Rails @config = configuration end + def secrets #:nodoc: + @secrets ||= begin + secrets = ActiveSupport::OrderedOptions.new + yaml = config.paths["config/secrets"].first + if File.exist?(yaml) + require "erb" + env_secrets = YAML.load(ERB.new(IO.read(yaml)).result)[Rails.env] + secrets.merge!(env_secrets.symbolize_keys) if env_secrets + end + + # Fallback to config.secret_key_base if secrets.secret_key_base isn't set + secrets.secret_key_base ||= config.secret_key_base + + secrets + end + end + + def secrets=(secrets) #:nodoc: + @secrets = secrets + end + def to_app #:nodoc: self end @@ -391,8 +413,8 @@ module Rails end def validate_secret_key_config! #:nodoc: - if config.secret_key_base.blank? && config.secret_token.blank? - raise "You must set config.secret_key_base in your app's config." + if secrets.secret_key_base.blank? && config.secret_token.blank? + raise "Missing `secret_key_base` for '#{Rails.env}' environment, set this value in `config/secrets.yml`" end end end diff --git a/railties/lib/rails/application/configuration.rb b/railties/lib/rails/application/configuration.rb index dd0b9c6d70..9975bb8596 100644 --- a/railties/lib/rails/application/configuration.rb +++ b/railties/lib/rails/application/configuration.rb @@ -76,6 +76,7 @@ module Rails @paths ||= begin paths = super paths.add "config/database", with: "config/database.yml" + paths.add "config/secrets", with: "config/secrets.yml" paths.add "config/environment", with: "config/environment.rb" paths.add "lib/templates" paths.add "log", with: "log/#{Rails.env}.log" diff --git a/railties/lib/rails/application/finisher.rb b/railties/lib/rails/application/finisher.rb index 7a1bb1e25c..5b8509b2e9 100644 --- a/railties/lib/rails/application/finisher.rb +++ b/railties/lib/rails/application/finisher.rb @@ -22,6 +22,8 @@ module Rails initializer :add_builtin_route do |app| if Rails.env.development? app.routes.append do + get '/rails/mailers' => "rails/mailers#index" + get '/rails/mailers/*path' => "rails/mailers#preview" get '/rails/info/properties' => "rails/info#properties" get '/rails/info/routes' => "rails/info#routes" get '/rails/info' => "rails/info#index" diff --git a/railties/lib/rails/application_controller.rb b/railties/lib/rails/application_controller.rb new file mode 100644 index 0000000000..9a29ec21cf --- /dev/null +++ b/railties/lib/rails/application_controller.rb @@ -0,0 +1,16 @@ +class Rails::ApplicationController < ActionController::Base # :nodoc: + self.view_paths = File.expand_path('../templates', __FILE__) + layout 'application' + + protected + + def require_local! + unless local_request? + render text: '<p>For security purposes, this information is only available to local requests.</p>', status: :forbidden + end + end + + def local_request? + Rails.application.config.consider_all_requests_local || request.local? + end +end diff --git a/railties/lib/rails/commands/dbconsole.rb b/railties/lib/rails/commands/dbconsole.rb index 3e4cc787c4..c265ed8f36 100644 --- a/railties/lib/rails/commands/dbconsole.rb +++ b/railties/lib/rails/commands/dbconsole.rb @@ -81,14 +81,10 @@ module Rails def config @config ||= begin - cfg = begin - YAML.load(ERB.new(IO.read("config/database.yml")).result) - rescue SyntaxError, StandardError - require APP_PATH - Rails.application.config.database_configuration - end - - cfg[environment] || abort("No database is configured for the environment '#{environment}'") + require APP_PATH + ActiveRecord::ConnectionAdapters::ConnectionSpecification::Resolver.new( + Rails.application.config.database_configuration || {} + ).resolve(ENV["DATABASE_URL"]) end end diff --git a/railties/lib/rails/commands/runner.rb b/railties/lib/rails/commands/runner.rb index dd2ee5639e..3a71f8d3f8 100644 --- a/railties/lib/rails/commands/runner.rb +++ b/railties/lib/rails/commands/runner.rb @@ -9,7 +9,7 @@ if ARGV.first.nil? end ARGV.clone.options do |opts| - opts.banner = "Usage: rails runner [options] ('Some.ruby(code)' or a filename)" + opts.banner = "Usage: rails runner [options] [<'Some.ruby(code)'> | <filename.rb>]" opts.separator "" @@ -22,14 +22,23 @@ ARGV.clone.options do |opts| opts.on("-h", "--help", "Show this help message.") { $stdout.puts opts; exit } + opts.separator "" + opts.separator "Examples: " + + opts.separator " rails runner 'puts Rails.env'" + opts.separator " This runs the code `puts Rails.env` after loading the app" + opts.separator "" + opts.separator " rails runner path/to/filename.rb" + opts.separator " This runs the Ruby file located at `path/to/filename.rb` after loading the app" + if RbConfig::CONFIG['host_os'] !~ /mswin|mingw/ opts.separator "" opts.separator "You can also use runner as a shebang line for your executables:" - opts.separator "-------------------------------------------------------------" - opts.separator "#!/usr/bin/env #{File.expand_path($0)} runner" + opts.separator " -------------------------------------------------------------" + opts.separator " #!/usr/bin/env #{File.expand_path($0)} runner" opts.separator "" - opts.separator "Product.all.each { |p| p.price *= 2 ; p.save! }" - opts.separator "-------------------------------------------------------------" + opts.separator " Product.all.each { |p| p.price *= 2 ; p.save! }" + opts.separator " -------------------------------------------------------------" end opts.order! { |o| code_or_file ||= o } rescue retry diff --git a/railties/lib/rails/generators/app_base.rb b/railties/lib/rails/generators/app_base.rb index 5d4682f6e3..3305a57b62 100644 --- a/railties/lib/rails/generators/app_base.rb +++ b/railties/lib/rails/generators/app_base.rb @@ -308,7 +308,7 @@ module Rails 'Use SCSS for stylesheets') else gems << GemfileEntry.version('sass-rails', - '~> 4.0.0.rc1', + '~> 4.0.1', 'Use SCSS for stylesheets') end @@ -329,7 +329,7 @@ module Rails def jbuilder_gemfile_entry comment = 'Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder' - GemfileEntry.version('jbuilder', '~> 1.2', comment) + GemfileEntry.version('jbuilder', '~> 2.0', comment) end def sdoc_gemfile_entry diff --git a/railties/lib/rails/generators/base.rb b/railties/lib/rails/generators/base.rb index cf33b13fd8..67bab96a22 100644 --- a/railties/lib/rails/generators/base.rb +++ b/railties/lib/rails/generators/base.rb @@ -296,7 +296,7 @@ module Rails end end - # Return the default value for the option name given doing a lookup in + # Returns the default value for the option name given doing a lookup in # Rails::Generators.options. def self.default_value_for_option(name, options) default_for_option(Rails::Generators.options, name, options, options[:default]) diff --git a/railties/lib/rails/generators/erb.rb b/railties/lib/rails/generators/erb.rb index 73e986ee7f..cfd77097d5 100644 --- a/railties/lib/rails/generators/erb.rb +++ b/railties/lib/rails/generators/erb.rb @@ -5,6 +5,10 @@ module Erb # :nodoc: class Base < Rails::Generators::NamedBase #:nodoc: protected + def formats + format + end + def format :html end @@ -13,7 +17,7 @@ module Erb # :nodoc: :erb end - def filename_with_extensions(name) + def filename_with_extensions(name, format) [name, format, handler].compact.join(".") 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 5f06734ab8..e62aece7c5 100644 --- a/railties/lib/rails/generators/erb/controller/controller_generator.rb +++ b/railties/lib/rails/generators/erb/controller/controller_generator.rb @@ -11,8 +11,10 @@ module Erb # :nodoc: actions.each do |action| @action = action - @path = File.join(base_path, filename_with_extensions(action)) - template filename_with_extensions(:view), @path + Array(formats).each do |format| + @path = File.join(base_path, filename_with_extensions(action, format)) + template filename_with_extensions(:view, format), @path + end end end end diff --git a/railties/lib/rails/generators/erb/mailer/mailer_generator.rb b/railties/lib/rails/generators/erb/mailer/mailer_generator.rb index 7bcac30dde..66b17bd10e 100644 --- a/railties/lib/rails/generators/erb/mailer/mailer_generator.rb +++ b/railties/lib/rails/generators/erb/mailer/mailer_generator.rb @@ -5,8 +5,8 @@ module Erb # :nodoc: class MailerGenerator < ControllerGenerator # :nodoc: protected - def format - :text + def formats + [:text, :html] end end end diff --git a/railties/lib/rails/generators/erb/mailer/templates/view.html.erb b/railties/lib/rails/generators/erb/mailer/templates/view.html.erb new file mode 100644 index 0000000000..8bb7c2b768 --- /dev/null +++ b/railties/lib/rails/generators/erb/mailer/templates/view.html.erb @@ -0,0 +1,5 @@ +<h1><%= class_name %>#<%= @action %></h1> + +<p> + <%%= @greeting %>, find me in app/views/<%= @path %> +</p> diff --git a/railties/lib/rails/generators/erb/scaffold/scaffold_generator.rb b/railties/lib/rails/generators/erb/scaffold/scaffold_generator.rb index bacbc2d280..b219f459ac 100644 --- a/railties/lib/rails/generators/erb/scaffold/scaffold_generator.rb +++ b/railties/lib/rails/generators/erb/scaffold/scaffold_generator.rb @@ -14,8 +14,10 @@ module Erb # :nodoc: def copy_view_files available_views.each do |view| - filename = filename_with_extensions(view) - template filename, File.join("app/views", controller_file_path, filename) + Array(formats).each do |format| + filename = filename_with_extensions(view, format) + template filename, File.join("app/views", controller_file_path, filename) + end end end diff --git a/railties/lib/rails/generators/rails/app/app_generator.rb b/railties/lib/rails/generators/rails/app/app_generator.rb index 87556bd609..e12ee3c713 100644 --- a/railties/lib/rails/generators/rails/app/app_generator.rb +++ b/railties/lib/rails/generators/rails/app/app_generator.rb @@ -78,6 +78,7 @@ module Rails template "routes.rb" template "application.rb" template "environment.rb" + template "secrets.yml" directory "environments" directory "initializers" 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 index c6dfd50d40..334d2ba51c 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 @@ -23,6 +23,6 @@ test: <<: *default database: <%= app_name %>_test -production: - <<: *default - database: <%= app_name %>_production +# Do not keep production credentials in the repository, +# instead read the configuration from the environment. +production: <%%= ENV["RAILS_DATABASE_URL"] %> 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 index fe53cd0ea2..0a2dc1b19e 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 @@ -61,6 +61,6 @@ test: <<: *default database: <%= app_name[0,4] %>_tst -production: - <<: *default - database: <%= app_name[0,8] %> +# Do not keep production credentials in the repository, +# instead read the configuration from the environment. +production: <%%= ENV["RAILS_DATABASE_URL"] %> 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 index be1dae332f..cda6bcab06 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 @@ -53,6 +53,6 @@ test: <<: *default url: jdbc:db://localhost/<%= app_name %>_test -production: - <<: *default - url: jdbc:db://localhost/<%= app_name %>_production +# Do not keep production credentials in the repository, +# instead read the configuration from the environment. +production: <%%= ENV["RAILS_DATABASE_URL"] %> 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 index 26e2a5976c..b316b3ade1 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 @@ -26,6 +26,6 @@ test: <<: *default database: <%= app_name %>_test -production: - <<: *default - database: <%= app_name %>_production +# Do not keep production credentials in the repository, +# instead read the configuration from the environment. +production: <%%= ENV["RAILS_DATABASE_URL"] %> 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 index ccd44cf54b..d76632f0ac 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 @@ -6,13 +6,20 @@ default: &default adapter: postgresql encoding: unicode - username: <%= app_name %> - password: development: <<: *default database: <%= app_name %>_development + # The specified database role being used to connect to postgres. + # To create additional roles in postgres see `$ createuser --help`. + # When left blank, postgres will use the default role. This is + # the same name as the operating system user that initialized the database. + #username: <%= app_name %> + + # The password associated with the postgres role (username). + #password: + # Connect on a TCP socket. Omitted by default since the client uses a # domain socket that doesn't need configuration. Windows does not have # domain sockets, so uncomment these lines. @@ -35,6 +42,6 @@ test: <<: *default database: <%= app_name %>_test -production: - <<: *default - database: <%= app_name %>_production +# Do not keep production credentials in the repository, +# instead read the configuration from the environment. +production: <%%= ENV["RAILS_DATABASE_URL"] %> 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 index 28c36eb82f..4aaa97b104 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 @@ -18,6 +18,6 @@ test: <<: *default database: db/test.sqlite3 -production: - <<: *default - database: db/production.sqlite3 +# Do not keep production credentials in the repository, +# instead read the configuration from the environment. +production: <%%= ENV["RAILS_DATABASE_URL"] %> 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 index 3fc7ce28a1..28a5418b49 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 @@ -32,6 +32,10 @@ test: <<: *default database: <%= app_name %>_test -production: - <<: *default - database: <%= app_name %>_production +# Avoid production credentials in the repository, +# instead read the configuration from the environment. +# +# Example: +# mysql2://myuser:mypass@localhost/somedatabase +# +production: <%%= ENV["RAILS_DATABASE_URL"] %> 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 index d5b52c969b..31abbe8ba6 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 @@ -32,6 +32,6 @@ test: <<: *default database: <%= app_name %>_test -production: - <<: *default - database: <%= app_name %>_production +# Do not keep production credentials in the repository, +# instead read the configuration from the environment. +production: <%%= ENV["RAILS_DATABASE_URL"] %> 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 index eaeb82bddd..7a7a8c08e0 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 @@ -17,16 +17,23 @@ default: &default adapter: postgresql encoding: unicode - # For details on connection pooling, see rails configration guide + # For details on connection pooling, see rails configuration guide # http://guides.rubyonrails.org/configuring.html#database-pooling pool: 5 - username: <%= app_name %> - password: development: <<: *default database: <%= app_name %>_development + # The specified database role being used to connect to postgres. + # To create additional roles in postgres see `$ createuser --help`. + # When left blank, postgres will use the default role. This is + # the same name as the operating system user that initialized the database. + #username: <%= app_name %> + + # The password associated with the postgres role (username). + #password: + # Connect on a TCP socket. Omitted by default since the client uses a # domain socket that doesn't need configuration. Windows does not have # domain sockets, so uncomment these lines. @@ -52,6 +59,10 @@ test: <<: *default database: <%= app_name %>_test -production: - <<: *default - database: <%= app_name %>_production +# Do not keep production credentials in the repository, +# instead read the configuration from the environment. +# +# Example: +# postgres://myuser:mypass@localhost/somedatabase +# +production: <%%= ENV["RAILS_DATABASE_URL"] %> 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 index 1c1a37ca8d..d8b0b61e14 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 @@ -20,6 +20,10 @@ test: <<: *default database: db/test.sqlite3 -production: - <<: *default - database: db/production.sqlite3 +# Do not keep production credentials in the repository, +# instead read the configuration from the environment. +# +# Example: +# sqlite3://myuser:mypass@localhost/somedatabase +# +production: <%%= ENV["RAILS_DATABASE_URL"] %> 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 index 4855f66c0d..c270497879 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 @@ -42,6 +42,6 @@ test: <<: *default database: <%= app_name %>_test -production: - <<: *default - database: <%= app_name %>_production +# Do not keep production credentials in the repository, +# instead read the configuration from the environment. +production: <%%= ENV["RAILS_DATABASE_URL"] %> 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 b724d468a2..cce4743a33 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 @@ -29,5 +29,10 @@ Rails.application.configure do # This option may cause significant delays in view rendering with a large # number of complex assets. config.assets.debug = true + + # Adds additional error checking when serving assets at runtime. + # Checks for improperly declared sprockets dependencies. + # Raises helpful error messages. + config.assets.raise_runtime_errors = true <%- end -%> end diff --git a/railties/lib/rails/generators/rails/app/templates/config/initializers/secret_token.rb.tt b/railties/lib/rails/generators/rails/app/templates/config/secrets.yml index f3cc6098a3..6e2c45e119 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/initializers/secret_token.rb.tt +++ b/railties/lib/rails/generators/rails/app/templates/config/secrets.yml @@ -7,6 +7,16 @@ # no regular words or you'll be exposed to dictionary attacks. # You can use `rake secret` to generate a secure secret key. -# Make sure your secret_key_base is kept private +# Make sure the secrets in this file are kept private # if you're sharing your code publicly. -Rails.application.config.secret_key_base = '<%= app_secret %>' + +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["RAILS_SECRET_KEY_BASE"] %> 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 3334b189bf..85dee1a066 100644 --- a/railties/lib/rails/generators/test_unit/mailer/mailer_generator.rb +++ b/railties/lib/rails/generators/test_unit/mailer/mailer_generator.rb @@ -4,11 +4,18 @@ module TestUnit # :nodoc: module Generators # :nodoc: class MailerGenerator < Base # :nodoc: argument :actions, type: :array, default: [], banner: "method method" - check_class_collision suffix: "Test" + + def check_class_collision + class_collisions "#{class_name}Test", "#{class_name}Preview" + end def create_test_files template "functional_test.rb", File.join('test/mailers', class_path, "#{file_name}_test.rb") end + + def create_preview_files + template "preview.rb", File.join('test/mailers/previews', class_path, "#{file_name}_preview.rb") + end end end end diff --git a/railties/lib/rails/generators/test_unit/mailer/templates/preview.rb b/railties/lib/rails/generators/test_unit/mailer/templates/preview.rb new file mode 100644 index 0000000000..3bfd5426e8 --- /dev/null +++ b/railties/lib/rails/generators/test_unit/mailer/templates/preview.rb @@ -0,0 +1,13 @@ +<% module_namespacing do -%> +# Preview all emails at http://localhost:3000/rails/mailers/<%= file_path %> +class <%= class_name %>Preview < ActionMailer::Preview +<% actions.each do |action| -%> + + # Preview this email at http://localhost:3000/rails/mailers/<%= file_path %>/<%= action %> + def <%= action %> + <%= class_name %>.<%= action %> + end +<% end -%> + +end +<% end -%> diff --git a/railties/lib/rails/info_controller.rb b/railties/lib/rails/info_controller.rb index 85ea11b4e7..908c4ce65e 100644 --- a/railties/lib/rails/info_controller.rb +++ b/railties/lib/rails/info_controller.rb @@ -1,9 +1,9 @@ +require 'rails/application_controller' require 'action_dispatch/routing/inspector' -class Rails::InfoController < ActionController::Base # :nodoc: - self.view_paths = File.expand_path('../templates', __FILE__) +class Rails::InfoController < Rails::ApplicationController # :nodoc: prepend_view_path ActionDispatch::DebugExceptions::RESCUES_TEMPLATE_PATH - layout -> { request.xhr? ? nil : 'application' } + layout -> { request.xhr? ? false : 'application' } before_filter :require_local! @@ -20,16 +20,4 @@ class Rails::InfoController < ActionController::Base # :nodoc: @routes_inspector = ActionDispatch::Routing::RoutesInspector.new(_routes.routes) @page_title = 'Routes' end - - protected - - def require_local! - unless local_request? - render text: '<p>For security purposes, this information is only available to local requests.</p>', status: :forbidden - end - end - - def local_request? - Rails.application.config.consider_all_requests_local || request.local? - end end diff --git a/railties/lib/rails/mailers_controller.rb b/railties/lib/rails/mailers_controller.rb new file mode 100644 index 0000000000..dd318f52e5 --- /dev/null +++ b/railties/lib/rails/mailers_controller.rb @@ -0,0 +1,73 @@ +require 'rails/application_controller' + +class Rails::MailersController < Rails::ApplicationController # :nodoc: + prepend_view_path ActionDispatch::DebugExceptions::RESCUES_TEMPLATE_PATH + + before_filter :require_local! + before_filter :find_preview, only: :preview + + def index + @previews = ActionMailer::Preview.all + @page_title = "Mailer Previews" + end + + def preview + if params[:path] == @preview.preview_name + @page_title = "Mailer Previews for #{@preview.preview_name}" + render action: 'mailer' + else + email = File.basename(params[:path]) + + if @preview.email_exists?(email) + @email = @preview.call(email) + + if params[:part] + part_type = Mime::Type.lookup(params[:part]) + + if part = find_part(part_type) + response.content_type = part_type + render text: part.respond_to?(:decoded) ? part.decoded : part + else + raise AbstractController::ActionNotFound, "Email part '#{part_type}' not found in #{@preview.name}##{email}" + end + else + @part = find_preferred_part(request.format, Mime::HTML, Mime::TEXT) + render action: 'email', layout: false, formats: %w[html] + end + else + raise AbstractController::ActionNotFound, "Email '#{email}' not found in #{@preview.name}" + end + end + end + + protected + def find_preview + candidates = [] + params[:path].to_s.scan(%r{/|$}){ candidates << $` } + preview = candidates.detect{ |candidate| ActionMailer::Preview.exists?(candidate) } + + if preview + @preview = ActionMailer::Preview.find(preview) + else + raise AbstractController::ActionNotFound, "Mailer preview '#{params[:path]}' not found" + end + end + + def find_preferred_part(*formats) + if @email.multipart? + formats.each do |format| + return find_part(format) if @email.parts.any?{ |p| p.mime_type == format } + end + else + @email + end + end + + def find_part(format) + if @email.multipart? + @email.parts.find{ |p| p.mime_type == format } + elsif @email.mime_type == format + @email + end + end +end
\ No newline at end of file diff --git a/railties/lib/rails/templates/layouts/application.html.erb b/railties/lib/rails/templates/layouts/application.html.erb index 50a4755e45..5aecaa712a 100644 --- a/railties/lib/rails/templates/layouts/application.html.erb +++ b/railties/lib/rails/templates/layouts/application.html.erb @@ -29,7 +29,7 @@ </style> </head> <body> -<h2>Your App: <%= link_to 'properties', '/rails/info/properties' %> | <%= link_to 'routes', '/rails/info/routes' %></h2> + <%= yield %> </body> diff --git a/railties/lib/rails/templates/rails/mailers/email.html.erb b/railties/lib/rails/templates/rails/mailers/email.html.erb new file mode 100644 index 0000000000..977feb922b --- /dev/null +++ b/railties/lib/rails/templates/rails/mailers/email.html.erb @@ -0,0 +1,98 @@ +<!DOCTYPE html> +<html><head> +<meta name="viewport" content="width=device-width" /> +<style type="text/css"> + header { + width: 100%; + padding: 10px 0 0 0; + margin: 0; + background: white; + font: 12px "Lucida Grande", sans-serif; + border-bottom: 1px solid #dedede; + overflow: hidden; + } + + dl { + margin: 0 0 10px 0; + padding: 0; + } + + dt { + width: 80px; + padding: 1px; + float: left; + clear: left; + text-align: right; + color: #7f7f7f; + } + + dd { + margin-left: 90px; /* 80px + 10px */ + padding: 1px; + } + + iframe { + border: 0; + width: 100%; + height: 800px; + } +</style> +</head> + +<body> +<header> + <dl> + <% if @email.respond_to?(:smtp_envelope_from) && Array(@email.from) != Array(@email.smtp_envelope_from) %> + <dt>SMTP-From:</dt> + <dd><%= @email.smtp_envelope_from %></dd> + <% end %> + + <% if @email.respond_to?(:smtp_envelope_to) && @email.to != @email.smtp_envelope_to %> + <dt>SMTP-To:</dt> + <dd><%= @email.smtp_envelope_to %></dd> + <% end %> + + <dt>From:</dt> + <dd><%= @email.header['from'] %></dd> + + <% if @email.reply_to %> + <dt>Reply-To:</dt> + <dd><%= @email.header['reply-to'] %></dd> + <% end %> + + <dt>To:</dt> + <dd><%= @email.header['to'] %></dd> + + <% if @email.cc %> + <dt>CC:</dt> + <dd><%= @email.header['cc'] %></dd> + <% end %> + + <dt>Date:</dt> + <dd><%= Time.current.rfc2822 %></dd> + + <dt>Subject:</dt> + <dd><strong><%= @email.subject %></strong></dd> + + <% unless @email.attachments.nil? || @email.attachments.empty? %> + <dt>Attachments:</dt> + <dd> + <%= @email.attachments.map { |a| a.respond_to?(:original_filename) ? a.original_filename : a.filename }.inspect %> + </dd> + <% end %> + + <% if @email.multipart? %> + <dd> + <select onchange="document.getElementsByName('messageBody')[0].src=this.options[this.selectedIndex].value;"> + <option <%= request.format == Mime::HTML ? 'selected' : '' %> value="?part=text%2Fhtml">View as HTML email</option> + <option <%= request.format == Mime::TEXT ? 'selected' : '' %> value="?part=text%2Fplain">View as plain-text email</option> + </select> + </dd> + <% end %> + </dl> +</header> + +<iframe seamless name="messageBody" src="?part=<%= Rack::Utils.escape(@part.mime_type) %>"></iframe> + +</body> +</html>
\ No newline at end of file diff --git a/railties/lib/rails/templates/rails/mailers/index.html.erb b/railties/lib/rails/templates/rails/mailers/index.html.erb new file mode 100644 index 0000000000..c4c9757d57 --- /dev/null +++ b/railties/lib/rails/templates/rails/mailers/index.html.erb @@ -0,0 +1,8 @@ +<% @previews.each do |preview| %> +<h3><%= link_to preview.preview_name.titleize, "/rails/mailers/#{preview.preview_name}" %></h3> +<ul> +<% preview.emails.each do |email| %> +<li><%= link_to email, "/rails/mailers/#{preview.preview_name}/#{email}" %></li> +<% end %> +</ul> +<% end %> diff --git a/railties/lib/rails/templates/rails/mailers/mailer.html.erb b/railties/lib/rails/templates/rails/mailers/mailer.html.erb new file mode 100644 index 0000000000..607c8d1677 --- /dev/null +++ b/railties/lib/rails/templates/rails/mailers/mailer.html.erb @@ -0,0 +1,6 @@ +<h3><%= @preview.preview_name.titleize %></h3> +<ul> +<% @preview.emails.each do |email| %> +<li><%= link_to email, "/rails/mailers/#{@preview.preview_name}/#{email}" %></li> +<% end %> +</ul> diff --git a/railties/lib/rails/test_help.rb b/railties/lib/rails/test_help.rb index be801befc2..7765c9ae86 100644 --- a/railties/lib/rails/test_help.rb +++ b/railties/lib/rails/test_help.rb @@ -11,7 +11,7 @@ require 'rails/generators/test_case' # Config Rails backtrace in tests. require 'rails/backtrace_cleaner' if ENV["BACKTRACE"].nil? - MiniTest.backtrace_filter = Rails.backtrace_cleaner + Minitest.backtrace_filter = Rails.backtrace_cleaner end if defined?(ActiveRecord::Base) diff --git a/railties/lib/rails/version.rb b/railties/lib/rails/version.rb index 5a6d8d0983..923cab4e2a 100644 --- a/railties/lib/rails/version.rb +++ b/railties/lib/rails/version.rb @@ -3,7 +3,7 @@ module Rails MAJOR = 4 MINOR = 1 TINY = 0 - PRE = "beta" + PRE = "beta1" STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".") end diff --git a/railties/lib/rails/welcome_controller.rb b/railties/lib/rails/welcome_controller.rb index 45b764fa6b..de9cd18b01 100644 --- a/railties/lib/rails/welcome_controller.rb +++ b/railties/lib/rails/welcome_controller.rb @@ -1,6 +1,7 @@ -class Rails::WelcomeController < ActionController::Base # :nodoc: - self.view_paths = File.expand_path('../templates', __FILE__) - layout nil +require 'rails/application_controller' + +class Rails::WelcomeController < Rails::ApplicationController # :nodoc: + layout false def index end |