diff options
45 files changed, 312 insertions, 158 deletions
diff --git a/actioncable/lib/action_cable/subscription_adapter.rb b/actioncable/lib/action_cable/subscription_adapter.rb index 72e62f3daf..596269ab9b 100644 --- a/actioncable/lib/action_cable/subscription_adapter.rb +++ b/actioncable/lib/action_cable/subscription_adapter.rb @@ -4,5 +4,6 @@ module ActionCable autoload :Base autoload :SubscriberMap + autoload :ChannelPrefix end end diff --git a/actioncable/lib/action_cable/subscription_adapter/channel_prefix.rb b/actioncable/lib/action_cable/subscription_adapter/channel_prefix.rb new file mode 100644 index 0000000000..8b293cc785 --- /dev/null +++ b/actioncable/lib/action_cable/subscription_adapter/channel_prefix.rb @@ -0,0 +1,26 @@ +module ActionCable + module SubscriptionAdapter + module ChannelPrefix # :nodoc: + def broadcast(channel, payload) + channel = channel_with_prefix(channel) + super + end + + def subscribe(channel, callback, success_callback = nil) + channel = channel_with_prefix(channel) + super + end + + def unsubscribe(channel, callback) + channel = channel_with_prefix(channel) + super + end + + private + # Returns the channel name, including channel_prefix specified in cable.yml + def channel_with_prefix(channel) + [@server.config.cable[:channel_prefix], channel].compact.join(":") + end + end + end +end diff --git a/actioncable/lib/action_cable/subscription_adapter/evented_redis.rb b/actioncable/lib/action_cable/subscription_adapter/evented_redis.rb index c3018c5281..56b068976b 100644 --- a/actioncable/lib/action_cable/subscription_adapter/evented_redis.rb +++ b/actioncable/lib/action_cable/subscription_adapter/evented_redis.rb @@ -11,6 +11,8 @@ EventMachine.kqueue if EventMachine.kqueue? module ActionCable module SubscriptionAdapter class EventedRedis < Base # :nodoc: + prepend ChannelPrefix + @@mutex = Mutex.new # Overwrite this factory method for EventMachine Redis connections if you want to use a different Redis connection library than EM::Hiredis. diff --git a/actioncable/lib/action_cable/subscription_adapter/redis.rb b/actioncable/lib/action_cable/subscription_adapter/redis.rb index 62bd284a6b..41a6e55822 100644 --- a/actioncable/lib/action_cable/subscription_adapter/redis.rb +++ b/actioncable/lib/action_cable/subscription_adapter/redis.rb @@ -6,6 +6,8 @@ require "redis" module ActionCable module SubscriptionAdapter class Redis < Base # :nodoc: + prepend ChannelPrefix + # Overwrite this factory method for redis connections if you want to use a different Redis library than Redis. # This is needed, for example, when using Makara proxies for distributed Redis. cattr_accessor(:redis_connector) { ->(config) { ::Redis.new(url: config[:url]) } } diff --git a/actioncable/test/subscription_adapter/channel_prefix.rb b/actioncable/test/subscription_adapter/channel_prefix.rb new file mode 100644 index 0000000000..9ad659912e --- /dev/null +++ b/actioncable/test/subscription_adapter/channel_prefix.rb @@ -0,0 +1,36 @@ +require "test_helper" + +class ActionCable::Server::WithIndependentConfig < ActionCable::Server::Base + # ActionCable::Server::Base defines config as a class variable. + # Need config to be an instance variable here as we're testing 2 separate configs + def config + @config ||= ActionCable::Server::Configuration.new + end +end + +module ChannelPrefixTest + def test_channel_prefix + server2 = ActionCable::Server::WithIndependentConfig.new + server2.config.cable = alt_cable_config + server2.config.logger = Logger.new(StringIO.new).tap { |l| l.level = Logger::UNKNOWN } + + adapter_klass = server2.config.pubsub_adapter + + rx_adapter2 = adapter_klass.new(server2) + tx_adapter2 = adapter_klass.new(server2) + + subscribe_as_queue("channel") do |queue| + subscribe_as_queue("channel", rx_adapter2) do |queue2| + @tx_adapter.broadcast("channel", "hello world") + tx_adapter2.broadcast("channel", "hello world 2") + + assert_equal "hello world", queue.pop + assert_equal "hello world 2", queue2.pop + end + end + end + + def alt_cable_config + cable_config.merge(channel_prefix: "foo") + end +end diff --git a/actioncable/test/subscription_adapter/evented_redis_test.rb b/actioncable/test/subscription_adapter/evented_redis_test.rb index 2401950aa7..c55d35848e 100644 --- a/actioncable/test/subscription_adapter/evented_redis_test.rb +++ b/actioncable/test/subscription_adapter/evented_redis_test.rb @@ -1,8 +1,10 @@ require "test_helper" require_relative "./common" +require_relative "./channel_prefix" class EventedRedisAdapterTest < ActionCable::TestCase include CommonSubscriptionAdapterTest + include ChannelPrefixTest def setup super diff --git a/actioncable/test/subscription_adapter/redis_test.rb b/actioncable/test/subscription_adapter/redis_test.rb index 2ba5636656..4df5e0cbcd 100644 --- a/actioncable/test/subscription_adapter/redis_test.rb +++ b/actioncable/test/subscription_adapter/redis_test.rb @@ -1,8 +1,10 @@ require "test_helper" require_relative "./common" +require_relative "./channel_prefix" class RedisAdapterTest < ActionCable::TestCase include CommonSubscriptionAdapterTest + include ChannelPrefixTest def cable_config { adapter: "redis", driver: "ruby", url: "redis://127.0.0.1:6379/12" } diff --git a/actionpack/test/controller/parameters/parameters_permit_test.rb b/actionpack/test/controller/parameters/parameters_permit_test.rb index 82d7530e9f..8920914af1 100644 --- a/actionpack/test/controller/parameters/parameters_permit_test.rb +++ b/actionpack/test/controller/parameters/parameters_permit_test.rb @@ -66,12 +66,20 @@ class ParametersPermitTest < ActiveSupport::TestCase values.each do |value| params = ActionController::Parameters.new(id: value) permitted = params.permit(:id) - assert_equal value, permitted[:id] + if value.nil? + assert_nil permitted[:id] + else + assert_equal value, permitted[:id] + end @struct_fields.each do |sf| params = ActionController::Parameters.new(sf => value) permitted = params.permit(:sf) - assert_equal value, permitted[sf] + if value.nil? + assert_nil permitted[sf] + else + assert_equal value, permitted[sf] + end end end end diff --git a/actionpack/test/controller/request/test_request_test.rb b/actionpack/test/controller/request/test_request_test.rb index b67ae72c0a..1440db00f6 100644 --- a/actionpack/test/controller/request/test_request_test.rb +++ b/actionpack/test/controller/request/test_request_test.rb @@ -21,16 +21,20 @@ class ActionController::TestRequestTest < ActionController::TestCase @request.get_header("CONTENT_LENGTH")) end - ActionDispatch::Session::AbstractStore::DEFAULT_OPTIONS.each_key do |option| - test "rack default session options #{option} exists in session options and is default" do - assert_equal(ActionDispatch::Session::AbstractStore::DEFAULT_OPTIONS[option], - @request.session_options[option], - "Missing rack session default option #{option} in request.session_options") + ActionDispatch::Session::AbstractStore::DEFAULT_OPTIONS.each_pair do |key, value| + test "rack default session options #{key} exists in session options and is default" do + if value.nil? + assert_nil(@request.session_options[key], + "Missing rack session default option #{key} in request.session_options") + else + assert_equal(value, @request.session_options[key], + "Missing rack session default option #{key} in request.session_options") + end end - test "rack default session options #{option} exists in session options" do - assert(@request.session_options.has_key?(option), - "Missing rack session option #{option} in request.session_options") + test "rack default session options #{key} exists in session options" do + assert(@request.session_options.has_key?(key), + "Missing rack session option #{key} in request.session_options") end end end diff --git a/actionpack/test/dispatch/prefix_generation_test.rb b/actionpack/test/dispatch/prefix_generation_test.rb index bb2fc53add..0e093d2188 100644 --- a/actionpack/test/dispatch/prefix_generation_test.rb +++ b/actionpack/test/dispatch/prefix_generation_test.rb @@ -22,8 +22,6 @@ module TestGenerationPrefix end class WithMountedEngine < ActionDispatch::IntegrationTest - include Rack::Test::Methods - class BlogEngine < Rails::Engine routes.draw do get "/posts/:id", to: "inside_engine_generating#show", as: :post @@ -153,114 +151,114 @@ module TestGenerationPrefix # Inside Engine test "[ENGINE] generating engine's url use SCRIPT_NAME from request" do get "/pure-awesomeness/blog/posts/1" - assert_equal "/pure-awesomeness/blog/posts/1", last_response.body + assert_equal "/pure-awesomeness/blog/posts/1", response.body end test "[ENGINE] generating application's url never uses SCRIPT_NAME from request" do get "/pure-awesomeness/blog/url_to_application" - assert_equal "/generate", last_response.body + assert_equal "/generate", response.body end test "[ENGINE] generating engine's url with polymorphic path" do get "/pure-awesomeness/blog/polymorphic_path_for_engine" - assert_equal "/pure-awesomeness/blog/posts/1", last_response.body + assert_equal "/pure-awesomeness/blog/posts/1", response.body end test "[ENGINE] url_helpers from engine have higher priority than application's url_helpers" do get "/awesome/blog/conflicting_url" - assert_equal "engine", last_response.body + assert_equal "engine", response.body end test "[ENGINE] relative path root uses SCRIPT_NAME from request" do get "/awesome/blog/relative_path_root" - verify_redirect "http://example.org/awesome/blog" + verify_redirect "http://www.example.com/awesome/blog" end test "[ENGINE] relative path redirect uses SCRIPT_NAME from request" do get "/awesome/blog/relative_path_redirect" - verify_redirect "http://example.org/awesome/blog/foo" + verify_redirect "http://www.example.com/awesome/blog/foo" end test "[ENGINE] relative option root uses SCRIPT_NAME from request" do get "/awesome/blog/relative_option_root" - verify_redirect "http://example.org/awesome/blog" + verify_redirect "http://www.example.com/awesome/blog" end test "[ENGINE] relative option redirect uses SCRIPT_NAME from request" do get "/awesome/blog/relative_option_redirect" - verify_redirect "http://example.org/awesome/blog/foo" + verify_redirect "http://www.example.com/awesome/blog/foo" end test "[ENGINE] relative custom root uses SCRIPT_NAME from request" do get "/awesome/blog/relative_custom_root" - verify_redirect "http://example.org/awesome/blog" + verify_redirect "http://www.example.com/awesome/blog" end test "[ENGINE] relative custom redirect uses SCRIPT_NAME from request" do get "/awesome/blog/relative_custom_redirect" - verify_redirect "http://example.org/awesome/blog/foo" + verify_redirect "http://www.example.com/awesome/blog/foo" end test "[ENGINE] absolute path root doesn't use SCRIPT_NAME from request" do get "/awesome/blog/absolute_path_root" - verify_redirect "http://example.org/" + verify_redirect "http://www.example.com/" end test "[ENGINE] absolute path redirect doesn't use SCRIPT_NAME from request" do get "/awesome/blog/absolute_path_redirect" - verify_redirect "http://example.org/foo" + verify_redirect "http://www.example.com/foo" end test "[ENGINE] absolute option root doesn't use SCRIPT_NAME from request" do get "/awesome/blog/absolute_option_root" - verify_redirect "http://example.org/" + verify_redirect "http://www.example.com/" end test "[ENGINE] absolute option redirect doesn't use SCRIPT_NAME from request" do get "/awesome/blog/absolute_option_redirect" - verify_redirect "http://example.org/foo" + verify_redirect "http://www.example.com/foo" end test "[ENGINE] absolute custom root doesn't use SCRIPT_NAME from request" do get "/awesome/blog/absolute_custom_root" - verify_redirect "http://example.org/" + verify_redirect "http://www.example.com/" end test "[ENGINE] absolute custom redirect doesn't use SCRIPT_NAME from request" do get "/awesome/blog/absolute_custom_redirect" - verify_redirect "http://example.org/foo" + verify_redirect "http://www.example.com/foo" end # Inside Application test "[APP] generating engine's route includes prefix" do get "/generate" - assert_equal "/awesome/blog/posts/1", last_response.body + assert_equal "/awesome/blog/posts/1", response.body end test "[APP] generating engine's route includes default_url_options[:script_name]" do RailsApplication.routes.default_url_options = { script_name: "/something" } get "/generate" - assert_equal "/something/awesome/blog/posts/1", last_response.body + assert_equal "/something/awesome/blog/posts/1", response.body end test "[APP] generating engine's url with polymorphic path" do get "/polymorphic_path_for_engine" - assert_equal "/awesome/blog/posts/1", last_response.body + assert_equal "/awesome/blog/posts/1", response.body end test "polymorphic_path_for_app" do get "/polymorphic_path_for_app" - assert_equal "/posts/1", last_response.body + assert_equal "/posts/1", response.body end test "[APP] generating engine's url with url_for(@post)" do get "/polymorphic_with_url_for" - assert_equal "http://example.org/awesome/blog/posts/1", last_response.body + assert_equal "http://www.example.com/awesome/blog/posts/1", response.body end test "[APP] instance variable with same name as engine" do get "/ivar_usage" - assert_equal "/awesome/blog/posts/1", last_response.body + assert_equal "/awesome/blog/posts/1", response.body end # Inside any Object @@ -322,9 +320,9 @@ module TestGenerationPrefix private def verify_redirect(url, status = 301) - assert_equal status, last_response.status - assert_equal url, last_response.headers["Location"] - assert_equal expected_redirect_body(url), last_response.body + assert_equal status, response.status + assert_equal url, response.headers["Location"] + assert_equal expected_redirect_body(url), response.body end def expected_redirect_body(url) @@ -333,8 +331,6 @@ module TestGenerationPrefix end class EngineMountedAtRoot < ActionDispatch::IntegrationTest - include Rack::Test::Methods - class BlogEngine def self.routes @routes ||= begin @@ -388,74 +384,74 @@ module TestGenerationPrefix test "generating path inside engine" do get "/posts/1" - assert_equal "/posts/1", last_response.body + assert_equal "/posts/1", response.body end test "[ENGINE] relative path root uses SCRIPT_NAME from request" do get "/relative_path_root" - verify_redirect "http://example.org/" + verify_redirect "http://www.example.com/" end test "[ENGINE] relative path redirect uses SCRIPT_NAME from request" do get "/relative_path_redirect" - verify_redirect "http://example.org/foo" + verify_redirect "http://www.example.com/foo" end test "[ENGINE] relative option root uses SCRIPT_NAME from request" do get "/relative_option_root" - verify_redirect "http://example.org/" + verify_redirect "http://www.example.com/" end test "[ENGINE] relative option redirect uses SCRIPT_NAME from request" do get "/relative_option_redirect" - verify_redirect "http://example.org/foo" + verify_redirect "http://www.example.com/foo" end test "[ENGINE] relative custom root uses SCRIPT_NAME from request" do get "/relative_custom_root" - verify_redirect "http://example.org/" + verify_redirect "http://www.example.com/" end test "[ENGINE] relative custom redirect uses SCRIPT_NAME from request" do get "/relative_custom_redirect" - verify_redirect "http://example.org/foo" + verify_redirect "http://www.example.com/foo" end test "[ENGINE] absolute path root doesn't use SCRIPT_NAME from request" do get "/absolute_path_root" - verify_redirect "http://example.org/" + verify_redirect "http://www.example.com/" end test "[ENGINE] absolute path redirect doesn't use SCRIPT_NAME from request" do get "/absolute_path_redirect" - verify_redirect "http://example.org/foo" + verify_redirect "http://www.example.com/foo" end test "[ENGINE] absolute option root doesn't use SCRIPT_NAME from request" do get "/absolute_option_root" - verify_redirect "http://example.org/" + verify_redirect "http://www.example.com/" end test "[ENGINE] absolute option redirect doesn't use SCRIPT_NAME from request" do get "/absolute_option_redirect" - verify_redirect "http://example.org/foo" + verify_redirect "http://www.example.com/foo" end test "[ENGINE] absolute custom root doesn't use SCRIPT_NAME from request" do get "/absolute_custom_root" - verify_redirect "http://example.org/" + verify_redirect "http://www.example.com/" end test "[ENGINE] absolute custom redirect doesn't use SCRIPT_NAME from request" do get "/absolute_custom_redirect" - verify_redirect "http://example.org/foo" + verify_redirect "http://www.example.com/foo" end private def verify_redirect(url, status = 301) - assert_equal status, last_response.status - assert_equal url, last_response.headers["Location"] - assert_equal expected_redirect_body(url), last_response.body + assert_equal status, response.status + assert_equal url, response.headers["Location"] + assert_equal expected_redirect_body(url), response.body end def expected_redirect_body(url) diff --git a/actionpack/test/dispatch/ssl_test.rb b/actionpack/test/dispatch/ssl_test.rb index 53b99ebbc4..757e26973f 100644 --- a/actionpack/test/dispatch/ssl_test.rb +++ b/actionpack/test/dispatch/ssl_test.rb @@ -102,7 +102,11 @@ class StrictTransportSecurityTest < SSLTest def assert_hsts(expected, url: "https://example.org", hsts: { subdomains: true }, headers: {}) self.app = build_app ssl_options: { hsts: hsts }, headers: headers get url - assert_equal expected, response.headers["Strict-Transport-Security"] + if expected.nil? + assert_nil response.headers["Strict-Transport-Security"] + else + assert_equal expected, response.headers["Strict-Transport-Security"] + end end test "enabled by default" do diff --git a/actionview/lib/action_view/helpers/asset_url_helper.rb b/actionview/lib/action_view/helpers/asset_url_helper.rb index bdabaed85c..03bd1eb008 100644 --- a/actionview/lib/action_view/helpers/asset_url_helper.rb +++ b/actionview/lib/action_view/helpers/asset_url_helper.rb @@ -237,7 +237,11 @@ module ActionView def compute_asset_extname(source, options = {}) return if options[:extname] == false extname = options[:extname] || ASSET_EXTENSIONS[options[:type]] - extname if extname && File.extname(source) != extname + if extname && File.extname(source) != extname + extname + else + nil + end end # Maps asset types to public directory. diff --git a/actionview/lib/action_view/helpers/output_safety_helper.rb b/actionview/lib/action_view/helpers/output_safety_helper.rb index e9febb8be9..25defd1276 100644 --- a/actionview/lib/action_view/helpers/output_safety_helper.rb +++ b/actionview/lib/action_view/helpers/output_safety_helper.rb @@ -60,7 +60,7 @@ module ActionView #:nodoc: when 2 safe_join([array[0], array[1]], options[:two_words_connector]) else - safe_join([safe_join(array[0...-1], options[:words_connector]), options[:last_word_connector], array[-1]]) + safe_join([safe_join(array[0...-1], options[:words_connector]), options[:last_word_connector], array[-1]], nil) end end end diff --git a/actionview/lib/action_view/renderer/partial_renderer.rb b/actionview/lib/action_view/renderer/partial_renderer.rb index af3df52b28..2bb4465131 100644 --- a/actionview/lib/action_view/renderer/partial_renderer.rb +++ b/actionview/lib/action_view/renderer/partial_renderer.rb @@ -99,7 +99,7 @@ module ActionView # <%= render partial: "ad", collection: @advertisements, spacer_template: "ad_divider" %> # # If the given <tt>:collection</tt> is +nil+ or empty, <tt>render</tt> will return nil. This will allow you - # to specify a text which will displayed instead by using this form: + # to specify a text which will be displayed instead by using this form: # # <%= render(partial: "ad", collection: @advertisements) || "There's no ad to be displayed" %> # diff --git a/actionview/lib/action_view/renderer/streaming_template_renderer.rb b/actionview/lib/action_view/renderer/streaming_template_renderer.rb index 7ede034492..62ce985243 100644 --- a/actionview/lib/action_view/renderer/streaming_template_renderer.rb +++ b/actionview/lib/action_view/renderer/streaming_template_renderer.rb @@ -4,7 +4,6 @@ module ActionView # == TODO # # * Support streaming from child templates, partials and so on. - # * Integrate exceptions with exceptron # * Rack::Cache needs to support streaming bodies class StreamingTemplateRenderer < TemplateRenderer #:nodoc: # A valid Rack::Body (i.e. it responds to each). @@ -28,7 +27,6 @@ module ActionView private # This is the same logging logic as in ShowExceptions middleware. - # TODO Once "exceptron" is in, refactor this piece to simply re-use exceptron. def log_error(exception) logger = ActionView::Base.logger return unless logger diff --git a/actionview/test/template/erb_util_test.rb b/actionview/test/template/erb_util_test.rb index 0a16364ed3..4412ea37fa 100644 --- a/actionview/test/template/erb_util_test.rb +++ b/actionview/test/template/erb_util_test.rb @@ -51,7 +51,12 @@ class ErbUtilTest < ActiveSupport::TestCase def test_json_escape_does_not_alter_json_string_meaning JSON_ESCAPE_TEST_CASES.each do |(raw, _)| - assert_equal ActiveSupport::JSON.decode(raw), ActiveSupport::JSON.decode(json_escape(raw)) + expected = ActiveSupport::JSON.decode(raw) + if expected.nil? + assert_nil ActiveSupport::JSON.decode(json_escape(raw)) + else + assert_equal expected, ActiveSupport::JSON.decode(json_escape(raw)) + end end end diff --git a/actionview/test/template/output_safety_helper_test.rb b/actionview/test/template/output_safety_helper_test.rb index 8691bb11ee..0f3288130b 100644 --- a/actionview/test/template/output_safety_helper_test.rb +++ b/actionview/test/template/output_safety_helper_test.rb @@ -33,6 +33,11 @@ class OutputSafetyHelperTest < ActionView::TestCase assert_equal ""a" <br/> <b> <br/> <c>", joined end + test "safe_join should return the safe string separated by $, when second argument is not passed" do + joined = safe_join(["a", "b"]) + assert_equal "a#{$,}b", joined + end + test "to_sentence should escape non-html_safe values" do actual = to_sentence(%w(< > & ' ")) assert actual.html_safe? @@ -87,4 +92,14 @@ class OutputSafetyHelperTest < ActionView::TestCase assert_equal "one, two three", to_sentence(["one", "two", "three"], last_word_connector: " ") assert_equal "one, two and three", to_sentence(["one", "two", "three"], last_word_connector: " and ") end + + test "to_sentence is not affected by $," do + $, = "|" + begin + assert_equal "one and two", to_sentence(["one", "two"]) + assert_equal "one, two, and three", to_sentence(["one", "two", "three"]) + ensure + $, = nil + end + end end diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md index 3d299f6233..4b8e8f555d 100644 --- a/activerecord/CHANGELOG.md +++ b/activerecord/CHANGELOG.md @@ -1,12 +1,21 @@ -* Place generated migrations into the path set by `config.paths["db/migrate"]` +* Support foreign key creation for SQLite3. + + *Ryuta Kamizono* + +* Remove `initialize_schema_migrations_table` and `initialize_internal_metadata_table` + internal public methods. + + *Ryuta Kamizono* + +* Place generated migrations into the path set by `config.paths["db/migrate"]`. *Kevin Glowacz* - -* Raise `ActiveRecord::InvalidForeignKey` when a foreign key constraint fails on Sqlite3. + +* Raise `ActiveRecord::InvalidForeignKey` when a foreign key constraint fails on SQLite3. *Ryuta Kamizono* -* Add the touch option to ActiveRecord#increment! and decrement! +* Add the touch option to ActiveRecord#increment! and decrement!. *Hiroaki Izu* @@ -15,9 +24,9 @@ *Kir Shatrov* -* Raise error when has_many through is defined before through association +* Raise error when has_many through is defined before through association. - Fixes #26834 + Fixes #26834. *Chris Holmes* @@ -428,7 +437,7 @@ *Ryuta Kamizono* -* Sqlite3 migrations to add a column to an existing table can now be +* SQLite3 migrations to add a column to an existing table can now be successfully rolled back when the column was given and invalid column type. diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb index 1bdc086380..95725cd883 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb @@ -1008,16 +1008,6 @@ module ActiveRecord end end - # Should not be called normally, but this operation is non-destructive. - # The migrations module handles this automatically. - def initialize_schema_migrations_table - ActiveRecord::SchemaMigration.create_table - end - - def initialize_internal_metadata_table - ActiveRecord::InternalMetadata.create_table - end - def internal_string_options_for_primary_key # :nodoc: { primary_key: true } end diff --git a/activerecord/lib/active_record/migration.rb b/activerecord/lib/active_record/migration.rb index 31c2397bc9..339332a60d 100644 --- a/activerecord/lib/active_record/migration.rb +++ b/activerecord/lib/active_record/migration.rb @@ -1107,8 +1107,8 @@ module ActiveRecord validate(@migrations) - Base.connection.initialize_schema_migrations_table - Base.connection.initialize_internal_metadata_table + ActiveRecord::SchemaMigration.create_table + ActiveRecord::InternalMetadata.create_table end def current_version diff --git a/activerecord/lib/active_record/schema.rb b/activerecord/lib/active_record/schema.rb index 7a2bc9c8af..5104427339 100644 --- a/activerecord/lib/active_record/schema.rb +++ b/activerecord/lib/active_record/schema.rb @@ -48,7 +48,7 @@ module ActiveRecord instance_eval(&block) if info[:version].present? - initialize_schema_migrations_table + ActiveRecord::SchemaMigration.create_table connection.assume_migrated_upto_version(info[:version], migrations_paths) end diff --git a/activerecord/test/cases/adapters/mysql2/schema_migrations_test.rb b/activerecord/test/cases/adapters/mysql2/schema_migrations_test.rb index fa54aac6b3..605baa9905 100644 --- a/activerecord/test/cases/adapters/mysql2/schema_migrations_test.rb +++ b/activerecord/test/cases/adapters/mysql2/schema_migrations_test.rb @@ -16,7 +16,7 @@ class SchemaMigrationsTest < ActiveRecord::Mysql2TestCase table_name = ActiveRecord::SchemaMigration.table_name connection.drop_table table_name, if_exists: true - connection.initialize_schema_migrations_table + ActiveRecord::SchemaMigration.create_table assert connection.column_exists?(table_name, :version, :string, collation: "utf8_general_ci") end @@ -27,7 +27,7 @@ class SchemaMigrationsTest < ActiveRecord::Mysql2TestCase table_name = ActiveRecord::InternalMetadata.table_name connection.drop_table table_name, if_exists: true - connection.initialize_internal_metadata_table + ActiveRecord::InternalMetadata.create_table assert connection.column_exists?(table_name, :key, :string, collation: "utf8_general_ci") end diff --git a/activerecord/test/cases/adapters/postgresql/infinity_test.rb b/activerecord/test/cases/adapters/postgresql/infinity_test.rb index 19b00258b6..2d73312864 100644 --- a/activerecord/test/cases/adapters/postgresql/infinity_test.rb +++ b/activerecord/test/cases/adapters/postgresql/infinity_test.rb @@ -30,7 +30,7 @@ class PostgresqlInfinityTest < ActiveRecord::PostgreSQLTestCase record = PostgresqlInfinity.new(float: "-Infinity") assert_equal(-Float::INFINITY, record.float) record = PostgresqlInfinity.new(float: "NaN") - assert_send [record.float, :nan?] + assert record.float.nan? end test "update_all with infinity on a float column" do diff --git a/activerecord/test/cases/adapters/postgresql/numbers_test.rb b/activerecord/test/cases/adapters/postgresql/numbers_test.rb index 834354dcc9..e5f1828065 100644 --- a/activerecord/test/cases/adapters/postgresql/numbers_test.rb +++ b/activerecord/test/cases/adapters/postgresql/numbers_test.rb @@ -31,7 +31,7 @@ class PostgresqlNumberTest < ActiveRecord::PostgreSQLTestCase assert_equal 123456.789, first.double assert_equal(-::Float::INFINITY, second.single) assert_equal ::Float::INFINITY, second.double - assert_send [third.double, :nan?] + assert third.double.nan? end def test_update diff --git a/activerecord/test/cases/adapters/sqlite3/copy_table_test.rb b/activerecord/test/cases/adapters/sqlite3/copy_table_test.rb index 91967c1e33..e1cfd703e8 100644 --- a/activerecord/test/cases/adapters/sqlite3/copy_table_test.rb +++ b/activerecord/test/cases/adapters/sqlite3/copy_table_test.rb @@ -41,8 +41,8 @@ class CopyTableTest < ActiveRecord::SQLite3TestCase test_copy_table("comments", "comments_with_index") do @connection.add_index("comments_with_index", ["post_id", "type"]) test_copy_table("comments_with_index", "comments_with_index2") do - assert_equal table_indexes_without_name("comments_with_index"), - table_indexes_without_name("comments_with_index2") + assert_nil table_indexes_without_name("comments_with_index") + assert_nil table_indexes_without_name("comments_with_index2") end end end @@ -59,7 +59,8 @@ class CopyTableTest < ActiveRecord::SQLite3TestCase copied_id = @connection.columns("goofy_string_id2").detect { |col| col.name == "id" } assert_equal original_id.type, copied_id.type assert_equal original_id.sql_type, copied_id.sql_type - assert_equal original_id.limit, copied_id.limit + assert_nil original_id.limit + assert_nil copied_id.limit end end diff --git a/activerecord/test/cases/associations/eager_test.rb b/activerecord/test/cases/associations/eager_test.rb index ff1bf8acd4..7d054b874b 100644 --- a/activerecord/test/cases/associations/eager_test.rb +++ b/activerecord/test/cases/associations/eager_test.rb @@ -933,7 +933,11 @@ class EagerAssociationTest < ActiveRecord::TestCase d2 = find_all_ordered(Firm, :account) d1.each_index do |i| assert_equal(d1[i], d2[i]) - assert_equal(d1[i].account, d2[i].account) + if d1[i].account.nil? + assert_nil(d2[i].account) + else + assert_equal(d1[i].account, d2[i].account) + end end end @@ -943,7 +947,13 @@ class EagerAssociationTest < ActiveRecord::TestCase d2 = find_all_ordered(Client, firm_types) d1.each_index do |i| assert_equal(d1[i], d2[i]) - firm_types.each { |type| assert_equal(d1[i].send(type), d2[i].send(type)) } + firm_types.each do |type| + if (expected = d1[i].send(type)).nil? + assert_nil(d2[i].send(type)) + else + assert_equal(expected, d2[i].send(type)) + end + end end end def test_eager_with_valid_association_as_string_not_symbol diff --git a/activerecord/test/cases/associations/inverse_associations_test.rb b/activerecord/test/cases/associations/inverse_associations_test.rb index 6fe6ee6783..287b3e9ebc 100644 --- a/activerecord/test/cases/associations/inverse_associations_test.rb +++ b/activerecord/test/cases/associations/inverse_associations_test.rb @@ -443,7 +443,7 @@ class InverseHasManyTests < ActiveRecord::TestCase assert man.equal?(man.interests.first.man), "Two inverses should lead back to the same object that was originally held" assert man.equal?(man.interests.find(interest.id).man), "Two inversions should lead back to the same object that was originally held" - assert_equal man.name, man.interests.find(interest.id).man.name, "The name of the man should match before the name is changed" + assert_nil man.interests.find(interest.id).man.name, "The name of the man should match before the name is changed" man.name = "Ben Bitdiddle" assert_equal man.name, man.interests.find(interest.id).man.name, "The name of the man should match after the parent name is changed" man.interests.find(interest.id).man.name = "Alyssa P. Hacker" diff --git a/activerecord/test/cases/migration_test.rb b/activerecord/test/cases/migration_test.rb index 4edb807bbb..c728cc9669 100644 --- a/activerecord/test/cases/migration_test.rb +++ b/activerecord/test/cases/migration_test.rb @@ -43,10 +43,10 @@ class MigrationTest < ActiveRecord::TestCase ActiveRecord::Base.table_name_prefix = "" ActiveRecord::Base.table_name_suffix = "" - ActiveRecord::Base.connection.initialize_schema_migrations_table - ActiveRecord::Base.connection.execute "DELETE FROM #{ActiveRecord::Migrator.schema_migrations_table_name}" + ActiveRecord::SchemaMigration.create_table + ActiveRecord::SchemaMigration.delete_all - %w(things awesome_things prefix_things_suffix p_awesome_things_s ).each do |table| + %w(things awesome_things prefix_things_suffix p_awesome_things_s).each do |table| Thing.connection.drop_table(table) rescue nil end Thing.reset_column_information diff --git a/activerecord/test/cases/query_cache_test.rb b/activerecord/test/cases/query_cache_test.rb index 93a67d0738..04e48e201e 100644 --- a/activerecord/test/cases/query_cache_test.rb +++ b/activerecord/test/cases/query_cache_test.rb @@ -442,6 +442,10 @@ end class QueryCacheExpiryTest < ActiveRecord::TestCase fixtures :tasks, :posts, :categories, :categories_posts + def teardown + Task.connection.clear_query_cache + end + def test_cache_gets_cleared_after_migration # warm the cache Post.find(1) diff --git a/activerecord/test/cases/transactions_test.rb b/activerecord/test/cases/transactions_test.rb index 9b1cca8583..8f9980f168 100644 --- a/activerecord/test/cases/transactions_test.rb +++ b/activerecord/test/cases/transactions_test.rb @@ -279,7 +279,11 @@ class TransactionTest < ActiveRecord::TestCase e = assert_raises(RuntimeError) { new_topic.save } assert_equal "Make the transaction rollback", e.message assert_equal new_record_snapshot, !new_topic.persisted?, "The topic should have its old persisted value" - assert_equal id_snapshot, new_topic.id, "The topic should have its old id" + if id_snapshot.nil? + assert_nil new_topic.id, "The topic should have its old id" + else + assert_equal id_snapshot, new_topic.id, "The topic should have its old id" + end assert_equal id_present, new_topic.has_attribute?(Topic.primary_key) end end diff --git a/activesupport/lib/active_support/core_ext/module/introspection.rb b/activesupport/lib/active_support/core_ext/module/introspection.rb index 0665aa88bc..ca20a6d4c5 100644 --- a/activesupport/lib/active_support/core_ext/module/introspection.rb +++ b/activesupport/lib/active_support/core_ext/module/introspection.rb @@ -5,10 +5,12 @@ class Module # # M::N.parent_name # => "M" def parent_name - if defined? @parent_name + if defined?(@parent_name) @parent_name else - @parent_name = name =~ /::[^:]+\Z/ ? $`.freeze : nil + parent_name = name =~ /::[^:]+\Z/ ? $`.freeze : nil + @parent_name = parent_name unless frozen? + parent_name end end diff --git a/activesupport/test/core_ext/kernel_test.rb b/activesupport/test/core_ext/kernel_test.rb index db0008b735..26f5088ede 100644 --- a/activesupport/test/core_ext/kernel_test.rb +++ b/activesupport/test/core_ext/kernel_test.rb @@ -49,19 +49,3 @@ class KernelSuppressTest < ActiveSupport::TestCase suppress(LoadError, ArgumentError) { raise ArgumentError } end end - -class MockStdErr - attr_reader :output - def puts(message) - @output ||= [] - @output << message - end - - def info(message) - puts(message) - end - - def write(message) - puts(message) - end -end diff --git a/activesupport/test/core_ext/module/introspection_test.rb b/activesupport/test/core_ext/module/introspection_test.rb new file mode 100644 index 0000000000..db383850cd --- /dev/null +++ b/activesupport/test/core_ext/module/introspection_test.rb @@ -0,0 +1,37 @@ +require "abstract_unit" +require "active_support/core_ext/module/introspection" + +module ParentA + module B + module C; end + module FrozenC; end + FrozenC.freeze + end + + module FrozenB; end + FrozenB.freeze +end + +class IntrospectionTest < ActiveSupport::TestCase + def test_parent_name + assert_equal "ParentA", ParentA::B.parent_name + assert_equal "ParentA::B", ParentA::B::C.parent_name + assert_nil ParentA.parent_name + end + + def test_parent_name_when_frozen + assert_equal "ParentA", ParentA::FrozenB.parent_name + assert_equal "ParentA::B", ParentA::B::FrozenC.parent_name + end + + def test_parent + assert_equal ParentA::B, ParentA::B::C.parent + assert_equal ParentA, ParentA::B.parent + assert_equal Object, ParentA.parent + end + + def test_parents + assert_equal [ParentA::B, ParentA, Object], ParentA::B::C.parents + assert_equal [ParentA, Object], ParentA::B.parents + end +end diff --git a/activesupport/test/core_ext/module_test.rb b/activesupport/test/core_ext/module_test.rb index 5906e5d3d2..a17438bf4d 100644 --- a/activesupport/test/core_ext/module_test.rb +++ b/activesupport/test/core_ext/module_test.rb @@ -1,25 +1,6 @@ require "abstract_unit" require "active_support/core_ext/module" -module One - Constant1 = "Hello World" - Constant2 = "What's up?" -end - -class Ab - include One - Constant1 = "Hello World" # Will have different object id than One::Constant1 - Constant3 = "Goodbye World" -end - -module Yz - module Zy - class Cd - include One - end - end -end - Somewhere = Struct.new(:street, :city) do attr_accessor :name end @@ -375,17 +356,6 @@ class ModuleTest < ActiveSupport::TestCase assert_match(/undefined method `my_fake_method' for/, e.message) end - def test_parent - assert_equal Yz::Zy, Yz::Zy::Cd.parent - assert_equal Yz, Yz::Zy.parent - assert_equal Object, Yz.parent - end - - def test_parents - assert_equal [Yz::Zy, Yz, Object], Yz::Zy::Cd.parents - assert_equal [Yz, Object], Yz::Zy.parents - end - def test_delegate_with_case event = Event.new(Tester.new) assert_equal 1, event.foo diff --git a/activesupport/test/evented_file_update_checker_test.rb b/activesupport/test/evented_file_update_checker_test.rb index 77d8dcb0f8..bb2ae4baa6 100644 --- a/activesupport/test/evented_file_update_checker_test.rb +++ b/activesupport/test/evented_file_update_checker_test.rb @@ -30,11 +30,6 @@ class EventedFileUpdateCheckerTest < ActiveSupport::TestCase wait # wait for the events to fire end - def rm_f(files) - super - wait - end - test "notifies forked processes" do jruby_skip "Forking not available on JRuby" diff --git a/guides/source/action_cable_overview.md b/guides/source/action_cable_overview.md index 319277ef68..e929945dd0 100644 --- a/guides/source/action_cable_overview.md +++ b/guides/source/action_cable_overview.md @@ -240,8 +240,8 @@ WebNotificationsChannel.broadcast_to( ``` The `WebNotificationsChannel.broadcast_to` call places a message in the current -subscription adapter (by default `redis` for production and `async` for development and -test environments)'s pubsub queue under a separate broadcasting name for each user. +subscription adapter (by default `redis` for production and `async` for development and +test environments)'s pubsub queue under a separate broadcasting name for each user. For a user with an ID of 1, the broadcasting name would be `web_notifications:1`. The channel has been instructed to stream everything that arrives at @@ -530,7 +530,7 @@ Action Cable has two required configurations: a subscription adapter and allowed ### Subscription Adapter By default, Action Cable looks for a configuration file in `config/cable.yml`. -The file must specify an adapter and a URL for each Rails environment. See the +The file must specify an adapter for each Rails environment. See the [Dependencies](#dependencies) section for additional information on adapters. ```yaml @@ -543,7 +543,28 @@ test: production: adapter: redis url: redis://10.10.3.153:6381 + channel_prefix: appname_production ``` +#### Adapter Configuration + +Below is a list of the subscription adapters available for end users. + +##### Async Adapter + +The async adapter is intended for development/testing and should not be used in production. + +##### Redis Adapter + +Action Cable contains two Redis adapters: "normal" Redis and Evented Redis. Both +of the adapters require users to provide a URL pointing to the Redis server. +Additionally, a channel_prefix may be provided to avoid channel name collisions +when using the same Redis server for multiple applications. See the [Redis PubSub documentation](https://redis.io/topics/pubsub#database-amp-scoping) for more details. + +##### PostgreSQL Adapter + +The PostgreSQL adapter uses Active Record's connection pool, and thus the +application's `config/database.yml` database configuration, for its connection. +This may change in the future. [#27214](https://github.com/rails/rails/issues/27214) ### Allowed Request Origins diff --git a/guides/source/i18n.md b/guides/source/i18n.md index df5869f9ca..4db6e3e195 100644 --- a/guides/source/i18n.md +++ b/guides/source/i18n.md @@ -672,7 +672,7 @@ end ### Pluralization -In English there are only one singular and one plural form for a given string, e.g. "1 message" and "2 messages". Other languages ([Arabic](http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/language_plural_rules.html#ar), [Japanese](http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/language_plural_rules.html#ja), [Russian](http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/language_plural_rules.html#ru) and many more) have different grammars that have additional or fewer [plural forms](http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/language_plural_rules.html). Thus, the I18n API provides a flexible pluralization feature. +In English there are only one singular and one plural form for a given string, e.g. "1 message" and "2 messages". Other languages ([Arabic](http://www.unicode.org/cldr/charts/latest/supplemental/language_plural_rules.html#ar), [Japanese](http://www.unicode.org/cldr/charts/latest/supplemental/language_plural_rules.html#ja), [Russian](http://www.unicode.org/cldr/charts/latest/supplemental/language_plural_rules.html#ru) and many more) have different grammars that have additional or fewer [plural forms](http://cldr.unicode.org/index/cldr-spec/plural-rules). Thus, the I18n API provides a flexible pluralization feature. The `:count` interpolation variable has a special role in that it both is interpolated to the translation and used to pick a pluralization from the translations according to the pluralization rules defined by CLDR: diff --git a/railties/CHANGELOG.md b/railties/CHANGELOG.md index 1f259ab326..9df6194b9b 100644 --- a/railties/CHANGELOG.md +++ b/railties/CHANGELOG.md @@ -1,3 +1,8 @@ +* Initialize git repo when generating new app, if option `--skip-git` + is not provided. + + *Dino Maric* + * Install Byebug gem as default in Windows (mingw and x64_mingw) platform. *Junichi Ito* diff --git a/railties/lib/rails/generators/rails/app/app_generator.rb b/railties/lib/rails/generators/rails/app/app_generator.rb index 8efdfdcb44..bdeebbb8b5 100644 --- a/railties/lib/rails/generators/rails/app/app_generator.rb +++ b/railties/lib/rails/generators/rails/app/app_generator.rb @@ -53,6 +53,12 @@ module Rails template "gitignore", ".gitignore" end + def version_control + unless options[:skip_git] + run "git init" + end + end + def app directory "app" @@ -205,6 +211,7 @@ module Rails build(:configru) build(:gitignore) unless options[:skip_git] build(:gemfile) unless options[:skip_gemfile] + build(:version_control) end def create_app_files diff --git a/railties/lib/rails/generators/rails/app/templates/config/cable.yml b/railties/lib/rails/generators/rails/app/templates/config/cable.yml index 0bbde6f74f..1da4913082 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/cable.yml +++ b/railties/lib/rails/generators/rails/app/templates/config/cable.yml @@ -7,3 +7,4 @@ test: production: adapter: redis url: redis://localhost:6379/1 + channel_prefix: <%= app_name %>_production 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 7deab5dbb1..4a39e43e57 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 @@ -88,7 +88,7 @@ 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? -%> diff --git a/railties/lib/rails/tasks.rb b/railties/lib/rails/tasks.rb index 48675b3845..c0a50e5bda 100644 --- a/railties/lib/rails/tasks.rb +++ b/railties/lib/rails/tasks.rb @@ -12,6 +12,7 @@ require "rake" restart routes tmp + yarn ).tap { |arr| arr << "statistics" if Rake.application.current_scope.empty? }.each do |task| diff --git a/railties/lib/rails/tasks/yarn.rake b/railties/lib/rails/tasks/yarn.rake index 7c5e266e3e..2097b7ffef 100644 --- a/railties/lib/rails/tasks/yarn.rake +++ b/railties/lib/rails/tasks/yarn.rake @@ -1,9 +1,11 @@ namespace :yarn do desc "Install all JavaScript dependencies as specified via Yarn" task :install do - system("./bin/yarn install") + system('./bin/yarn install --no-progress') end end # Run Yarn prior to Sprockets assets precompilation, so dependencies are available for use. -Rake::Task["assets:precompile"].enhance [ "yarn:install" ] +if Rake::Task.task_defined?("assets:precompile") + Rake::Task["assets:precompile"].enhance [ "yarn:install" ] +end diff --git a/railties/test/generators/app_generator_test.rb b/railties/test/generators/app_generator_test.rb index 20de2258c5..35f7d519d8 100644 --- a/railties/test/generators/app_generator_test.rb +++ b/railties/test/generators/app_generator_test.rb @@ -731,6 +731,11 @@ class AppGeneratorTest < Rails::Generators::TestCase end end + def test_version_control_initializes_git_repo + run_generator [destination_root] + assert_directory ".git" + end + def test_create_keeps run_generator folders_with_keep = %w( @@ -777,7 +782,7 @@ class AppGeneratorTest < Rails::Generators::TestCase template end - sequence = ["install", "exec spring binstub --all", "echo ran after_bundle"] + sequence = ["git init", "install", "exec spring binstub --all", "echo ran after_bundle"] @sequence_step ||= 0 ensure_bundler_first = -> command do assert_equal sequence[@sequence_step], command, "commands should be called in sequence #{sequence}" @@ -792,7 +797,7 @@ class AppGeneratorTest < Rails::Generators::TestCase end end - assert_equal 3, @sequence_step + assert_equal 4, @sequence_step end private diff --git a/railties/test/generators/shared_generator_tests.rb b/railties/test/generators/shared_generator_tests.rb index 08b0e34fe2..cc9d3629e9 100644 --- a/railties/test/generators/shared_generator_tests.rb +++ b/railties/test/generators/shared_generator_tests.rb @@ -109,6 +109,7 @@ module SharedGeneratorTests def test_skip_git run_generator [destination_root, "--skip-git", "--full"] assert_no_file(".gitignore") + assert_no_directory(".git") end def test_skip_keeps |