diff options
47 files changed, 222 insertions, 164 deletions
diff --git a/actioncable/lib/action_cable/remote_connections.rb b/actioncable/lib/action_cable/remote_connections.rb index a92b5e90b4..a07a517092 100644 --- a/actioncable/lib/action_cable/remote_connections.rb +++ b/actioncable/lib/action_cable/remote_connections.rb @@ -51,9 +51,10 @@ module ActionCable server.connection_identifiers end - private + protected attr_reader :server + private def set_identifier_instance_vars(ids) raise InvalidIdentifiersError unless valid_identifiers?(ids) ids.each { |k, v| instance_variable_set("@#{k}", v) } diff --git a/actionpack/lib/action_dispatch/middleware/cookies.rb b/actionpack/lib/action_dispatch/middleware/cookies.rb index 5a55ee13ee..c0913715ac 100644 --- a/actionpack/lib/action_dispatch/middleware/cookies.rb +++ b/actionpack/lib/action_dispatch/middleware/cookies.rb @@ -360,7 +360,11 @@ module ActionDispatch @cookies.map { |k, v| "#{escape(k)}=#{escape(v)}" }.join "; " end - def handle_options(options) #:nodoc: + def handle_options(options) # :nodoc: + if options[:expires].respond_to?(:from_now) + options[:expires] = options[:expires].from_now + end + options[:path] ||= "/" if options[:domain] == :all || options[:domain] == "all" @@ -488,6 +492,14 @@ module ActionDispatch def request; @parent_jar.request; end private + def expiry_options(options) + if options[:expires].respond_to?(:from_now) + { expires_in: options[:expires] } + else + { expires_at: options[:expires] } + end + end + def parse(name, data); data; end def commit(options); end end @@ -569,7 +581,7 @@ module ActionDispatch end def commit(options) - options[:value] = @verifier.generate(serialize(options[:value])) + options[:value] = @verifier.generate(serialize(options[:value]), expiry_options(options)) raise CookieOverflow if options[:value].bytesize > MAX_COOKIE_SIZE end @@ -609,7 +621,7 @@ module ActionDispatch end def commit(options) - options[:value] = @encryptor.encrypt_and_sign(serialize(options[:value])) + options[:value] = @encryptor.encrypt_and_sign(serialize(options[:value]), expiry_options(options)) raise CookieOverflow if options[:value].bytesize > MAX_COOKIE_SIZE end diff --git a/actionpack/lib/action_dispatch/routing/mapper.rb b/actionpack/lib/action_dispatch/routing/mapper.rb index 28809d7e67..57a5bc681e 100644 --- a/actionpack/lib/action_dispatch/routing/mapper.rb +++ b/actionpack/lib/action_dispatch/routing/mapper.rb @@ -1851,7 +1851,7 @@ module ActionDispatch path_types.fetch(String, []).each do |_path| route_options = options.dup if _path && option_path - raise ArgumentError, "Ambiguous route definition. Both :path and the route path where specified as strings." + raise ArgumentError, "Ambiguous route definition. Both :path and the route path were specified as strings." end to = get_to_from_path(_path, to, route_options[:action]) decomposed_match(_path, controller, route_options, _path, to, via, formatted, anchor, options_constraints) diff --git a/actionpack/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb b/actionpack/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb index 4eef15b6c2..dbd27ffd32 100644 --- a/actionpack/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +++ b/actionpack/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb @@ -21,7 +21,7 @@ module ActionDispatch # This is the default value if the +CI+ environment variables # is defined. # * [+artifact+] display the screenshot in the terminal, using the terminal - # artifact format (http://buildkite.github.io/terminal/inline-images/). + # artifact format (https://buildkite.github.io/terminal/inline-images/). def take_screenshot save_image puts display_image diff --git a/actionpack/test/dispatch/cookies_test.rb b/actionpack/test/dispatch/cookies_test.rb index a551fb00a8..cb225c0f62 100644 --- a/actionpack/test/dispatch/cookies_test.rb +++ b/actionpack/test/dispatch/cookies_test.rb @@ -278,6 +278,11 @@ class CookiesTest < ActionController::TestCase def encrypted_cookie cookies.encrypted["foo"] end + + def cookie_expires_in_two_hours + cookies[:user_name] = { value: "assain", expires: 2.hours } + head :ok + end end tests TestController @@ -1235,6 +1240,33 @@ class CookiesTest < ActionController::TestCase assert_equal "bar", @controller.encrypted_cookie end + def test_signed_cookie_with_expires_set_relatively + cookies.signed[:user_name] = { value: "assain", expires: 2.hours } + + travel 1.hour + assert_equal "assain", cookies.signed[:user_name] + + travel 2.hours + assert_nil cookies.signed[:user_name] + end + + def test_encrypted_cookie_with_expires_set_relatively + cookies.encrypted[:user_name] = { value: "assain", expires: 2.hours } + + travel 1.hour + assert_equal "assain", cookies.encrypted[:user_name] + + travel 2.hours + assert_nil cookies.encrypted[:user_name] + end + + def test_vanilla_cookie_with_expires_set_relatively + travel_to Time.utc(2017, 8, 15) do + get :cookie_expires_in_two_hours + assert_cookie_header "user_name=assain; path=/; expires=Tue, 15 Aug 2017 02:00:00 -0000" + end + end + private def assert_cookie_header(expected) header = @response.headers["Set-Cookie"] diff --git a/actionpack/test/dispatch/session/cookie_store_test.rb b/actionpack/test/dispatch/session/cookie_store_test.rb index 26a63c9f7d..6517cf4c99 100644 --- a/actionpack/test/dispatch/session/cookie_store_test.rb +++ b/actionpack/test/dispatch/session/cookie_store_test.rb @@ -26,6 +26,11 @@ class CookieStoreTest < ActionDispatch::IntegrationTest render plain: Rack::Utils.escape(Verifier.generate(session.to_hash)) end + def set_session_value_expires_in_five_hours + session[:foo] = "bar" + render plain: Rack::Utils.escape(Verifier.generate(session.to_hash, expires_in: 5.hours)) + end + def get_session_value render plain: "foo: #{session[:foo].inspect}" end @@ -283,7 +288,7 @@ class CookieStoreTest < ActionDispatch::IntegrationTest cookies[SessionKey] = SignedBar - get "/set_session_value" + get "/set_session_value_expires_in_five_hours" assert_response :success cookie_body = response.body @@ -299,7 +304,7 @@ class CookieStoreTest < ActionDispatch::IntegrationTest get "/no_session_access" assert_response :success - assert_equal "_myapp_session=#{cookie_body}; path=/; expires=#{expected_expiry}; HttpOnly", + assert_equal "_myapp_session=#{cookies[SessionKey]}; path=/; expires=#{expected_expiry}; HttpOnly", headers["Set-Cookie"] end end diff --git a/actionview/test/ujs/public/vendor/qunit.js b/actionview/test/ujs/public/vendor/qunit.js index 0e279fde17..50a9e6455d 100644 --- a/actionview/test/ujs/public/vendor/qunit.js +++ b/actionview/test/ujs/public/vendor/qunit.js @@ -42,7 +42,7 @@ var QUnit, * with IE 7 (and prior) where Error.prototype.toString is * not properly implemented * - * Based on http://es5.github.com/#x15.11.4.4 + * Based on https://es5.github.io/#x15.11.4.4 * * @param {String|Error} error * @return {String} error message diff --git a/activejob/lib/active_job/queue_adapters/async_adapter.rb b/activejob/lib/active_job/queue_adapters/async_adapter.rb index eec9ae08bb..ebf6f384e3 100644 --- a/activejob/lib/active_job/queue_adapters/async_adapter.rb +++ b/activejob/lib/active_job/queue_adapters/async_adapter.rb @@ -31,7 +31,7 @@ module ActiveJob # jobs. Since jobs share a single thread pool, long-running jobs will block # short-lived jobs. Fine for dev/test; bad for production. class AsyncAdapter - # See {Concurrent::ThreadPoolExecutor}[http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/ThreadPoolExecutor.html] for executor options. + # See {Concurrent::ThreadPoolExecutor}[https://ruby-concurrency.github.io/concurrent-ruby/Concurrent/ThreadPoolExecutor.html] for executor options. def initialize(**executor_options) @scheduler = Scheduler.new(**executor_options) end diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_dumper.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_dumper.rb index 9be26254b2..f17f1d35e2 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/schema_dumper.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_dumper.rb @@ -1,5 +1,7 @@ # frozen_string_literal: true +require "active_support/core_ext/hash/compact" + module ActiveRecord module ConnectionAdapters # :nodoc: # The goal of this module is to move Adapter specific column @@ -20,38 +22,6 @@ module ActiveRecord spec end - # This can be overridden on an Adapter level basis to support other - # extended datatypes (Example: Adding an array option in the - # PostgreSQL::ColumnDumper) - def prepare_column_options(column) - spec = {} - - if limit = schema_limit(column) - spec[:limit] = limit - end - - if precision = schema_precision(column) - spec[:precision] = precision - end - - if scale = schema_scale(column) - spec[:scale] = scale - end - - default = schema_default(column) if column.has_default? - spec[:default] = default unless default.nil? - - spec[:null] = "false" unless column.null - - if collation = schema_collation(column) - spec[:collation] = collation - end - - spec[:comment] = column.comment.inspect if column.comment.present? - - spec - end - # Lists the valid migration options def migration_keys # :nodoc: column_options_keys @@ -59,6 +29,18 @@ module ActiveRecord deprecate :migration_keys private + def prepare_column_options(column) + spec = {} + spec[:limit] = schema_limit(column) + spec[:precision] = schema_precision(column) + spec[:scale] = schema_scale(column) + spec[:default] = schema_default(column) + spec[:null] = "false" unless column.null + spec[:collation] = schema_collation(column) + spec[:comment] = column.comment.inspect if column.comment.present? + spec.compact! + spec + end def default_primary_key?(column) schema_type(column) == :bigint @@ -98,6 +80,7 @@ module ActiveRecord end def schema_default(column) + return unless column.has_default? type = lookup_cast_type_from_column(column) default = type.deserialize(column.default) if default.nil? diff --git a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb index 5915f0db2d..1b4688a904 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb @@ -20,10 +20,6 @@ module ActiveRecord include MySQL::ColumnDumper include MySQL::SchemaStatements - def update_table_definition(table_name, base) # :nodoc: - MySQL::Table.new(table_name, base) - end - ## # :singleton-method: # By default, the Mysql2Adapter will consider all columns of type <tt>tinyint(1)</tt> diff --git a/activerecord/lib/active_record/connection_adapters/mysql/schema_dumper.rb b/activerecord/lib/active_record/connection_adapters/mysql/schema_dumper.rb index fbe3596dda..81f7dce562 100644 --- a/activerecord/lib/active_record/connection_adapters/mysql/schema_dumper.rb +++ b/activerecord/lib/active_record/connection_adapters/mysql/schema_dumper.rb @@ -4,24 +4,23 @@ module ActiveRecord module ConnectionAdapters module MySQL module ColumnDumper # :nodoc: - def prepare_column_options(column) - spec = super - spec[:unsigned] = "true" if column.unsigned? - - if supports_virtual_columns? && column.virtual? - spec[:as] = extract_expression_for_virtual_column(column) - spec[:stored] = "true" if /\b(?:STORED|PERSISTENT)\b/.match?(column.extra) - spec = { type: schema_type(column).inspect }.merge!(spec) - end - - spec - end - def migration_keys super + [:unsigned] end private + def prepare_column_options(column) + spec = super + spec[:unsigned] = "true" if column.unsigned? + + if supports_virtual_columns? && column.virtual? + spec[:as] = extract_expression_for_virtual_column(column) + spec[:stored] = "true" if /\b(?:STORED|PERSISTENT)\b/.match?(column.extra) + spec = { type: schema_type(column).inspect }.merge!(spec) + end + + spec + end def default_primary_key?(column) super && column.auto_increment? && !column.unsigned? diff --git a/activerecord/lib/active_record/connection_adapters/mysql/schema_statements.rb b/activerecord/lib/active_record/connection_adapters/mysql/schema_statements.rb index 1d87d60ba9..7bebe82065 100644 --- a/activerecord/lib/active_record/connection_adapters/mysql/schema_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/mysql/schema_statements.rb @@ -62,6 +62,10 @@ module ActiveRecord end end + def update_table_definition(table_name, base) + MySQL::Table.new(table_name, base) + end + private CHARSETS_OF_4BYTES_MAXLEN = ["utf8mb4", "utf16", "utf16le", "utf32"] diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/schema_dumper.rb b/activerecord/lib/active_record/connection_adapters/postgresql/schema_dumper.rb index 12c6603081..5031605c2a 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql/schema_dumper.rb @@ -4,19 +4,17 @@ module ActiveRecord module ConnectionAdapters module PostgreSQL module ColumnDumper # :nodoc: - # Adds +:array+ option to the default set - def prepare_column_options(column) - spec = super - spec[:array] = "true" if column.array? - spec - end - # Adds +:array+ as a valid migration key def migration_keys super + [:array] end private + def prepare_column_options(column) + spec = super + spec[:array] = "true" if column.array? + spec + end def default_primary_key?(column) schema_type(column) == :bigserial diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb b/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb index 780e642f21..f258203a43 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb @@ -586,6 +586,10 @@ module ActiveRecord [super, *order_columns].join(", ") end + def update_table_definition(table_name, base) # :nodoc: + PostgreSQL::Table.new(table_name, base) + end + private def schema_creation PostgreSQL::SchemaCreation.new(self) diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb index 3b4439fc46..a2a9017bd9 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb @@ -76,7 +76,7 @@ module ActiveRecord primary_key: "bigserial primary key", string: { name: "character varying" }, text: { name: "text" }, - integer: { name: "integer" }, + integer: { name: "integer", limit: 4 }, float: { name: "float" }, decimal: { name: "decimal" }, datetime: { name: "timestamp" }, @@ -368,10 +368,6 @@ module ActiveRecord @use_insert_returning end - def update_table_definition(table_name, base) #:nodoc: - PostgreSQL::Table.new(table_name, base) - end - def column_name_for_operation(operation, node) # :nodoc: OPERATION_ALIASES.fetch(operation) { operation.downcase } end @@ -439,9 +435,9 @@ module ActiveRecord end def initialize_type_map(m = type_map) - register_class_with_limit m, "int2", Type::Integer - register_class_with_limit m, "int4", Type::Integer - register_class_with_limit m, "int8", Type::Integer + m.register_type "int2", Type::Integer.new(limit: 2) + m.register_type "int4", Type::Integer.new(limit: 4) + m.register_type "int8", Type::Integer.new(limit: 8) m.register_type "oid", OID::Oid.new m.register_type "float4", Type::Float.new m.alias_type "float8", "float4" @@ -508,17 +504,6 @@ module ActiveRecord load_additional_types end - def extract_limit(sql_type) - case sql_type - when /^bigint/i, /^int8/i - 8 - when /^smallint/i - 2 - else - super - end - end - # Extracts the value from a PostgreSQL column default definition. def extract_value_from_default(default) case default diff --git a/activerecord/lib/active_record/connection_adapters/sqlite3/schema_statements.rb b/activerecord/lib/active_record/connection_adapters/sqlite3/schema_statements.rb index c155e7f1ac..ee84646214 100644 --- a/activerecord/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/sqlite3/schema_statements.rb @@ -39,6 +39,10 @@ module ActiveRecord end end + def update_table_definition(table_name, base) + SQLite3::Table.new(table_name, base) + end + private def schema_creation SQLite3::SchemaCreation.new(self) diff --git a/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb b/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb index 10e80179ac..327ca34e77 100644 --- a/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb @@ -99,10 +99,6 @@ module ActiveRecord end end - def update_table_definition(table_name, base) # :nodoc: - SQLite3::Table.new(table_name, base) - end - def initialize(connection, logger, connection_options, config) super(connection, logger, config) diff --git a/activerecord/lib/active_record/schema.rb b/activerecord/lib/active_record/schema.rb index f166c27fd9..1e121f2a09 100644 --- a/activerecord/lib/active_record/schema.rb +++ b/activerecord/lib/active_record/schema.rb @@ -39,7 +39,7 @@ module ActiveRecord # The +info+ hash is optional, and if given is used to define metadata # about the current schema (currently, only the schema's version): # - # ActiveRecord::Schema.define(version: 20380119000001) do + # ActiveRecord::Schema.define(version: 2038_01_19_000001) do # ... # end def self.define(info = {}, &block) diff --git a/activerecord/test/cases/adapter_test.rb b/activerecord/test/cases/adapter_test.rb index d7551cd658..9aaa2852d0 100644 --- a/activerecord/test/cases/adapter_test.rb +++ b/activerecord/test/cases/adapter_test.rb @@ -288,11 +288,11 @@ module ActiveRecord def test_log_invalid_encoding error = assert_raises RuntimeError do @connection.send :log, "SELECT 'ы' FROM DUAL" do - raise "ы".force_encoding(Encoding::ASCII_8BIT) + raise "ы".dup.force_encoding(Encoding::ASCII_8BIT) end end - assert_not_nil error.message + assert_equal "ы", error.message end end end diff --git a/activestorage/app/controllers/active_storage/disk_controller.rb b/activestorage/app/controllers/active_storage/disk_controller.rb index b10d4e2cac..41e6d61bff 100644 --- a/activestorage/app/controllers/active_storage/disk_controller.rb +++ b/activestorage/app/controllers/active_storage/disk_controller.rb @@ -8,7 +8,7 @@ class ActiveStorage::DiskController < ActionController::Base def show if key = decode_verified_key send_data disk_service.download(key), - filename: params[:filename], disposition: disposition_param, content_type: params[:content_type] + disposition: disposition_param, content_type: params[:content_type] else head :not_found end @@ -39,7 +39,7 @@ class ActiveStorage::DiskController < ActionController::Base end def disposition_param - params[:disposition].presence_in(%w( inline attachment )) || "inline" + params[:disposition].presence || "inline" end diff --git a/activestorage/app/models/active_storage/blob.rb b/activestorage/app/models/active_storage/blob.rb index 9f2ed1e5ac..2e627ef118 100644 --- a/activestorage/app/models/active_storage/blob.rb +++ b/activestorage/app/models/active_storage/blob.rb @@ -127,7 +127,7 @@ class ActiveStorage::Blob < ActiveRecord::Base # Hiding the +service_url+ behind a redirect also gives you the power to change services without updating all URLs. And # it allows permanent URLs that redirect to the +service_url+ to be cached in the view. def service_url(expires_in: 5.minutes, disposition: :inline) - service.url key, expires_in: expires_in, disposition: disposition, filename: filename, content_type: content_type + service.url key, expires_in: expires_in, disposition: "#{disposition}; filename=\"#{filename}\"", filename: filename, content_type: content_type end # Returns a URL that can be used to directly upload a file for this blob on the service. This URL is intended to be diff --git a/activestorage/app/models/active_storage/filename.rb b/activestorage/app/models/active_storage/filename.rb index 6a9889addf..df21078718 100644 --- a/activestorage/app/models/active_storage/filename.rb +++ b/activestorage/app/models/active_storage/filename.rb @@ -9,21 +9,23 @@ class ActiveStorage::Filename @filename = filename end - # Filename.new("racecar.jpg").extname # => ".jpg" - def extname - File.extname(@filename) + # Filename.new("racecar.jpg").base # => "racecar" + def base + File.basename @filename, extension_with_delimiter end - # Filename.new("racecar.jpg").extension # => "jpg" - def extension - extname.from(1) + # Filename.new("racecar.jpg").extension_with_delimiter # => ".jpg" + def extension_with_delimiter + File.extname @filename end - # Filename.new("racecar.jpg").base # => "racecar" - def base - File.basename(@filename, extname) + # Filename.new("racecar.jpg").extension_without_delimiter # => "jpg" + def extension_without_delimiter + extension_with_delimiter.from(1).to_s end + alias_method :extension, :extension_without_delimiter + # Filename.new("foo:bar.jpg").sanitized # => "foo-bar.jpg" # Filename.new("foo/bar.jpg").sanitized # => "foo-bar.jpg" # diff --git a/activestorage/bin/test b/activestorage/bin/test new file mode 100755 index 0000000000..c53377cc97 --- /dev/null +++ b/activestorage/bin/test @@ -0,0 +1,5 @@ +#!/usr/bin/env ruby +# frozen_string_literal: true + +COMPONENT_ROOT = File.expand_path("..", __dir__) +require_relative "../../tools/test" diff --git a/activestorage/lib/active_storage/service/azure_storage_service.rb b/activestorage/lib/active_storage/service/azure_storage_service.rb index d0ee2273c5..895cc9c2f1 100644 --- a/activestorage/lib/active_storage/service/azure_storage_service.rb +++ b/activestorage/lib/active_storage/service/azure_storage_service.rb @@ -59,12 +59,16 @@ module ActiveStorage end end - def url(key, expires_in:, disposition:, filename:, content_type:) + def url(key, expires_in:, filename:, disposition:, content_type:) instrument :url, key do |payload| base_url = url_for(key) - generated_url = signer.signed_uri(URI(base_url), false, permissions: "r", - expiry: format_expiry(expires_in), content_type: content_type, - content_disposition: "#{disposition}; filename=\"#{filename}\"").to_s + generated_url = signer.signed_uri( + URI(base_url), false, + permissions: "r", + expiry: format_expiry(expires_in), + content_disposition: disposition, + content_type: content_type + ).to_s payload[:url] = generated_url diff --git a/activestorage/lib/active_storage/service/disk_service.rb b/activestorage/lib/active_storage/service/disk_service.rb index 1d121dcb6c..5aa8d74a5a 100644 --- a/activestorage/lib/active_storage/service/disk_service.rb +++ b/activestorage/lib/active_storage/service/disk_service.rb @@ -56,7 +56,7 @@ module ActiveStorage end end - def url(key, expires_in:, disposition:, filename:, content_type:) + def url(key, expires_in:, filename:, disposition:, content_type:) instrument :url, key do |payload| verified_key_with_expiration = ActiveStorage.verifier.generate(key, expires_in: expires_in, purpose: :blob_key) @@ -64,7 +64,7 @@ module ActiveStorage if defined?(Rails.application) Rails.application.routes.url_helpers.rails_disk_service_path \ verified_key_with_expiration, - disposition: disposition, filename: filename, content_type: content_type + filename: filename, disposition: disposition, content_type: content_type else "/rails/active_storage/disk/#{verified_key_with_expiration}/#{filename}?disposition=#{disposition}&content_type=#{content_type}" end diff --git a/activestorage/lib/active_storage/service/gcs_service.rb b/activestorage/lib/active_storage/service/gcs_service.rb index e656f2c69f..ebf24a36d7 100644 --- a/activestorage/lib/active_storage/service/gcs_service.rb +++ b/activestorage/lib/active_storage/service/gcs_service.rb @@ -47,10 +47,10 @@ module ActiveStorage end end - def url(key, expires_in:, disposition:, filename:, content_type:) + def url(key, expires_in:, filename:, content_type:, disposition:) instrument :url, key do |payload| generated_url = file_for(key).signed_url expires: expires_in, query: { - "response-content-disposition" => "#{disposition}; filename=\"#{filename}\"", + "response-content-disposition" => disposition, "response-content-type" => content_type } diff --git a/activestorage/lib/active_storage/service/s3_service.rb b/activestorage/lib/active_storage/service/s3_service.rb index bef2ecbea9..e5d1e56e05 100644 --- a/activestorage/lib/active_storage/service/s3_service.rb +++ b/activestorage/lib/active_storage/service/s3_service.rb @@ -52,10 +52,10 @@ module ActiveStorage end end - def url(key, expires_in:, disposition:, filename:, content_type:) + def url(key, expires_in:, filename:, disposition:, content_type:) instrument :url, key do |payload| generated_url = object_for(key).presigned_url :get, expires_in: expires_in, - response_content_disposition: "#{disposition}; filename=\"#{filename}\"", + response_content_disposition: disposition, response_content_type: content_type payload[:url] = generated_url diff --git a/activestorage/test/controllers/disk_controller_test.rb b/activestorage/test/controllers/disk_controller_test.rb index 53a086f214..eacb9bfc11 100644 --- a/activestorage/test/controllers/disk_controller_test.rb +++ b/activestorage/test/controllers/disk_controller_test.rb @@ -8,7 +8,7 @@ class ActiveStorage::DiskControllerTest < ActionDispatch::IntegrationTest blob = create_blob get blob.service_url - assert_equal "inline; filename=\"#{blob.filename.base}\"", @response.headers["Content-Disposition"] + assert_equal "inline; filename=\"hello.txt\"", @response.headers["Content-Disposition"] assert_equal "text/plain", @response.headers["Content-Type"] end @@ -16,7 +16,7 @@ class ActiveStorage::DiskControllerTest < ActionDispatch::IntegrationTest blob = create_blob get blob.service_url(disposition: :attachment) - assert_equal "attachment; filename=\"#{blob.filename.base}\"", @response.headers["Content-Disposition"] + assert_equal "attachment; filename=\"hello.txt\"", @response.headers["Content-Disposition"] assert_equal "text/plain", @response.headers["Content-Type"] end diff --git a/activestorage/test/models/blob_test.rb b/activestorage/test/models/blob_test.rb index 99f2fb20b0..03bf72c0de 100644 --- a/activestorage/test/models/blob_test.rb +++ b/activestorage/test/models/blob_test.rb @@ -50,7 +50,7 @@ class ActiveStorage::BlobTest < ActiveSupport::TestCase private def expected_url_for(blob, disposition: :inline) - query_string = { content_type: blob.content_type, disposition: disposition }.to_param + query_string = { content_type: blob.content_type, disposition: "#{disposition}; filename=\"#{blob.filename}\"" }.to_param "/rails/active_storage/disk/#{ActiveStorage.verifier.generate(blob.key, expires_in: 5.minutes, purpose: :blob_key)}/#{blob.filename}?#{query_string}" end end diff --git a/activestorage/test/models/filename_test.rb b/activestorage/test/models/filename_test.rb index f1e4a467ba..88405e41c0 100644 --- a/activestorage/test/models/filename_test.rb +++ b/activestorage/test/models/filename_test.rb @@ -3,6 +3,24 @@ require "test_helper" class ActiveStorage::FilenameTest < ActiveSupport::TestCase + test "base" do + assert_equal "racecar", ActiveStorage::Filename.new("racecar.jpg").base + assert_equal "race.car", ActiveStorage::Filename.new("race.car.jpg").base + assert_equal "racecar", ActiveStorage::Filename.new("racecar").base + end + + test "extension with delimiter" do + assert_equal ".jpg", ActiveStorage::Filename.new("racecar.jpg").extension_with_delimiter + assert_equal ".jpg", ActiveStorage::Filename.new("race.car.jpg").extension_with_delimiter + assert_equal "", ActiveStorage::Filename.new("racecar").extension_with_delimiter + end + + test "extension without delimiter" do + assert_equal "jpg", ActiveStorage::Filename.new("racecar.jpg").extension_without_delimiter + assert_equal "jpg", ActiveStorage::Filename.new("race.car.jpg").extension_without_delimiter + assert_equal "", ActiveStorage::Filename.new("racecar").extension_without_delimiter + end + test "sanitize" do "%$|:;/\t\r\n\\".each_char do |character| filename = ActiveStorage::Filename.new("foo#{character}bar.pdf") diff --git a/activestorage/test/service/azure_storage_service_test.rb b/activestorage/test/service/azure_storage_service_test.rb index dac154cf11..4729bdfbc5 100644 --- a/activestorage/test/service/azure_storage_service_test.rb +++ b/activestorage/test/service/azure_storage_service_test.rb @@ -11,9 +11,9 @@ if SERVICE_CONFIGURATIONS[:azure] test "signed URL generation" do url = @service.url(FIXTURE_KEY, expires_in: 5.minutes, - disposition: :inline, filename: "avatar.png", content_type: "image/png") + disposition: "inline; filename=\"avatar.png\"", filename: "avatar.png", content_type: "image/png") - assert_match(/(\S+)&rsct=image%2Fpng&rscd=inline%3B\+filename%3D%22avatar.png/, url) + assert_match(/(\S+)&rscd=inline%3B\+filename%3D%22avatar.png%22&rsct=image%2Fpng/, url) assert_match SERVICE_CONFIGURATIONS[:azure][:container], url end end diff --git a/activestorage/test/service/disk_service_test.rb b/activestorage/test/service/disk_service_test.rb index 835a3a2971..f57e44536a 100644 --- a/activestorage/test/service/disk_service_test.rb +++ b/activestorage/test/service/disk_service_test.rb @@ -9,6 +9,6 @@ class ActiveStorage::Service::DiskServiceTest < ActiveSupport::TestCase test "url generation" do assert_match(/rails\/active_storage\/disk\/.*\/avatar\.png\?.+disposition=inline/, - @service.url(FIXTURE_KEY, expires_in: 5.minutes, disposition: :inline, filename: "avatar.png", content_type: "image/png")) + @service.url(FIXTURE_KEY, expires_in: 5.minutes, disposition: "inline; filename=\"avatar.png\"", filename: "avatar.png", content_type: "image/png")) end end diff --git a/activestorage/test/service/gcs_service_test.rb b/activestorage/test/service/gcs_service_test.rb index 5f53f61baf..f664cee90b 100644 --- a/activestorage/test/service/gcs_service_test.rb +++ b/activestorage/test/service/gcs_service_test.rb @@ -37,7 +37,7 @@ if SERVICE_CONFIGURATIONS[:gcs] "&response-content-disposition=inline%3B+filename%3D%22test.txt%22" + "&response-content-type=text%2Fplain" - assert_equal url, @service.url(FIXTURE_KEY, expires_in: 2.minutes, disposition: :inline, filename: "test.txt", content_type: "text/plain") + assert_equal url, @service.url(FIXTURE_KEY, expires_in: 2.minutes, disposition: "inline; filename=\"test.txt\"", filename: "test.txt", content_type: "text/plain") end end end diff --git a/activestorage/test/service/s3_service_test.rb b/activestorage/test/service/s3_service_test.rb index 98f520741d..c07d6396b1 100644 --- a/activestorage/test/service/s3_service_test.rb +++ b/activestorage/test/service/s3_service_test.rb @@ -33,7 +33,7 @@ if SERVICE_CONFIGURATIONS[:s3] && SERVICE_CONFIGURATIONS[:s3][:access_key_id].pr test "signed URL generation" do url = @service.url(FIXTURE_KEY, expires_in: 5.minutes, - disposition: :inline, filename: "avatar.png", content_type: "image/png") + disposition: "inline; filename=\"avatar.png\"", filename: "avatar.png", content_type: "image/png") assert_match(/s3\.(\S+)?amazonaws.com.*response-content-disposition=inline.*avatar\.png.*response-content-type=image%2Fpng/, url) assert_match SERVICE_CONFIGURATIONS[:s3][:bucket], url diff --git a/guides/source/2_3_release_notes.md b/guides/source/2_3_release_notes.md index 6976848e95..3f5a3c7ade 100644 --- a/guides/source/2_3_release_notes.md +++ b/guides/source/2_3_release_notes.md @@ -10,7 +10,7 @@ Rails 2.3 delivers a variety of new and improved features, including pervasive R Application Architecture ------------------------ -There are two major changes in the architecture of Rails applications: complete integration of the [Rack](http://rack.github.io/) modular web server interface, and renewed support for Rails Engines. +There are two major changes in the architecture of Rails applications: complete integration of the [Rack](https://rack.github.io/) modular web server interface, and renewed support for Rails Engines. ### Rack Integration diff --git a/guides/source/5_0_release_notes.md b/guides/source/5_0_release_notes.md index 5f4be07351..6d53e1c2b4 100644 --- a/guides/source/5_0_release_notes.md +++ b/guides/source/5_0_release_notes.md @@ -55,7 +55,7 @@ information. ### API Applications Rails can now be used to create slimmed down API only applications. -This is useful for creating and serving APIs similar to [Twitter](https://dev.twitter.com) or [GitHub](http://developer.github.com) API, +This is useful for creating and serving APIs similar to [Twitter](https://dev.twitter.com) or [GitHub](https://developer.github.com) API, that can be used to serve public facing, as well as, for custom applications. You can generate a new api Rails app using: @@ -74,11 +74,11 @@ This will do three main things: Controller modules that provide functionalities primarily used by browser applications. - Configure the generators to skip generating views, helpers and assets when - you generate a new resource. + you generate a new resource. -The application provides a base for APIs, +The application provides a base for APIs, that can then be [configured to pull in functionality](api_app.html) as suitable for the application's needs. - + See the [Using Rails for API-only Applications](api_app.html) guide for more information. diff --git a/guides/source/api_app.md b/guides/source/api_app.md index 64200ec242..5ec79de8a0 100644 --- a/guides/source/api_app.md +++ b/guides/source/api_app.md @@ -18,7 +18,7 @@ What is an API Application? Traditionally, when people said that they used Rails as an "API", they meant providing a programmatically accessible API alongside their web application. -For example, GitHub provides [an API](http://developer.github.com) that you +For example, GitHub provides [an API](https://developer.github.com) that you can use from your own custom clients. With the advent of client-side frameworks, more developers are using Rails to @@ -94,7 +94,7 @@ Handled at the Action Pack layer: means not having to spend time thinking about how to model your API in terms of HTTP. - URL Generation: The flip side of routing is URL generation. A good API based - on HTTP includes URLs (see [the GitHub Gist API](http://developer.github.com/v3/gists/) + on HTTP includes URLs (see [the GitHub Gist API](https://developer.github.com/v3/gists/) for an example). - Header and Redirection Responses: `head :no_content` and `redirect_to user_url(current_user)` come in handy. Sure, you could manually diff --git a/guides/source/asset_pipeline.md b/guides/source/asset_pipeline.md index 383e972f74..f148cef24f 100644 --- a/guides/source/asset_pipeline.md +++ b/guides/source/asset_pipeline.md @@ -1069,7 +1069,7 @@ Customizing the Pipeline ### CSS Compression One of the options for compressing CSS is YUI. The [YUI CSS -compressor](http://yui.github.io/yuicompressor/css.html) provides +compressor](https://yui.github.io/yuicompressor/css.html) provides minification. The following line enables YUI compression, and requires the `yui-compressor` diff --git a/guides/source/autoloading_and_reloading_constants.md b/guides/source/autoloading_and_reloading_constants.md index 05743ee4ce..c62194faf4 100644 --- a/guides/source/autoloading_and_reloading_constants.md +++ b/guides/source/autoloading_and_reloading_constants.md @@ -475,12 +475,21 @@ it is (edited): ``` $ bin/rails r 'puts ActiveSupport::Dependencies.autoload_paths' .../app/assets +.../app/channels .../app/controllers +.../app/controllers/concerns .../app/helpers +.../app/jobs .../app/mailers .../app/models -.../app/controllers/concerns .../app/models/concerns +.../activestorage/app/assets +.../activestorage/app/controllers +.../activestorage/app/javascript +.../activestorage/app/jobs +.../activestorage/app/models +.../actioncable/app/assets +.../actionview/app/assets .../test/mailers/previews ``` diff --git a/guides/source/command_line.md b/guides/source/command_line.md index 8ae01286e4..2cd8e02a77 100644 --- a/guides/source/command_line.md +++ b/guides/source/command_line.md @@ -645,13 +645,16 @@ $ cat config/database.yml # Configure Using Gemfile # gem 'pg' # -development: +default: &default adapter: postgresql encoding: unicode + # For details on connection pooling, see Rails configuration guide + # http://guides.rubyonrails.org/configuring.html#database-pooling + pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> + +development: + <<: *default database: gitapp_development - pool: 5 - username: gitapp - password: ... ... ``` diff --git a/guides/source/contributing_to_ruby_on_rails.md b/guides/source/contributing_to_ruby_on_rails.md index 2f2962a3e6..959cd3ea1c 100644 --- a/guides/source/contributing_to_ruby_on_rails.md +++ b/guides/source/contributing_to_ruby_on_rails.md @@ -164,7 +164,7 @@ NOTE: The instructions are for Rails > 4. The Redcarpet Gem doesn't work with JR Translation efforts we know about (various versions): * **Italian**: [https://github.com/rixlabs/docrails](https://github.com/rixlabs/docrails) -* **Spanish**: [http://wiki.github.com/gramos/docrails](http://wiki.github.com/gramos/docrails) +* **Spanish**: [https://wiki.github.com/gramos/docrails](https://wiki.github.com/gramos/docrails) * **Polish**: [https://github.com/apohllo/docrails/tree/master](https://github.com/apohllo/docrails/tree/master) * **French** : [https://github.com/railsfrance/docrails](https://github.com/railsfrance/docrails) * **Czech** : [https://github.com/rubyonrails-cz/docrails/tree/czech](https://github.com/rubyonrails-cz/docrails/tree/czech) @@ -324,7 +324,7 @@ file. #### Testing Active Record -First, create the databases you'll need. You can find a list of the required +First, create the databases you'll need. You can find a list of the required table names, usernames, and passwords in `activerecord/test/config.example.yml`. For MySQL and PostgreSQL, running the SQL statements `create database diff --git a/guides/source/debugging_rails_applications.md b/guides/source/debugging_rails_applications.md index 7ea3646c30..99bc7c5fb5 100644 --- a/guides/source/debugging_rails_applications.md +++ b/guides/source/debugging_rails_applications.md @@ -186,21 +186,17 @@ end Here's an example of the log generated when this controller action is executed: ``` -Processing ArticlesController#create (for 127.0.0.1 at 2008-09-08 11:52:54) [POST] - Session ID: BAh7BzoMY3NyZl9pZCIlMDY5MWU1M2I1ZDRjODBlMzkyMWI1OTg2NWQyNzViZjYiCmZsYXNoSUM6J0FjdGl -vbkNvbnRyb2xsZXI6OkZsYXNoOjpGbGFzaEhhc2h7AAY6CkB1c2VkewA=--b18cd92fba90eacf8137e5f6b3b06c4d724596a4 - Parameters: {"commit"=>"Create", "article"=>{"title"=>"Debugging Rails", - "body"=>"I'm learning how to print in logs!!!", "published"=>"0"}, - "authenticity_token"=>"2059c1286e93402e389127b1153204e0d1e275dd", "action"=>"create", "controller"=>"articles"} -New article: {"updated_at"=>nil, "title"=>"Debugging Rails", "body"=>"I'm learning how to print in logs!!!", - "published"=>false, "created_at"=>nil} +Started POST "/articles" for 127.0.0.1 at 2017-08-20 20:53:10 +0900 +Processing by ArticlesController#create as HTML + Parameters: {"utf8"=>"✓", "authenticity_token"=>"xhuIbSBFytHCE1agHgvrlKnSVIOGD6jltW2tO+P6a/ACjQ3igjpV4OdbsZjIhC98QizWH9YdKokrqxBCJrtoqQ==", "article"=>{"title"=>"Debugging Rails", "body"=>"I'm learning how to print in logs!!!", "published"=>"0"}, "commit"=>"Create Article"} +New article: {"id"=>nil, "title"=>"Debugging Rails", "body"=>"I'm learning how to print in logs!!!", "published"=>false, "created_at"=>nil, "updated_at"=>nil} Article should be valid: true - Article Create (0.000443) INSERT INTO "articles" ("updated_at", "title", "body", "published", - "created_at") VALUES('2008-09-08 14:52:54', 'Debugging Rails', - 'I''m learning how to print in logs!!!', 'f', '2008-09-08 14:52:54') + (0.1ms) BEGIN + SQL (0.4ms) INSERT INTO "articles" ("title", "body", "published", "created_at", "updated_at") VALUES ($1, $2, $3, $4, $5) RETURNING "id" [["title", "Debugging Rails"], ["body", "I'm learning how to print in logs!!!"], ["published", "f"], ["created_at", "2017-08-20 11:53:10.010435"], ["updated_at", "2017-08-20 11:53:10.010435"]] + (0.3ms) COMMIT The article was saved and now the user is going to be redirected... -Redirected to # Article:0x20af760> -Completed in 0.01224 (81 reqs/sec) | DB: 0.00044 (3%) | 302 Found [http://localhost/articles] +Redirected to http://localhost:3000/articles/1 +Completed 302 Found in 4ms (ActiveRecord: 0.8ms) ``` Adding extra logging like this makes it easy to search for unexpected or unusual behavior in your logs. If you add extra logging, be sure to make sensible use of log levels to avoid filling your production logs with useless trivia. diff --git a/guides/source/development_dependencies_install.md b/guides/source/development_dependencies_install.md index 77b036b20f..5a9729bb0f 100644 --- a/guides/source/development_dependencies_install.md +++ b/guides/source/development_dependencies_install.md @@ -30,7 +30,7 @@ Ruby on Rails uses Git for source code control. The [Git homepage](https://git-s * [Try Git course](https://try.github.io/) is an interactive course that will teach you the basics. * The [official Documentation](https://git-scm.com/documentation) is pretty comprehensive and also contains some videos with the basics of Git. -* [Everyday Git](http://schacon.github.io/git/everyday.html) will teach you just enough about Git to get by. +* [Everyday Git](https://schacon.github.io/git/everyday.html) will teach you just enough about Git to get by. * [GitHub](https://help.github.com/) offers links to a variety of Git resources. * [Pro Git](https://git-scm.com/book) is an entire book about Git with a Creative Commons license. @@ -364,7 +364,7 @@ sudo apt-get update && sudo apt-get install yarn On Fedora or CentOS, just run: -``bash +```bash sudo wget https://dl.yarnpkg.com/rpm/yarn.repo -O /etc/yum.repos.d/yarn.repo sudo yum install yarn diff --git a/guides/source/initialization.md b/guides/source/initialization.md index ccad10f07d..0cfabe2a66 100644 --- a/guides/source/initialization.md +++ b/guides/source/initialization.md @@ -99,13 +99,15 @@ configure the load path for your Gemfile's dependencies. A standard Rails application depends on several gems, specifically: +* actioncable * actionmailer * actionpack * actionview +* activejob * activemodel * activerecord +* activestorage * activesupport -* activejob * arel * builder * bundler @@ -131,7 +133,7 @@ Once `config/boot.rb` has finished, the next file that is required is `ARGV` array simply contains `server` which will be passed over: ```ruby -require "rails/command" +require_relative "command" aliases = { "g" => "generate", @@ -170,7 +172,7 @@ module Rails::Command namespace = namespace.to_s namespace = "help" if namespace.blank? || HELP_MAPPINGS.include?(namespace) namespace = "version" if %w( -v --version ).include? namespace - + if command = find_by_namespace(namespace) command.perform(namespace, args, config) else @@ -189,7 +191,7 @@ module Rails class ServerCommand < Base # :nodoc: def perform set_application_directory! - + Rails::Server.new.tap do |server| # Require application after server sets environment to propagate # the --environment option. @@ -311,7 +313,7 @@ def parse!(args) args, options = args.dup, {} option_parser(options).parse! args - + options[:log_stdout] = options[:daemonize].blank? && (options[:environment] || Rails.env) == "development" options[:server] = args.shift options @@ -366,11 +368,11 @@ private def log_to_stdout wrapped_app # touch the app so the logger is set up - + console = ActiveSupport::Logger.new(STDOUT) console.formatter = Rails.logger.formatter console.level = Rails.logger.level - + unless ActiveSupport::Logger.logger_outputs_to?(Rails.logger, STDOUT) Rails.logger.extend(ActiveSupport::Logger.broadcast(console)) end @@ -537,6 +539,7 @@ require "rails" action_mailer/railtie active_job/railtie action_cable/engine + active_storage/engine rails/test_unit/railtie sprockets/railtie ).each do |railtie| diff --git a/guides/source/rails_on_rack.md b/guides/source/rails_on_rack.md index cef8450ee4..00020a0ea5 100644 --- a/guides/source/rails_on_rack.md +++ b/guides/source/rails_on_rack.md @@ -302,7 +302,7 @@ Resources ### Learning Rack -* [Official Rack Website](http://rack.github.io) +* [Official Rack Website](https://rack.github.io) * [Introducing Rack](http://chneukirchen.org/blog/archive/2007/02/introducing-rack.html) ### Understanding Middlewares diff --git a/guides/source/security.md b/guides/source/security.md index 56969c7aea..7736a4b224 100644 --- a/guides/source/security.md +++ b/guides/source/security.md @@ -1025,7 +1025,7 @@ Here is a list of common headers: * **X-Content-Type-Options:** _'nosniff' in Rails by default_ - stops the browser from guessing the MIME type of a file. * **X-Content-Security-Policy:** [A powerful mechanism for controlling which sites certain content types can be loaded from](http://w3c.github.io/webappsec/specs/content-security-policy/csp-specification.dev.html) * **Access-Control-Allow-Origin:** Used to control which sites are allowed to bypass same origin policies and send cross-origin requests. -* **Strict-Transport-Security:** [Used to control if the browser is allowed to only access a site over a secure connection](http://en.wikipedia.org/wiki/HTTP_Strict_Transport_Security) +* **Strict-Transport-Security:** [Used to control if the browser is allowed to only access a site over a secure connection](https://en.wikipedia.org/wiki/HTTP_Strict_Transport_Security) Environmental Security ---------------------- @@ -1060,7 +1060,7 @@ Additional Resources The security landscape shifts and it is important to keep up to date, because missing a new vulnerability can be catastrophic. You can find additional resources about (Rails) security here: -* Subscribe to the Rails security [mailing list](http://groups.google.com/group/rubyonrails-security). -* [Brakeman - Rails Security Scanner](http://brakemanscanner.org/) - To perform static security analysis for Rails applications. +* Subscribe to the Rails security [mailing list](https://groups.google.com/forum/#!forum/rubyonrails-security). +* [Brakeman - Rails Security Scanner](https://brakemanscanner.org/) - To perform static security analysis for Rails applications. * [Keep up to date on the other application layers](http://secunia.com/) (they have a weekly newsletter, too). * A [good security blog](https://www.owasp.org) including the [Cross-Site scripting Cheat Sheet](https://www.owasp.org/index.php/DOM_based_XSS_Prevention_Cheat_Sheet). diff --git a/railties/lib/rails/test_unit/line_filtering.rb b/railties/lib/rails/test_unit/line_filtering.rb index e8b891d07b..f8ca77fe4a 100644 --- a/railties/lib/rails/test_unit/line_filtering.rb +++ b/railties/lib/rails/test_unit/line_filtering.rb @@ -1,6 +1,5 @@ # frozen_string_literal: true -require "method_source" require "rails/test_unit/runner" module Rails |