diff options
64 files changed, 510 insertions, 355 deletions
diff --git a/.travis.yml b/.travis.yml index 5b8cfa9dbf..19fc899a8b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -15,9 +15,6 @@ services: addons: postgresql: "9.4" - apt: - packages: - - postgresql-9.4 bundler_args: --without test --jobs 3 --retry 3 before_install: @@ -42,7 +42,7 @@ gem "json", ">= 2.0.0" gem "rubocop", ">= 0.47", require: false group :doc do - gem "sdoc", "1.0.0.rc1" + gem "sdoc", "> 1.0.0.rc1", "< 2.0" gem "redcarpet", "~> 3.2.3", platforms: :ruby gem "w3c_validators" gem "kindlerb", "~> 1.2.0" diff --git a/Gemfile.lock b/Gemfile.lock index da7e5a8cab..445bab1ca3 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -264,7 +264,7 @@ GEM rainbow (2.2.1) rake (12.0.0) rb-fsevent (0.9.8) - rdoc (5.0.0) + rdoc (5.1.0) redcarpet (3.2.3) redis (3.3.2) redis-namespace (1.5.2) @@ -298,8 +298,8 @@ GEM sprockets (>= 2.8, < 4.0) sprockets-rails (>= 2.0, < 4.0) tilt (>= 1.1, < 3) - sdoc (1.0.0.rc1) - rdoc (= 5.0.0) + sdoc (1.0.0.rc2) + rdoc (~> 5.0) selenium-webdriver (3.0.5) childprocess (~> 0.5) rubyzip (~> 1.0) @@ -417,7 +417,7 @@ DEPENDENCIES resque-scheduler rubocop (>= 0.47) sass-rails - sdoc (= 1.0.0.rc1) + sdoc (> 1.0.0.rc1, < 2.0) sequel sidekiq sneakers diff --git a/actionmailer/lib/action_mailer/preview.rb b/actionmailer/lib/action_mailer/preview.rb index b0152aff03..87ba743f3d 100644 --- a/actionmailer/lib/action_mailer/preview.rb +++ b/actionmailer/lib/action_mailer/preview.rb @@ -52,6 +52,12 @@ module ActionMailer class Preview extend ActiveSupport::DescendantsTracker + attr_reader :params + + def initialize(params = {}) + @params = params + end + class << self # Returns all mailer preview classes. def all @@ -62,8 +68,8 @@ module ActionMailer # Returns the mail object for the given email name. The registered preview # interceptors will be informed so that they can transform the message # as they would if the mail was actually being delivered. - def call(email) - preview = new + def call(email, params = {}) + preview = new(params) message = preview.public_send(email) inform_preview_interceptors(message) message diff --git a/actionmailer/test/base_test.rb b/actionmailer/test/base_test.rb index 61960d411d..ebb97078e6 100644 --- a/actionmailer/test/base_test.rb +++ b/actionmailer/test/base_test.rb @@ -968,3 +968,19 @@ class BasePreviewInterceptorsTest < ActiveSupport::TestCase end end end + +class BasePreviewTest < ActiveSupport::TestCase + class BaseMailerPreview < ActionMailer::Preview + def welcome + BaseMailer.welcome(params) + end + end + + test "has access to params" do + params = { name: "World" } + + assert_called_with(BaseMailer, :welcome, [params]) do + BaseMailerPreview.call(:welcome, params) + end + end +end diff --git a/actionpack/lib/action_dispatch/http/mime_type.rb b/actionpack/lib/action_dispatch/http/mime_type.rb index 0cf010f59e..74a3afab44 100644 --- a/actionpack/lib/action_dispatch/http/mime_type.rb +++ b/actionpack/lib/action_dispatch/http/mime_type.rb @@ -326,11 +326,11 @@ module Mime def ref; end - def respond_to_missing?(method, include_private = false) - method.to_s.ends_with? "?" - end - private + def respond_to_missing?(method, _) + method.to_s.ends_with? "?" + end + def method_missing(method, *args) false if method.to_s.ends_with? "?" end diff --git a/actionpack/lib/action_dispatch/http/parameters.rb b/actionpack/lib/action_dispatch/http/parameters.rb index 79a2ef965b..7c585dbe68 100644 --- a/actionpack/lib/action_dispatch/http/parameters.rb +++ b/actionpack/lib/action_dispatch/http/parameters.rb @@ -85,7 +85,7 @@ module ActionDispatch def set_binary_encoding(params) action = params[:action] - if controller_class.binary_params_for?(action) + if binary_params_for?(action) ActionDispatch::Request::Utils.each_param_value(params) do |param| param.force_encoding ::Encoding::ASCII_8BIT end @@ -93,6 +93,12 @@ module ActionDispatch params end + def binary_params_for?(action) + controller_class.binary_params_for?(action) + rescue NameError + false + end + def parse_formatted_parameters(parsers) return yield if content_length.zero? || content_mime_type.nil? diff --git a/actionpack/lib/action_dispatch/routing/routes_proxy.rb b/actionpack/lib/action_dispatch/routing/routes_proxy.rb index ee847eaeed..c1423f770f 100644 --- a/actionpack/lib/action_dispatch/routing/routes_proxy.rb +++ b/actionpack/lib/action_dispatch/routing/routes_proxy.rb @@ -19,7 +19,8 @@ module ActionDispatch end end - def respond_to_missing?(method, include_private = false) + private + def respond_to_missing?(method, _) super || @helpers.respond_to?(method) end @@ -32,7 +33,7 @@ module ActionDispatch @helpers.#{method}(*args) end RUBY - send(method, *args) + public_send(method, *args) else super end diff --git a/actionpack/lib/action_dispatch/testing/integration.rb b/actionpack/lib/action_dispatch/testing/integration.rb index 2e2db98ad6..2416c58817 100644 --- a/actionpack/lib/action_dispatch/testing/integration.rb +++ b/actionpack/lib/action_dispatch/testing/integration.rb @@ -385,14 +385,15 @@ module ActionDispatch integration_session.default_url_options = options end - def respond_to_missing?(method, include_private = false) - integration_session.respond_to?(method, include_private) || super + private + def respond_to_missing?(method, _) + integration_session.respond_to?(method) || super end # Delegate unhandled messages to the current session instance. - def method_missing(sym, *args, &block) - if integration_session.respond_to?(sym) - integration_session.__send__(sym, *args, &block).tap do + def method_missing(method, *args, &block) + if integration_session.respond_to?(method) + integration_session.public_send(method, *args, &block).tap do copy_session_variables! end else diff --git a/actionview/lib/action_view/helpers/url_helper.rb b/actionview/lib/action_view/helpers/url_helper.rb index 70fc57c35f..a6857101b9 100644 --- a/actionview/lib/action_view/helpers/url_helper.rb +++ b/actionview/lib/action_view/helpers/url_helper.rb @@ -542,7 +542,7 @@ module ActionView return false unless request.get? || request.head? - check_parameters ||= !options.is_a?(String) && options.try(:delete, :check_parameters) + check_parameters ||= options.is_a?(Hash) && options.delete(:check_parameters) url_string = URI.parser.unescape(url_for(options)).force_encoding(Encoding::BINARY) # We ignore any extra parameters in the request_uri if the diff --git a/actionview/test/template/url_helper_test.rb b/actionview/test/template/url_helper_test.rb index c5c0349fb6..6adfa95dd1 100644 --- a/actionview/test/template/url_helper_test.rb +++ b/actionview/test/template/url_helper_test.rb @@ -509,6 +509,12 @@ class UrlHelperTest < ActiveSupport::TestCase assert !current_page?("http://www.example.com/", check_parameters: true) end + def test_current_page_considering_params_when_options_does_not_respond_to_to_hash + @request = request_for_url("/?order=desc&page=1") + + assert !current_page?(:back, check_parameters: false) + end + def test_current_page_with_params_that_match @request = request_for_url("/?order=desc&page=1") @@ -873,6 +879,11 @@ class WorkshopsController < ActionController::Base @workshop = Workshop.new(params[:id]) render inline: "<%= url_for(@workshop) %>\n<%= link_to('Workshop', @workshop) %>" end + + def edit + @workshop = Workshop.new(params[:id]) + render inline: "<%= current_page?(@workshop) %>" + end end class SessionsController < ActionController::Base @@ -937,4 +948,11 @@ class PolymorphicControllerTest < ActionController::TestCase get :edit, params: { workshop_id: 1, id: 1, format: "json" } assert_equal %{/workshops/1/sessions/1.json\n<a href="/workshops/1/sessions/1.json">Session</a>}, @response.body end + + def test_current_page_when_options_does_not_respond_to_to_hash + @controller = WorkshopsController.new + + get :edit, params: { id: 1 } + assert_equal "false", @response.body + end end diff --git a/activemodel/lib/active_model/validations/numericality.rb b/activemodel/lib/active_model/validations/numericality.rb index 995b331245..b82c85ddf4 100644 --- a/activemodel/lib/active_model/validations/numericality.rb +++ b/activemodel/lib/active_model/validations/numericality.rb @@ -104,7 +104,7 @@ module ActiveModel module HelperMethods # Validates whether the value of the specified attribute is numeric by # trying to convert it to a float with Kernel.Float (if <tt>only_integer</tt> - # is +false+) or applying it to the regular expression <tt>/\A[\+\-]?\d+\Z/</tt> + # is +false+) or applying it to the regular expression <tt>/\A[\+\-]?\d+\z/</tt> # (if <tt>only_integer</tt> is set to +true+). # # class Person < ActiveRecord::Base diff --git a/activemodel/test/cases/validations/format_validation_test.rb b/activemodel/test/cases/validations/format_validation_test.rb index d7e6bf3707..f5b1ad721c 100644 --- a/activemodel/test/cases/validations/format_validation_test.rb +++ b/activemodel/test/cases/validations/format_validation_test.rb @@ -107,7 +107,7 @@ class PresenceValidationTest < ActiveModel::TestCase end def test_validates_format_of_with_lambda - Topic.validates_format_of :content, with: lambda { |topic| topic.title == "digit" ? /\A\d+\Z/ : /\A\S+\Z/ } + Topic.validates_format_of :content, with: lambda { |topic| topic.title == "digit" ? /\A\d+\z/ : /\A\S+\z/ } t = Topic.new t.title = "digit" @@ -119,7 +119,7 @@ class PresenceValidationTest < ActiveModel::TestCase end def test_validates_format_of_without_lambda - Topic.validates_format_of :content, without: lambda { |topic| topic.title == "characters" ? /\A\d+\Z/ : /\A\S+\Z/ } + Topic.validates_format_of :content, without: lambda { |topic| topic.title == "characters" ? /\A\d+\z/ : /\A\S+\z/ } t = Topic.new t.title = "characters" @@ -131,7 +131,7 @@ class PresenceValidationTest < ActiveModel::TestCase end def test_validates_format_of_for_ruby_class - Person.validates_format_of :karma, with: /\A\d+\Z/ + Person.validates_format_of :karma, with: /\A\d+\z/ p = Person.new p.karma = "Pixies" diff --git a/activerecord/lib/active_record/associations/collection_proxy.rb b/activerecord/lib/active_record/associations/collection_proxy.rb index 5d6676f0df..74a4d515c2 100644 --- a/activerecord/lib/active_record/associations/collection_proxy.rb +++ b/activerecord/lib/active_record/associations/collection_proxy.rb @@ -1121,6 +1121,19 @@ module ActiveRecord delegate(*delegate_methods, to: :scope) + module DelegateExtending # :nodoc: + private + def method_missing(method, *args, &block) + extending_values = association_scope.extending_values + if extending_values.any? && (extending_values - self.class.included_modules).any? + self.class.include(*extending_values) + public_send(method, *args, &block) + else + super + end + end + end + private def find_nth_with_limit(index, limit) @@ -1141,21 +1154,16 @@ module ActiveRecord @association.find_from_target? end + def association_scope + @association.association_scope + end + def exec_queries load_target end def respond_to_missing?(method, _) - scope.respond_to?(method) || super - end - - def method_missing(method, *args, &block) - if scope.respond_to?(method) && scope.extending_values.any? - extend(*scope.extending_values) - public_send(method, *args, &block) - else - super - end + association_scope.respond_to?(method) || super end end end diff --git a/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb b/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb index 53dbbd8c21..61bf5477aa 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb @@ -506,14 +506,16 @@ module ActiveRecord # +conn+: an AbstractAdapter object, which was obtained by earlier by # calling #checkout on this pool. def checkin(conn) - synchronize do - remove_connection_from_thread_cache conn + conn.lock.synchronize do + synchronize do + remove_connection_from_thread_cache conn - conn._run_checkin_callbacks do - conn.expire - end + conn._run_checkin_callbacks do + conn.expire + end - @available.add conn + @available.add conn + end end end @@ -857,9 +859,9 @@ module ActiveRecord # All Active Record models use this handler to determine the connection pool that they # should use. # - # The ConnectionHandler class is not coupled with the Active models, as it has no knowlodge + # The ConnectionHandler class is not coupled with the Active models, as it has no knowledge # about the model. The model needs to pass a specification name to the handler, - # in order to lookup the correct connection pool. + # in order to look up the correct connection pool. class ConnectionHandler def initialize # These caches are keyed by spec.name (ConnectionSpecification#name). diff --git a/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb b/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb index 45e400b75b..af55cfe2f6 100644 --- a/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb @@ -10,8 +10,6 @@ module ActiveRecord # Establishes a connection to the database that's used by all Active Record objects. def mysql2_connection(config) config = config.symbolize_keys - - config[:username] = "root" if config[:username].nil? config[:flags] ||= 0 if config[:flags].kind_of? Array diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/referential_integrity.rb b/activerecord/lib/active_record/connection_adapters/postgresql/referential_integrity.rb index 730e7c7137..44a7338bf5 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql/referential_integrity.rb @@ -6,50 +6,8 @@ module ActiveRecord true end - def disable_referential_integrity(&block) # :nodoc: + def disable_referential_integrity # :nodoc: if supports_disable_referential_integrity? - if supports_alter_constraint? - disable_referential_integrity_with_alter_constraint(&block) - else - disable_referential_integrity_with_disable_trigger(&block) - end - else - yield - end - end - - private - - def disable_referential_integrity_with_alter_constraint - tables_constraints = execute(<<-SQL).values - SELECT table_name, constraint_name - FROM information_schema.table_constraints - WHERE constraint_type = 'FOREIGN KEY' - AND is_deferrable = 'NO' - SQL - - execute( - tables_constraints.collect { |table, constraint| - "ALTER TABLE #{quote_table_name(table)} ALTER CONSTRAINT #{constraint} DEFERRABLE" - }.join(";") - ) - - begin - transaction do - execute("SET CONSTRAINTS ALL DEFERRED") - - yield - end - ensure - execute( - tables_constraints.collect { |table, constraint| - "ALTER TABLE #{quote_table_name(table)} ALTER CONSTRAINT #{constraint} NOT DEFERRABLE" - }.join(";") - ) - end - end - - def disable_referential_integrity_with_disable_trigger original_exception = nil begin @@ -81,7 +39,10 @@ Rails needs superuser privileges to disable referential integrity. end rescue ActiveRecord::ActiveRecordError end + else + yield end + end end end end diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb index 7ae9bd9a5f..541013c1e7 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb @@ -314,12 +314,6 @@ module ActiveRecord postgresql_version >= 90400 end - def supports_alter_constraint? - # PostgreSQL 9.4 introduces ALTER TABLE ... ALTER CONSTRAINT but it has a bug and fixed in 9.4.2 - # https://www.postgresql.org/docs/9.4/static/release-9-4-2.html - postgresql_version >= 90402 - end - def get_advisory_lock(lock_id) # :nodoc: unless lock_id.is_a?(Integer) && lock_id.bit_length <= 63 raise(ArgumentError, "Postgres requires advisory lock ids to be a signed 64 bit integer") diff --git a/activerecord/lib/active_record/dynamic_matchers.rb b/activerecord/lib/active_record/dynamic_matchers.rb index d9912cfb22..3a9625092e 100644 --- a/activerecord/lib/active_record/dynamic_matchers.rb +++ b/activerecord/lib/active_record/dynamic_matchers.rb @@ -1,15 +1,14 @@ module ActiveRecord module DynamicMatchers #:nodoc: - def respond_to_missing?(name, include_private = false) - if self == Base - super - else - match = Method.match(self, name) - match && match.valid? || super - end - end - private + def respond_to_missing?(name, _) + if self == Base + super + else + match = Method.match(self, name) + match && match.valid? || super + end + end def method_missing(name, *arguments, &block) match = Method.match(self, name) diff --git a/activerecord/lib/active_record/migration/command_recorder.rb b/activerecord/lib/active_record/migration/command_recorder.rb index 03103bba98..f9cf59b283 100644 --- a/activerecord/lib/active_record/migration/command_recorder.rb +++ b/activerecord/lib/active_record/migration/command_recorder.rb @@ -92,10 +92,6 @@ module ActiveRecord send(method, args, &block) end - def respond_to_missing?(*args) # :nodoc: - super || delegate.respond_to?(*args) - end - ReversibleAndIrreversibleMethods.each do |method| class_eval <<-EOV, __FILE__, __LINE__ + 1 def #{method}(*args, &block) # def create_table(*args, &block) @@ -225,10 +221,14 @@ module ActiveRecord [:add_foreign_key, reversed_args] end + def respond_to_missing?(method, _) + super || delegate.respond_to?(method) + end + # Forwards any missing method call to the \target. def method_missing(method, *args, &block) - if @delegate.respond_to?(method) - @delegate.send(method, *args, &block) + if delegate.respond_to?(method) + delegate.public_send(method, *args, &block) else super end diff --git a/activerecord/lib/active_record/relation/delegation.rb b/activerecord/lib/active_record/relation/delegation.rb index 50378f9d99..257ae04ff4 100644 --- a/activerecord/lib/active_record/relation/delegation.rb +++ b/activerecord/lib/active_record/relation/delegation.rb @@ -25,6 +25,8 @@ module ActiveRecord def inherited(child_class) child_class.initialize_relation_delegate_cache + delegate = child_class.relation_delegate_class(ActiveRecord::Associations::CollectionProxy) + delegate.include ActiveRecord::Associations::CollectionProxy::DelegateExtending super end end @@ -109,12 +111,10 @@ module ActiveRecord end end - def respond_to_missing?(method, include_private = false) - super || @klass.respond_to?(method, include_private) || - arel.respond_to?(method, include_private) - end - private + def respond_to_missing?(method, _) + super || @klass.respond_to?(method) || arel.respond_to?(method) + end def method_missing(method, *args, &block) if @klass.respond_to?(method) diff --git a/activerecord/lib/active_record/tasks/database_tasks.rb b/activerecord/lib/active_record/tasks/database_tasks.rb index 46fa8a70a3..45110a79cd 100644 --- a/activerecord/lib/active_record/tasks/database_tasks.rb +++ b/activerecord/lib/active_record/tasks/database_tasks.rb @@ -164,7 +164,7 @@ module ActiveRecord def migrate raise "Empty VERSION provided" if ENV["VERSION"] && ENV["VERSION"].empty? - verbose = ENV["VERBOSE"] ? ENV["VERBOSE"] == "true" : true + verbose = ENV["VERBOSE"] ? ENV["VERBOSE"] != "false" : true version = ENV["VERSION"] ? ENV["VERSION"].to_i : nil scope = ENV["SCOPE"] verbose_was, Migration.verbose = Migration.verbose, verbose diff --git a/activerecord/test/cases/adapters/postgresql/referential_integrity_test.rb b/activerecord/test/cases/adapters/postgresql/referential_integrity_test.rb index c5c540cebc..0ff04bfa27 100644 --- a/activerecord/test/cases/adapters/postgresql/referential_integrity_test.rb +++ b/activerecord/test/cases/adapters/postgresql/referential_integrity_test.rb @@ -1,150 +1,111 @@ require "cases/helper" require "support/connection_helper" -if ActiveRecord::Base.connection.respond_to?(:supports_alter_constraint?) && - ActiveRecord::Base.connection.supports_alter_constraint? - class PostgreSQLReferentialIntegrityWithAlterConstraintTest < ActiveRecord::PostgreSQLTestCase - self.use_transactional_tests = false +class PostgreSQLReferentialIntegrityTest < ActiveRecord::PostgreSQLTestCase + self.use_transactional_tests = false - include ConnectionHelper + include ConnectionHelper - IS_REFERENTIAL_INTEGRITY_SQL = lambda do |sql| - sql.match(/SET CONSTRAINTS ALL DEFERRED/) - end + IS_REFERENTIAL_INTEGRITY_SQL = lambda do |sql| + sql.match(/DISABLE TRIGGER ALL/) || sql.match(/ENABLE TRIGGER ALL/) + end - module ProgrammerMistake - def execute(sql) - if IS_REFERENTIAL_INTEGRITY_SQL.call(sql) - raise ArgumentError, "something is not right." - else - super - end + module MissingSuperuserPrivileges + def execute(sql) + if IS_REFERENTIAL_INTEGRITY_SQL.call(sql) + super "BROKEN;" rescue nil # put transaction in broken state + raise ActiveRecord::StatementInvalid, "PG::InsufficientPrivilege" + else + super end end + end - def setup - @connection = ActiveRecord::Base.connection - end - - def teardown - reset_connection - end - - def test_errors_bubble_up - @connection.extend ProgrammerMistake - - assert_raises ArgumentError do - @connection.disable_referential_integrity {} + module ProgrammerMistake + def execute(sql) + if IS_REFERENTIAL_INTEGRITY_SQL.call(sql) + raise ArgumentError, "something is not right." + else + super end end end -else - class PostgreSQLReferentialIntegrityWithDisableTriggerTest < ActiveRecord::PostgreSQLTestCase - self.use_transactional_tests = false - include ConnectionHelper + def setup + @connection = ActiveRecord::Base.connection + end - IS_REFERENTIAL_INTEGRITY_SQL = lambda do |sql| - sql.match(/DISABLE TRIGGER ALL/) || sql.match(/ENABLE TRIGGER ALL/) + def teardown + reset_connection + if ActiveRecord::Base.connection.is_a?(MissingSuperuserPrivileges) + raise "MissingSuperuserPrivileges patch was not removed" end + end - module MissingSuperuserPrivileges - def execute(sql) - if IS_REFERENTIAL_INTEGRITY_SQL.call(sql) - super "BROKEN;" rescue nil # put transaction in broken state - raise ActiveRecord::StatementInvalid, "PG::InsufficientPrivilege" - else - super - end - end - end + def test_should_reraise_invalid_foreign_key_exception_and_show_warning + @connection.extend MissingSuperuserPrivileges - module ProgrammerMistake - def execute(sql) - if IS_REFERENTIAL_INTEGRITY_SQL.call(sql) - raise ArgumentError, "something is not right." - else - super + warning = capture(:stderr) do + e = assert_raises(ActiveRecord::InvalidForeignKey) do + @connection.disable_referential_integrity do + raise ActiveRecord::InvalidForeignKey, "Should be re-raised" end end + assert_equal "Should be re-raised", e.message end + assert_match (/WARNING: Rails was not able to disable referential integrity/), warning + assert_match (/cause: PG::InsufficientPrivilege/), warning + end - def setup - @connection = ActiveRecord::Base.connection - end - - def teardown - reset_connection - if ActiveRecord::Base.connection.is_a?(MissingSuperuserPrivileges) - raise "MissingSuperuserPrivileges patch was not removed" - end - end - - def test_should_reraise_invalid_foreign_key_exception_and_show_warning - @connection.extend MissingSuperuserPrivileges + def test_does_not_print_warning_if_no_invalid_foreign_key_exception_was_raised + @connection.extend MissingSuperuserPrivileges - warning = capture(:stderr) do - e = assert_raises(ActiveRecord::InvalidForeignKey) do - @connection.disable_referential_integrity do - raise ActiveRecord::InvalidForeignKey, "Should be re-raised" - end + warning = capture(:stderr) do + e = assert_raises(ActiveRecord::StatementInvalid) do + @connection.disable_referential_integrity do + raise ActiveRecord::StatementInvalid, "Should be re-raised" end - assert_equal "Should be re-raised", e.message end - assert_match (/WARNING: Rails was not able to disable referential integrity/), warning - assert_match (/cause: PG::InsufficientPrivilege/), warning + assert_equal "Should be re-raised", e.message end + assert warning.blank?, "expected no warnings but got:\n#{warning}" + end - def test_does_not_print_warning_if_no_invalid_foreign_key_exception_was_raised - @connection.extend MissingSuperuserPrivileges + def test_does_not_break_transactions + @connection.extend MissingSuperuserPrivileges - warning = capture(:stderr) do - e = assert_raises(ActiveRecord::StatementInvalid) do - @connection.disable_referential_integrity do - raise ActiveRecord::StatementInvalid, "Should be re-raised" - end - end - assert_equal "Should be re-raised", e.message + @connection.transaction do + @connection.disable_referential_integrity do + assert_transaction_is_not_broken end - assert warning.blank?, "expected no warnings but got:\n#{warning}" + assert_transaction_is_not_broken end + end - def test_does_not_break_transactions - @connection.extend MissingSuperuserPrivileges + def test_does_not_break_nested_transactions + @connection.extend MissingSuperuserPrivileges - @connection.transaction do + @connection.transaction do + @connection.transaction(requires_new: true) do @connection.disable_referential_integrity do assert_transaction_is_not_broken end - assert_transaction_is_not_broken end + assert_transaction_is_not_broken end + end - def test_does_not_break_nested_transactions - @connection.extend MissingSuperuserPrivileges + def test_only_catch_active_record_errors_others_bubble_up + @connection.extend ProgrammerMistake - @connection.transaction do - @connection.transaction(requires_new: true) do - @connection.disable_referential_integrity do - assert_transaction_is_not_broken - end - end - assert_transaction_is_not_broken - end + assert_raises ArgumentError do + @connection.disable_referential_integrity {} end + end - def test_only_catch_active_record_errors_others_bubble_up - @connection.extend ProgrammerMistake + private - assert_raises ArgumentError do - @connection.disable_referential_integrity {} - end + def assert_transaction_is_not_broken + assert_equal 1, @connection.select_value("SELECT 1") end - - private - - def assert_transaction_is_not_broken - assert_equal 1, @connection.select_value("SELECT 1") - end - end end diff --git a/activerecord/test/cases/associations/callbacks_test.rb b/activerecord/test/cases/associations/callbacks_test.rb index 7721bd5cd9..5fd2411f6f 100644 --- a/activerecord/test/cases/associations/callbacks_test.rb +++ b/activerecord/test/cases/associations/callbacks_test.rb @@ -7,7 +7,7 @@ require "models/computer" require "models/company" class AssociationCallbacksTest < ActiveRecord::TestCase - fixtures :posts, :authors, :author_addresses, :projects, :developers + fixtures :posts, :authors, :projects, :developers def setup @david = authors(:david) diff --git a/activerecord/test/cases/associations/cascaded_eager_loading_test.rb b/activerecord/test/cases/associations/cascaded_eager_loading_test.rb index 3638c87968..ddb5c7a4aa 100644 --- a/activerecord/test/cases/associations/cascaded_eager_loading_test.rb +++ b/activerecord/test/cases/associations/cascaded_eager_loading_test.rb @@ -12,7 +12,7 @@ require "models/vertex" require "models/edge" class CascadedEagerLoadingTest < ActiveRecord::TestCase - fixtures :authors, :author_addresses, :mixins, :companies, :posts, :topics, :accounts, :comments, + fixtures :authors, :mixins, :companies, :posts, :topics, :accounts, :comments, :categorizations, :people, :categories, :edges, :vertices def test_eager_association_loading_with_cascaded_two_levels diff --git a/activerecord/test/cases/associations/has_many_associations_test.rb b/activerecord/test/cases/associations/has_many_associations_test.rb index 25133fc580..1eb10c1dbe 100644 --- a/activerecord/test/cases/associations/has_many_associations_test.rb +++ b/activerecord/test/cases/associations/has_many_associations_test.rb @@ -40,7 +40,7 @@ require "models/zine" require "models/interest" class HasManyAssociationsTestForReorderWithJoinDependency < ActiveRecord::TestCase - fixtures :authors, :author_addresses, :posts, :comments + fixtures :authors, :posts, :comments def test_should_generate_valid_sql author = authors(:david) @@ -51,7 +51,7 @@ class HasManyAssociationsTestForReorderWithJoinDependency < ActiveRecord::TestCa end class HasManyAssociationsTestPrimaryKeys < ActiveRecord::TestCase - fixtures :authors, :author_addresses, :essays, :subscribers, :subscriptions, :people + fixtures :authors, :essays, :subscribers, :subscriptions, :people def test_custom_primary_key_on_new_record_should_fetch_with_query subscriber = Subscriber.new(nick: "webster132") @@ -100,7 +100,7 @@ end class HasManyAssociationsTest < ActiveRecord::TestCase fixtures :accounts, :categories, :companies, :developers, :projects, - :developers_projects, :topics, :authors, :author_addresses, :comments, + :developers_projects, :topics, :authors, :comments, :posts, :readers, :taggings, :cars, :jobs, :tags, :categorizations, :zines, :interests @@ -2037,12 +2037,6 @@ class HasManyAssociationsTest < ActiveRecord::TestCase assert_equal client_association.new.attributes, client_association.send(:new).attributes end - def test_respond_to_private_class_methods - client_association = companies(:first_firm).clients - assert !client_association.respond_to?(:private_method) - assert client_association.respond_to?(:private_method, true) - end - def test_creating_using_primary_key firm = Firm.all.merge!(order: "id").first client = firm.clients_using_primary_key.create!(name: "test") diff --git a/activerecord/test/cases/associations/has_one_through_associations_test.rb b/activerecord/test/cases/associations/has_one_through_associations_test.rb index 28b883586d..38a729d2d4 100644 --- a/activerecord/test/cases/associations/has_one_through_associations_test.rb +++ b/activerecord/test/cases/associations/has_one_through_associations_test.rb @@ -23,7 +23,7 @@ require "models/customer_carrier" class HasOneThroughAssociationsTest < ActiveRecord::TestCase fixtures :member_types, :members, :clubs, :memberships, :sponsors, :organizations, :minivans, - :dashboards, :speedometers, :authors, :author_addresses, :posts, :comments, :categories, :essays, :owners + :dashboards, :speedometers, :authors, :posts, :comments, :categories, :essays, :owners def setup @member = members(:groucho) diff --git a/activerecord/test/cases/associations/inner_join_association_test.rb b/activerecord/test/cases/associations/inner_join_association_test.rb index ddf5bc6f0b..7414869c8f 100644 --- a/activerecord/test/cases/associations/inner_join_association_test.rb +++ b/activerecord/test/cases/associations/inner_join_association_test.rb @@ -10,7 +10,7 @@ require "models/tagging" require "models/tag" class InnerJoinAssociationTest < ActiveRecord::TestCase - fixtures :authors, :author_addresses, :essays, :posts, :comments, :categories, :categories_posts, :categorizations, + fixtures :authors, :essays, :posts, :comments, :categories, :categories_posts, :categorizations, :taggings, :tags def test_construct_finder_sql_applies_aliases_tables_on_association_conditions diff --git a/activerecord/test/cases/associations/join_model_test.rb b/activerecord/test/cases/associations/join_model_test.rb index c078cef064..a4345f3857 100644 --- a/activerecord/test/cases/associations/join_model_test.rb +++ b/activerecord/test/cases/associations/join_model_test.rb @@ -19,7 +19,7 @@ require "models/car" class AssociationsJoinModelTest < ActiveRecord::TestCase self.use_transactional_tests = false unless supports_savepoints? - fixtures :posts, :authors, :author_addresses, :categories, :categorizations, :comments, :tags, :taggings, :author_favorites, :vertices, :items, :books, + fixtures :posts, :authors, :categories, :categorizations, :comments, :tags, :taggings, :author_favorites, :vertices, :items, :books, # Reload edges table from fixtures as otherwise repeated test was failing :edges diff --git a/activerecord/test/cases/associations/left_outer_join_association_test.rb b/activerecord/test/cases/associations/left_outer_join_association_test.rb index 2aca3523c4..42dbbad1c8 100644 --- a/activerecord/test/cases/associations/left_outer_join_association_test.rb +++ b/activerecord/test/cases/associations/left_outer_join_association_test.rb @@ -7,7 +7,7 @@ require "models/categorization" require "models/person" class LeftOuterJoinAssociationTest < ActiveRecord::TestCase - fixtures :authors, :essays, :posts, :comments, :categorizations, :people, :author_addresses + fixtures :authors, :essays, :posts, :comments, :categorizations, :people def test_construct_finder_sql_applies_aliases_tables_on_association_conditions result = Author.left_outer_joins(:thinking_posts, :welcome_posts).to_a diff --git a/activerecord/test/cases/associations/nested_through_associations_test.rb b/activerecord/test/cases/associations/nested_through_associations_test.rb index 67ff7355b3..dc26f6a383 100644 --- a/activerecord/test/cases/associations/nested_through_associations_test.rb +++ b/activerecord/test/cases/associations/nested_through_associations_test.rb @@ -24,7 +24,7 @@ require "models/membership" require "models/essay" class NestedThroughAssociationsTest < ActiveRecord::TestCase - fixtures :authors, :author_addresses, :books, :posts, :subscriptions, :subscribers, :tags, :taggings, + fixtures :authors, :books, :posts, :subscriptions, :subscribers, :tags, :taggings, :people, :readers, :references, :jobs, :ratings, :comments, :members, :member_details, :member_types, :sponsors, :clubs, :organizations, :categories, :categories_posts, :categorizations, :memberships, :essays diff --git a/activerecord/test/cases/associations_test.rb b/activerecord/test/cases/associations_test.rb index 4ab690bfc6..26056f6f63 100644 --- a/activerecord/test/cases/associations_test.rb +++ b/activerecord/test/cases/associations_test.rb @@ -22,7 +22,7 @@ require "models/interest" class AssociationsTest < ActiveRecord::TestCase fixtures :accounts, :companies, :developers, :projects, :developers_projects, - :computers, :people, :readers, :authors, :author_addresses, :author_favorites + :computers, :people, :readers, :authors, :author_favorites def test_eager_loading_should_not_change_count_of_children liquid = Liquid.create(name: "salty") @@ -111,7 +111,7 @@ class AssociationsTest < ActiveRecord::TestCase end class AssociationProxyTest < ActiveRecord::TestCase - fixtures :authors, :author_addresses, :posts, :categorizations, :categories, :developers, :projects, :developers_projects + fixtures :authors, :posts, :categorizations, :categories, :developers, :projects, :developers_projects def test_push_does_not_load_target david = authors(:david) diff --git a/activerecord/test/cases/base_test.rb b/activerecord/test/cases/base_test.rb index 15c253890b..8efbc41da9 100644 --- a/activerecord/test/cases/base_test.rb +++ b/activerecord/test/cases/base_test.rb @@ -64,7 +64,7 @@ class LintTest < ActiveRecord::TestCase end class BasicsTest < ActiveRecord::TestCase - fixtures :topics, :companies, :developers, :projects, :computers, :accounts, :minimalistics, "warehouse-things", :authors, :author_addresses, :categorizations, :categories, :posts + fixtures :topics, :companies, :developers, :projects, :computers, :accounts, :minimalistics, "warehouse-things", :authors, :categorizations, :categories, :posts def test_column_names_are_escaped conn = ActiveRecord::Base.connection diff --git a/activerecord/test/cases/batches_test.rb b/activerecord/test/cases/batches_test.rb index f7e21faf0f..1a54c02fac 100644 --- a/activerecord/test/cases/batches_test.rb +++ b/activerecord/test/cases/batches_test.rb @@ -35,12 +35,10 @@ class EachTest < ActiveRecord::TestCase end end - if Enumerator.method_defined? :size - def test_each_should_return_a_sized_enumerator - assert_equal 11, Post.find_each(batch_size: 1).size - assert_equal 5, Post.find_each(batch_size: 2, start: 7).size - assert_equal 11, Post.find_each(batch_size: 10_000).size - end + def test_each_should_return_a_sized_enumerator + assert_equal 11, Post.find_each(batch_size: 1).size + assert_equal 5, Post.find_each(batch_size: 2, start: 7).size + assert_equal 11, Post.find_each(batch_size: 10_000).size end def test_each_enumerator_should_execute_one_query_per_batch @@ -515,14 +513,12 @@ class EachTest < ActiveRecord::TestCase assert_equal 2, person.reload.author_id # incremented only once end - if Enumerator.method_defined? :size - def test_find_in_batches_should_return_a_sized_enumerator - assert_equal 11, Post.find_in_batches(batch_size: 1).size - assert_equal 6, Post.find_in_batches(batch_size: 2).size - assert_equal 4, Post.find_in_batches(batch_size: 2, start: 4).size - assert_equal 4, Post.find_in_batches(batch_size: 3).size - assert_equal 1, Post.find_in_batches(batch_size: 10_000).size - end + def test_find_in_batches_should_return_a_sized_enumerator + assert_equal 11, Post.find_in_batches(batch_size: 1).size + assert_equal 6, Post.find_in_batches(batch_size: 2).size + assert_equal 4, Post.find_in_batches(batch_size: 2, start: 4).size + assert_equal 4, Post.find_in_batches(batch_size: 3).size + assert_equal 1, Post.find_in_batches(batch_size: 10_000).size end [true, false].each do |load| diff --git a/activerecord/test/cases/bind_parameter_test.rb b/activerecord/test/cases/bind_parameter_test.rb index 6032aa9250..a0f83df80b 100644 --- a/activerecord/test/cases/bind_parameter_test.rb +++ b/activerecord/test/cases/bind_parameter_test.rb @@ -7,7 +7,7 @@ if ActiveRecord::Base.connection.supports_statement_cache? && ActiveRecord::Base.connection.prepared_statements module ActiveRecord class BindParameterTest < ActiveRecord::TestCase - fixtures :topics, :authors, :author_addresses, :posts + fixtures :topics, :authors, :posts class LogListener attr_accessor :calls diff --git a/activerecord/test/cases/collection_cache_key_test.rb b/activerecord/test/cases/collection_cache_key_test.rb index 92620761e4..f344c77691 100644 --- a/activerecord/test/cases/collection_cache_key_test.rb +++ b/activerecord/test/cases/collection_cache_key_test.rb @@ -11,16 +11,16 @@ module ActiveRecord fixtures :developers, :projects, :developers_projects, :topics, :comments, :posts test "collection_cache_key on model" do - assert_match(/\Adevelopers\/query-(\h+)-(\d+)-(\d+)\Z/, Developer.collection_cache_key) + assert_match(/\Adevelopers\/query-(\h+)-(\d+)-(\d+)\z/, Developer.collection_cache_key) end test "cache_key for relation" do developers = Developer.where(salary: 100000).order(updated_at: :desc) last_developer_timestamp = developers.first.updated_at - assert_match(/\Adevelopers\/query-(\h+)-(\d+)-(\d+)\Z/, developers.cache_key) + assert_match(/\Adevelopers\/query-(\h+)-(\d+)-(\d+)\z/, developers.cache_key) - /\Adevelopers\/query-(\h+)-(\d+)-(\d+)\Z/ =~ developers.cache_key + /\Adevelopers\/query-(\h+)-(\d+)-(\d+)\z/ =~ developers.cache_key assert_equal Digest::MD5.hexdigest(developers.to_sql), $1 assert_equal developers.count.to_s, $2 @@ -31,9 +31,9 @@ module ActiveRecord developers = Developer.where(salary: 100000).order(updated_at: :desc).limit(5) last_developer_timestamp = developers.first.updated_at - assert_match(/\Adevelopers\/query-(\h+)-(\d+)-(\d+)\Z/, developers.cache_key) + assert_match(/\Adevelopers\/query-(\h+)-(\d+)-(\d+)\z/, developers.cache_key) - /\Adevelopers\/query-(\h+)-(\d+)-(\d+)\Z/ =~ developers.cache_key + /\Adevelopers\/query-(\h+)-(\d+)-(\d+)\z/ =~ developers.cache_key assert_equal Digest::MD5.hexdigest(developers.to_sql), $1 assert_equal developers.count.to_s, $2 @@ -44,9 +44,9 @@ module ActiveRecord developers = Developer.where(salary: 100000).order(updated_at: :desc).limit(5).load last_developer_timestamp = developers.first.updated_at - assert_match(/\Adevelopers\/query-(\h+)-(\d+)-(\d+)\Z/, developers.cache_key) + assert_match(/\Adevelopers\/query-(\h+)-(\d+)-(\d+)\z/, developers.cache_key) - /\Adevelopers\/query-(\h+)-(\d+)-(\d+)\Z/ =~ developers.cache_key + /\Adevelopers\/query-(\h+)-(\d+)-(\d+)\z/ =~ developers.cache_key assert_equal Digest::MD5.hexdigest(developers.to_sql), $1 assert_equal developers.count.to_s, $2 @@ -74,7 +74,7 @@ module ActiveRecord test "cache_key for empty relation" do developers = Developer.where(name: "Non Existent Developer") - assert_match(/\Adevelopers\/query-(\h+)-0\Z/, developers.cache_key) + assert_match(/\Adevelopers\/query-(\h+)-0\z/, developers.cache_key) end test "cache_key with custom timestamp column" do @@ -90,7 +90,7 @@ module ActiveRecord test "collection proxy provides a cache_key" do developers = projects(:active_record).developers - assert_match(/\Adevelopers\/query-(\h+)-(\d+)-(\d+)\Z/, developers.cache_key) + assert_match(/\Adevelopers\/query-(\h+)-(\d+)-(\d+)\z/, developers.cache_key) end test "cache_key for loaded collection with zero size" do @@ -98,18 +98,18 @@ module ActiveRecord posts = Post.includes(:comments) empty_loaded_collection = posts.first.comments - assert_match(/\Acomments\/query-(\h+)-0\Z/, empty_loaded_collection.cache_key) + assert_match(/\Acomments\/query-(\h+)-0\z/, empty_loaded_collection.cache_key) end test "cache_key for queries with offset which return 0 rows" do developers = Developer.offset(20) - assert_match(/\Adevelopers\/query-(\h+)-0\Z/, developers.cache_key) + assert_match(/\Adevelopers\/query-(\h+)-0\z/, developers.cache_key) end test "cache_key with a relation having selected columns" do developers = Developer.select(:salary) - assert_match(/\Adevelopers\/query-(\h+)-(\d+)-(\d+)\Z/, developers.cache_key) + assert_match(/\Adevelopers\/query-(\h+)-(\d+)-(\d+)\z/, developers.cache_key) end end end diff --git a/activerecord/test/cases/fixtures_test.rb b/activerecord/test/cases/fixtures_test.rb index a0a6d3c7ef..4137a1e955 100644 --- a/activerecord/test/cases/fixtures_test.rb +++ b/activerecord/test/cases/fixtures_test.rb @@ -784,7 +784,7 @@ end class FasterFixturesTest < ActiveRecord::TestCase self.use_transactional_tests = false - fixtures :categories, :authors, :author_addresses + fixtures :categories, :authors def load_extra_fixture(name) fixture = create_fixtures(name).first diff --git a/activerecord/test/cases/json_serialization_test.rb b/activerecord/test/cases/json_serialization_test.rb index 9b4b61b16e..5a1d066aef 100644 --- a/activerecord/test/cases/json_serialization_test.rb +++ b/activerecord/test/cases/json_serialization_test.rb @@ -168,7 +168,7 @@ class JsonSerializationTest < ActiveRecord::TestCase end class DatabaseConnectedJsonEncodingTest < ActiveRecord::TestCase - fixtures :authors, :author_addresses, :posts, :comments, :tags, :taggings + fixtures :authors, :posts, :comments, :tags, :taggings include JsonSerializationHelpers diff --git a/activerecord/test/cases/migrator_test.rb b/activerecord/test/cases/migrator_test.rb index aadbc375af..2e4b454a86 100644 --- a/activerecord/test/cases/migrator_test.rb +++ b/activerecord/test/cases/migrator_test.rb @@ -299,6 +299,7 @@ class MigratorTest < ActiveRecord::TestCase def test_migrator_verbosity _, migrations = sensors(3) + ActiveRecord::Migration.verbose = true ActiveRecord::Migrator.new(:up, migrations, 1).migrate assert_not_equal 0, ActiveRecord::Migration.message_count @@ -311,7 +312,6 @@ class MigratorTest < ActiveRecord::TestCase def test_migrator_verbosity_off _, migrations = sensors(3) - ActiveRecord::Migration.message_count = 0 ActiveRecord::Migration.verbose = false ActiveRecord::Migrator.new(:up, migrations, 1).migrate assert_equal 0, ActiveRecord::Migration.message_count diff --git a/activerecord/test/cases/persistence_test.rb b/activerecord/test/cases/persistence_test.rb index 5b7e2fd008..5895c51714 100644 --- a/activerecord/test/cases/persistence_test.rb +++ b/activerecord/test/cases/persistence_test.rb @@ -49,7 +49,7 @@ class PersistenceTest < ActiveRecord::TestCase assert !test_update_with_order_succeeds.call("id ASC") # test that this wasn't a fluke and using an incorrect order results in an exception else # test that we're failing because the current Arel's engine doesn't support UPDATE ORDER BY queries is using subselects instead - assert_sql(/\AUPDATE .+ \(SELECT .* ORDER BY id DESC\)\Z/i) do + assert_sql(/\AUPDATE .+ \(SELECT .* ORDER BY id DESC\)\z/i) do test_update_with_order_succeeds.call("id DESC") end end diff --git a/activerecord/test/cases/readonly_test.rb b/activerecord/test/cases/readonly_test.rb index 24b678310d..a93061b516 100644 --- a/activerecord/test/cases/readonly_test.rb +++ b/activerecord/test/cases/readonly_test.rb @@ -10,7 +10,7 @@ require "models/person" require "models/ship" class ReadOnlyTest < ActiveRecord::TestCase - fixtures :authors, :author_addresses, :posts, :comments, :developers, :projects, :developers_projects, :people, :readers + fixtures :authors, :posts, :comments, :developers, :projects, :developers_projects, :people, :readers def test_cant_save_readonly_record dev = Developer.find(1) diff --git a/activerecord/test/cases/relation/merging_test.rb b/activerecord/test/cases/relation/merging_test.rb index 9e95149ede..67d76de798 100644 --- a/activerecord/test/cases/relation/merging_test.rb +++ b/activerecord/test/cases/relation/merging_test.rb @@ -8,7 +8,7 @@ require "models/project" require "models/rating" class RelationMergingTest < ActiveRecord::TestCase - fixtures :developers, :comments, :authors, :author_addresses, :posts + fixtures :developers, :comments, :authors, :posts def test_relation_merging devs = Developer.where("salary >= 80000").merge(Developer.limit(2)).merge(Developer.order("id ASC").where("id < 3")) @@ -21,7 +21,7 @@ class RelationMergingTest < ActiveRecord::TestCase def test_relation_to_sql post = Post.first sql = post.comments.to_sql - assert_match(/.?post_id.? = #{post.id}\Z/i, sql) + assert_match(/.?post_id.? = #{post.id}\z/i, sql) end def test_relation_merging_with_arel_equalities_keeps_last_equality @@ -114,7 +114,7 @@ class RelationMergingTest < ActiveRecord::TestCase end class MergingDifferentRelationsTest < ActiveRecord::TestCase - fixtures :posts, :authors, :author_addresses, :developers + fixtures :posts, :authors, :developers test "merging where relations" do hello_by_bob = Post.where(body: "hello").joins(:author). diff --git a/activerecord/test/cases/relation/where_test.rb b/activerecord/test/cases/relation/where_test.rb index cbc466d6b8..9a333e0d5a 100644 --- a/activerecord/test/cases/relation/where_test.rb +++ b/activerecord/test/cases/relation/where_test.rb @@ -15,7 +15,7 @@ require "models/vertex" module ActiveRecord class WhereTest < ActiveRecord::TestCase - fixtures :posts, :edges, :authors, :author_addresses, :binaries, :essays, :cars, :treasures, :price_estimates + fixtures :posts, :edges, :authors, :binaries, :essays, :cars, :treasures, :price_estimates def test_where_copies_bind_params author = authors(:david) diff --git a/activerecord/test/cases/relation_test.rb b/activerecord/test/cases/relation_test.rb index 5fb32270b7..1241bb54a4 100644 --- a/activerecord/test/cases/relation_test.rb +++ b/activerecord/test/cases/relation_test.rb @@ -6,7 +6,7 @@ require "models/rating" module ActiveRecord class RelationTest < ActiveRecord::TestCase - fixtures :posts, :comments, :authors, :author_addresses + fixtures :posts, :comments, :authors FakeKlass = Struct.new(:table_name, :name) do extend ActiveRecord::Delegation::DelegateCache diff --git a/activerecord/test/cases/relations_test.rb b/activerecord/test/cases/relations_test.rb index fcf68b0f2a..d32db0558f 100644 --- a/activerecord/test/cases/relations_test.rb +++ b/activerecord/test/cases/relations_test.rb @@ -22,7 +22,7 @@ require "models/categorization" require "models/edge" class RelationTest < ActiveRecord::TestCase - fixtures :authors, :author_addresses, :topics, :entrants, :developers, :companies, :developers_projects, :accounts, :categories, :categorizations, :posts, :comments, + fixtures :authors, :topics, :entrants, :developers, :companies, :developers_projects, :accounts, :categories, :categorizations, :posts, :comments, :tags, :taggings, :cars, :minivans class TopicWithCallbacks < ActiveRecord::Base @@ -594,7 +594,7 @@ class RelationTest < ActiveRecord::TestCase end end - def test_respond_to_delegates_to_relation + def test_respond_to_delegates_to_arel relation = Topic.all fake_arel = Struct.new(:responds) { def respond_to?(method, access = false) @@ -607,10 +607,6 @@ class RelationTest < ActiveRecord::TestCase relation.respond_to?(:matching_attributes) assert_equal [:matching_attributes, false], fake_arel.responds.first - - fake_arel.responds = [] - relation.respond_to?(:matching_attributes, true) - assert_equal [:matching_attributes, true], fake_arel.responds.first end def test_respond_to_dynamic_finders diff --git a/activerecord/test/cases/result_test.rb b/activerecord/test/cases/result_test.rb index 949086fda0..1a0b7c6ca7 100644 --- a/activerecord/test/cases/result_test.rb +++ b/activerecord/test/cases/result_test.rb @@ -45,10 +45,8 @@ module ActiveRecord end end - if Enumerator.method_defined? :size - test "each without block returns a sized enumerator" do - assert_equal 3, result.each.size - end + test "each without block returns a sized enumerator" do + assert_equal 3, result.each.size end test "cast_values returns rows after type casting" do diff --git a/activerecord/test/cases/scoping/relation_scoping_test.rb b/activerecord/test/cases/scoping/relation_scoping_test.rb index 3fbff7664b..a1ae57fdbb 100644 --- a/activerecord/test/cases/scoping/relation_scoping_test.rb +++ b/activerecord/test/cases/scoping/relation_scoping_test.rb @@ -10,7 +10,7 @@ require "models/person" require "models/reference" class RelationScopingTest < ActiveRecord::TestCase - fixtures :authors, :author_addresses, :developers, :projects, :comments, :posts, :developers_projects + fixtures :authors, :developers, :projects, :comments, :posts, :developers_projects setup do developers(:david) @@ -238,7 +238,7 @@ class RelationScopingTest < ActiveRecord::TestCase end class NestedRelationScopingTest < ActiveRecord::TestCase - fixtures :authors, :author_addresses, :developers, :projects, :comments, :posts + fixtures :authors, :developers, :projects, :comments, :posts def test_merge_options Developer.where("salary = 80000").scoping do diff --git a/activerecord/test/cases/tasks/database_tasks_test.rb b/activerecord/test/cases/tasks/database_tasks_test.rb index baa41a3a47..b4983624ba 100644 --- a/activerecord/test/cases/tasks/database_tasks_test.rb +++ b/activerecord/test/cases/tasks/database_tasks_test.rb @@ -343,8 +343,23 @@ module ActiveRecord ENV["VERBOSE"] = "false" ENV["VERSION"] = "4" - ActiveRecord::Migrator.expects(:migrate).with("custom/path", 4) + ActiveRecord::Migration.expects(:verbose=).with(false) + ActiveRecord::Migration.expects(:verbose=).with(ActiveRecord::Migration.verbose) + ActiveRecord::Tasks::DatabaseTasks.migrate + + ENV.delete("VERBOSE") + ENV.delete("VERSION") + ActiveRecord::Migrator.expects(:migrate).with("custom/path", nil) + ActiveRecord::Migration.expects(:verbose=).with(true) + ActiveRecord::Migration.expects(:verbose=).with(ActiveRecord::Migration.verbose) + ActiveRecord::Tasks::DatabaseTasks.migrate + + ENV["VERBOSE"] = "yes" + ENV["VERSION"] = "unknown" + ActiveRecord::Migrator.expects(:migrate).with("custom/path", 0) + ActiveRecord::Migration.expects(:verbose=).with(true) + ActiveRecord::Migration.expects(:verbose=).with(ActiveRecord::Migration.verbose) ActiveRecord::Tasks::DatabaseTasks.migrate ensure ENV["VERBOSE"], ENV["VERSION"] = verbose, version diff --git a/activerecord/test/cases/transactions_test.rb b/activerecord/test/cases/transactions_test.rb index 5c6d78b574..111495c481 100644 --- a/activerecord/test/cases/transactions_test.rb +++ b/activerecord/test/cases/transactions_test.rb @@ -10,7 +10,7 @@ require "models/movie" class TransactionTest < ActiveRecord::TestCase self.use_transactional_tests = false - fixtures :topics, :developers, :authors, :author_addresses, :posts + fixtures :topics, :developers, :authors, :posts def setup @first, @second = Topic.find(1, 2).sort_by(&:id) diff --git a/activerecord/test/cases/yaml_serialization_test.rb b/activerecord/test/cases/yaml_serialization_test.rb index ab0e67cd9d..1571b31329 100644 --- a/activerecord/test/cases/yaml_serialization_test.rb +++ b/activerecord/test/cases/yaml_serialization_test.rb @@ -5,7 +5,7 @@ require "models/post" require "models/author" class YamlSerializationTest < ActiveRecord::TestCase - fixtures :topics, :authors, :author_addresses, :posts + fixtures :topics, :authors, :posts def test_to_yaml_with_time_with_zone_should_not_raise_exception with_timezone_config aware_attributes: true, zone: "Pacific Time (US & Canada)" do diff --git a/activerecord/test/models/comment.rb b/activerecord/test/models/comment.rb index a4b81d56e0..76b484e616 100644 --- a/activerecord/test/models/comment.rb +++ b/activerecord/test/models/comment.rb @@ -19,6 +19,11 @@ class Comment < ActiveRecord::Base has_many :children, class_name: "Comment", foreign_key: :parent_id belongs_to :parent, class_name: "Comment", counter_cache: :children_count + # Should not be called if extending modules that having the method exists on an association. + def self.greeting + raise + end + def self.what_are_you "a comment..." end diff --git a/activerecord/test/models/company.rb b/activerecord/test/models/company.rb index 20e37710e7..d269a95e8c 100644 --- a/activerecord/test/models/company.rb +++ b/activerecord/test/models/company.rb @@ -170,14 +170,6 @@ class Client < Company def overwrite_to_raise end - - class << self - private - - def private_method - "darkness" - end - end end class ExclusivelyDependentFirm < Company diff --git a/activesupport/lib/active_support/duration.rb b/activesupport/lib/active_support/duration.rb index 99080e34a1..d4424ed792 100644 --- a/activesupport/lib/active_support/duration.rb +++ b/activesupport/lib/active_support/duration.rb @@ -305,10 +305,6 @@ module ActiveSupport to_i end - def respond_to_missing?(method, include_private = false) #:nodoc: - @value.respond_to?(method, include_private) - end - # Build ISO 8601 Duration string for this duration. # The +precision+ parameter can be used to limit seconds' precision of duration. def iso8601(precision: nil) @@ -335,8 +331,12 @@ module ActiveSupport end end + def respond_to_missing?(method, _) + value.respond_to?(method) + end + def method_missing(method, *args, &block) - value.send(method, *args, &block) + value.public_send(method, *args, &block) end def raise_type_error(other) diff --git a/activesupport/test/core_ext/enumerable_test.rb b/activesupport/test/core_ext/enumerable_test.rb index 4f1ab993b8..0b345ecf0f 100644 --- a/activesupport/test/core_ext/enumerable_test.rb +++ b/activesupport/test/core_ext/enumerable_test.rb @@ -171,10 +171,8 @@ class EnumerableTests < ActiveSupport::TestCase assert_equal({ 5 => Payment.new(5), 15 => Payment.new(15), 10 => Payment.new(10) }, payments.index_by(&:price)) assert_equal Enumerator, payments.index_by.class - if Enumerator.method_defined? :size - assert_nil payments.index_by.size - assert_equal 42, (1..42).index_by.size - end + assert_nil payments.index_by.size + assert_equal 42, (1..42).index_by.size assert_equal({ 5 => Payment.new(5), 15 => Payment.new(15), 10 => Payment.new(10) }, payments.index_by.each(&:price)) end diff --git a/guides/source/5_1_release_notes.md b/guides/source/5_1_release_notes.md index ffa18f1a2b..0f6167f1ee 100644 --- a/guides/source/5_1_release_notes.md +++ b/guides/source/5_1_release_notes.md @@ -40,7 +40,7 @@ Major Features [Pull Request](https://github.com/rails/rails/pull/26836) -Rails 5.1 will allow managing JavaScript dependencies +Rails 5.1 allows managing JavaScript dependencies from NPM via Yarn. This will make it easy to use libraries like React, VueJS or any other library from NPM world. The Yarn support is integrated with the asset pipeline so that all dependencies will work seamlessly with the @@ -70,14 +70,14 @@ offerings. It is no longer required, as the UJS has been rewritten to use plain, vanilla JavaScript. This code now ships inside of Action View as `rails-ujs`. -You can still use the jQuery version if needed, but it is no longer required by default. +You can still use jQuery if needed, but it is no longer required by default. ### System tests [Pull Request](https://github.com/rails/rails/pull/26703) Rails 5.1 has baked-in support for writing Capybara tests, in the form of -System tests. You need no longer worry about configuring Capybara and +System tests. You no longer need to worry about configuring Capybara and database cleaning strategies for such tests. Rails 5.1 provides a wrapper for running tests in Chrome with additional features such as failure screenshots. @@ -86,7 +86,7 @@ screenshots. [Pull Request](https://github.com/rails/rails/pull/28038) -Rails will now allow management of application secrets in a secure way, +Rails now allows management of application secrets in a secure way, building on top of the [sekrets](https://github.com/ahoward/sekrets) gem. Run `bin/rails secrets:setup` to setup a new encrypted secrets file. This will @@ -106,33 +106,24 @@ order to share instance variables, headers and other common setup. ``` ruby class InvitationsMailer < ApplicationMailer - before_action { @inviter, @invitee = params[:inviter], params[:invitee] } before_action { @account = params[:inviter].account } def account_invitation mail subject: "#{@inviter.name} invited you to their Basecamp (#{@account.name})" end - - def project_invitation - @project = params[:project] - @summarizer = ProjectInvitationSummarizer.new(@project.bucket) - - mail subject: "#{@inviter.name.familiar} added you to a project in Basecamp (#{@account.name})" - end end -InvitationsMailer.with(inviter: person_a, invitee: person_b).account_invitation.deliver_later +InvitationsMailer.with(inviter: person_a, invitee: person_b) + .account_invitation.deliver_later ``` ### Direct & resolved routes [Pull Request](https://github.com/rails/rails/pull/23138) -Rails 5.1 has added two new methods, `resolve` and `direct`, to the routing -DSL. - -The `resolve` method allows customizing polymorphic mapping of models. +Rails 5.1 adds two new methods, `resolve` and `direct`, to the routing +DSL. The `resolve` method allows customizing polymorphic mapping of models. ``` ruby resource :basket @@ -181,50 +172,94 @@ Before Rails 5.1, there were two interfaces for handling HTML forms: Rails 5.1 combines both of these interfaces with `form_with`, and can generate form tags based on URLs, scopes or models. -``` erb -# Using just a URL: +Using just a URL: +``` erb <%= form_with url: posts_path do |form| %> <%= form.text_field :title %> <% end %> -# => +<%# Will generate %> + <form action="/posts" method="post" data-remote="true"> <input type="text" name="title"> </form> +``` -# Adding a scope prefixes the input field names: +Adding a scope prefixes the input field names: +``` erb <%= form_with scope: :post, url: posts_path do |form| %> <%= form.text_field :title %> <% end %> -# => + +<%# Will generate %> + <form action="/posts" method="post" data-remote="true"> <input type="text" name="post[title]"> </form> +``` -# Using a model infers both the URL and scope: +Using a model infers both the URL and scope: +``` erb <%= form_with model: Post.new do |form| %> <%= form.text_field :title %> <% end %> -# => + +<%# Will generate %> + <form action="/posts" method="post" data-remote="true"> <input type="text" name="post[title]"> </form> +``` -# An existing model makes an update form and fills out field values: +An existing model makes an update form and fills out field values: +``` erb <%= form_with model: Post.first do |form| %> <%= form.text_field :title %> <% end %> -# => + +<%# Will generate %> + <form action="/posts/1" method="post" data-remote="true"> <input type="hidden" name="_method" value="patch"> <input type="text" name="post[title]" value="<the title of the post>"> </form> ``` +Incompatibilities +----------------- + +The following changes may require immediate action upon upgrade. + +### Transactional tests with multiple connections + +Transactional tests now wrap all Active Record connections in database +transactions. + +When a test spawns additional threads, and those threads obtain database +connections, those connections are now handled specially: + +The threads will share a single connection, which is inside the managed +transaction. This ensures all threads see the database in the same +state, ignoring the outermost transaction. Previously, such additional +connections were unable to see the fixture rows, for example. + +When a thread enters a nested transaction, it will temporarily obtain +exclusive use of the connection, to maintain isolation. + +If your tests currently rely on obtaining a separate, +outside-of-transaction, connection in a spawned thread, you'll need to +switch to more explicit connection management. + +If your tests spawn threads and those threads interact while also using +explicit database transactions, this change may introduce a deadlock. + +The easy way to opt out of this new behavior is to disable transactional +tests on any test cases it affects. + Railties -------- @@ -233,7 +268,7 @@ Please refer to the [Changelog][railties] for detailed changes. ### Removals * Remove deprecated `config.static_cache_control`. - ([commit](https://github.com/rails/rails/commit/c861decd44198f8d7d774ee6a74194d1ac1a5a13) + ([commit](https://github.com/rails/rails/commit/c861decd44198f8d7d774ee6a74194d1ac1a5a13)) * Remove deprecated `config.serve_static_files`. ([commit](https://github.com/rails/rails/commit/0129ca2eeb6d5b2ea8c6e6be38eeb770fe45f1fa)) @@ -267,7 +302,7 @@ Please refer to the [Changelog][railties] for detailed changes. * Add Yarn support in new apps with a yarn binstub and package.json. ([Pull Request](https://github.com/rails/rails/pull/26836)) -* Add Webpack support in new apps via the --webpack option, which will delegate +* Add Webpack support in new apps via the `--webpack` option, which will delegate to the rails/webpacker gem. ([Pull Request](https://github.com/rails/rails/pull/27288)) @@ -278,6 +313,9 @@ Please refer to the [Changelog][railties] for detailed changes. * Add encrypted secrets in `config/secrets.yml.enc`. ([Pull Request](https://github.com/rails/rails/pull/28038)) +* Display railtie class name in `rails initializers`. + ([Pull Request](https://github.com/rails/rails/pull/25257)) + Action Cable ----------- @@ -293,7 +331,7 @@ Please refer to the [Changelog][action-cable] for detailed changes. * Permit same-origin connections by default. ([commit](https://github.com/rails/rails/commit/dae404473409fcab0e07976aec626df670e52282)) -* Add `ActiveSupport::Notifications` hook for broadcasing data. +* Add `ActiveSupport::Notifications` hook for broadcasting data. ([Pull Request](https://github.com/rails/rails/pull/24988)) Action Pack @@ -303,10 +341,37 @@ Please refer to the [Changelog][action-pack] for detailed changes. ### Removals +* Removed support to non-keyword arguments in `#process`, `#get`, `#post`, + `#patch`, `#put`, `#delete`, and `#head` for the `ActionDispatch::IntegrationTest` + and `ActionController::TestCase` classes. + ([Commit](https://github.com/rails/rails/commit/98b8309569a326910a723f521911e54994b112fb), + [Commit](https://github.com/rails/rails/commit/de9542acd56f60d281465a59eac11e15ca8b3323)) + +* Removed deprecated `ActionDispatch::Callbacks.to_prepare` and + `ActionDispatch::Callbacks.to_cleanup`. + ([Commit](https://github.com/rails/rails/commit/3f2b7d60a52ffb2ad2d4fcf889c06b631db1946b)) + +* Removed deprecated methods related to controller filters. + ([Commit](https://github.com/rails/rails/commit/d7be30e8babf5e37a891522869e7b0191b79b757)) + ### Deprecations +* Deprecated `:controller` and `:action` path parameters. + ([Pull Request](https://github.com/rails/rails/pull/23980)) + +* Deprecated `config.action_controller.raise_on_unfiltered_parameters`. + It doesn't have any effect in Rails 5.1. + ([Commit](https://github.com/rails/rails/commit/c6640fb62b10db26004a998d2ece98baede509e5)) + ### Notable changes +* Added the `direct` and `resolve` methods to the routing DSL. + ([Pull Request](https://github.com/rails/rails/pull/23138)) + +* Added a new `ActionDispatch::SystemTestCase` class to write system tests in + your applications. + ([Pull Request](https://github.com/rails/rails/pull/26703)) + Action View ------------- @@ -341,6 +406,9 @@ Please refer to the [Changelog][action-view] for detailed changes. * Add `form_with` to unify `form_tag` and `form_for` usage. ([Pull Request](https://github.com/rails/rails/pull/26976)) +* Add `check_parameters` option to `current_page?`. + ([Pull Request](https://github.com/rails/rails/pull/27549)) + Action Mailer ------------- @@ -378,6 +446,19 @@ Please refer to the [Changelog][active-record] for detailed changes. ### Notable changes +* Change Default Primary Keys to BIGINT. + ([Pull Request](https://github.com/rails/rails/pull/26266)) + +* Virtual/generated column support for MySQL 5.7.5+ and MariaDB 5.2.0+. + ([Commit](https://github.com/rails/rails/commit/65bf1c60053e727835e06392d27a2fb49665484c)) + +* Added support for limits in batch processing. + ([Commit](https://github.com/rails/rails/commit/451437c6f57e66cc7586ec966e530493927098c7)) + +* Transactional tests now wrap all Active Record connections in database + transactions. + ([Pull Request](https://github.com/rails/rails/pull/28726)) + * Skipped comments in the output of `mysqldump` command by default. ([Pull Request](https://github.com/rails/rails/pull/23301)) @@ -389,6 +470,9 @@ Please refer to the [Changelog][active-record] for detailed changes. * Pass `"-v ON_ERROR_STOP=1"` flag with `psql` command to not suppress SQL errors. ([Pull Request](https://github.com/rails/rails/pull/24773)) +* Add `ActiveRecord::Base.connection_pool.stat`. + ([Pull Request](https://github.com/rails/rails/pull/26988)) + Active Model ------------ @@ -440,10 +524,36 @@ Please refer to the [Changelog][active-support] for detailed changes. ### Removals +* Removed the `ActiveSupport::Concurrency::Latch` class. + ([Commit](https://github.com/rails/rails/commit/0d7bd2031b4054fbdeab0a00dd58b1b08fb7fea6)) + +* Removed `halt_callback_chains_on_return_false`. + ([Commit](https://github.com/rails/rails/commit/4e63ce53fc25c3bc15c5ebf54bab54fa847ee02a)) + +* Removed deprecated behavior that halts callbacks when the return is false. + ([Commit](https://github.com/rails/rails/commit/3a25cdca3e0d29ee2040931d0cb6c275d612dffe)) + ### Deprecations +* The top level `HashWithIndifferentAccess` class has been softly deprecated + in favor of the `ActiveSupport::HashWithIndifferentAccess` one. + ([Pull request](https://github.com/rails/rails/pull/28157)) + +* Deprecate passing string to `:if` and `:unless` conditional options on `set_callback` and `skip_callback`. + ([Commit](https://github.com/rails/rails/commit/0952552) + ### Notable changes +* Fixed duration parsing and traveling to make it consistent across DST changes. + ([Commit](https://github.com/rails/rails/commit/8931916f4a1c1d8e70c06063ba63928c5c7eab1e), + [Pull Request](https://github.com/rails/rails/pull/26597)) + +* Updated Unicode to version 9.0.0. + ([Pull Request](https://github.com/rails/rails/pull/27822)) + +* Add Duration#before and #after as aliases for #ago and #since. + ([Pull Request](https://github.com/rails/rails/pull/27721)) + * Added `Module#delegate_missing_to` to delegate method calls not defined for the current object to a proxy object. ([Pull Request](https://github.com/rails/rails/pull/23930)) @@ -452,6 +562,15 @@ Please refer to the [Changelog][active-support] for detailed changes. of the current date & time. ([Pull Request](https://github.com/rails/rails/pull/24930)) +* Introduced the `assert_changes` and `assert_no_changes` methods for tests. + ([Pull Request](https://github.com/rails/rails/pull/25393)) + +* The `travel` and `travel_to` methods now raise on nested calls. + ([Pull Request](https://github.com/rails/rails/pull/24890)) + +* Update `DateTime#change` to support usec and nsec. + ([Pull Request](https://github.com/rails/rails/pull/28242)) + Credits ------- diff --git a/guides/source/configuring.md b/guides/source/configuring.md index ae70b06996..bf9456a482 100644 --- a/guides/source/configuring.md +++ b/guides/source/configuring.md @@ -543,6 +543,8 @@ encrypted cookies salt value. Defaults to `'signed encrypted cookie'`. * `config.action_view.debug_missing_translation` determines whether to wrap the missing translations key in a `<span>` tag or not. This defaults to `true`. +* `config.action_view.form_with_generates_remote_forms` determines whether `form_with` generates remote forms or not. This defaults to `true`. + ### Configuring Action Mailer There are a number of settings available on `config.action_mailer`: diff --git a/guides/source/getting_started.md b/guides/source/getting_started.md index 18331bb73b..f3ae5a5b28 100644 --- a/guides/source/getting_started.md +++ b/guides/source/getting_started.md @@ -182,7 +182,7 @@ of the files and folders that Rails created by default: |test/|Unit tests, fixtures, and other test apparatus. These are covered in [Testing Rails Applications](testing.html).| |tmp/|Temporary files (like cache and pid files).| |vendor/|A place for all third-party code. In a typical Rails application this includes vendored gems.| -|.gitignore|This file tells git which files (or patterns) it should ignore. See [Github - Ignoring files](https://help.github.com/articles/ignoring-files) for more info about ignoring files. +|.gitignore|This file tells git which files (or patterns) it should ignore. See [GitHub - Ignoring files](https://help.github.com/articles/ignoring-files) for more info about ignoring files. Hello, Rails! ------------- diff --git a/railties/lib/rails/generators/rails/app/templates/bin/yarn b/railties/lib/rails/generators/rails/app/templates/bin/yarn index 4ae896a8d3..44f75c22a4 100644 --- a/railties/lib/rails/generators/rails/app/templates/bin/yarn +++ b/railties/lib/rails/generators/rails/app/templates/bin/yarn @@ -3,7 +3,8 @@ Dir.chdir(VENDOR_PATH) do begin exec "yarnpkg #{ARGV.join(" ")}" rescue Errno::ENOENT - puts "Yarn executable was not detected in the system." - puts "Download Yarn at https://yarnpkg.com/en/docs/install" + $stderr.puts "Yarn executable was not detected in the system." + $stderr.puts "Download Yarn at https://yarnpkg.com/en/docs/install" + exit 1 end end diff --git a/railties/lib/rails/mailers_controller.rb b/railties/lib/rails/mailers_controller.rb index 000ce40fbc..7ff55ef5bf 100644 --- a/railties/lib/rails/mailers_controller.rb +++ b/railties/lib/rails/mailers_controller.rb @@ -6,6 +6,8 @@ class Rails::MailersController < Rails::ApplicationController # :nodoc: before_action :require_local!, unless: :show_previews? before_action :find_preview, only: :preview + helper_method :part_query + def index @previews = ActionMailer::Preview.all @page_title = "Mailer Previews" @@ -19,7 +21,7 @@ class Rails::MailersController < Rails::ApplicationController # :nodoc: @email_action = File.basename(params[:path]) if @preview.email_exists?(@email_action) - @email = @preview.call(@email_action) + @email = @preview.call(@email_action, params) if params[:part] part_type = Mime::Type.lookup(params[:part]) @@ -76,4 +78,8 @@ class Rails::MailersController < Rails::ApplicationController # :nodoc: @email end end + + def part_query(mime_type) + request.query_parameters.merge(part: mime_type).to_query + end end diff --git a/railties/lib/rails/railtie.rb b/railties/lib/rails/railtie.rb index 474118c0a9..3476bb0eb5 100644 --- a/railties/lib/rails/railtie.rb +++ b/railties/lib/rails/railtie.rb @@ -162,10 +162,6 @@ module Rails @instance ||= new end - def respond_to_missing?(*args) - instance.respond_to?(*args) || super - end - # Allows you to configure the railtie. This is the same method seen in # Railtie::Configurable, but this module is no longer required for all # subclasses of Railtie so we provide the class method here. @@ -178,6 +174,10 @@ module Rails ActiveSupport::Inflector.underscore(string).tr("/", "_") end + def respond_to_missing?(name, _) + instance.respond_to?(name) || super + end + # If the class method does not have a method, then send the method call # to the Railtie instance. def method_missing(name, *args, &block) diff --git a/railties/lib/rails/templates/rails/mailers/email.html.erb b/railties/lib/rails/templates/rails/mailers/email.html.erb index c63781ed0c..89c1129f90 100644 --- a/railties/lib/rails/templates/rails/mailers/email.html.erb +++ b/railties/lib/rails/templates/rails/mailers/email.html.erb @@ -98,8 +98,8 @@ <% if @email.multipart? %> <dd> <select onchange="formatChanged(this);"> - <option <%= request.format == Mime[:html] ? 'selected' : '' %> value="?part=text%2Fhtml">View as HTML email</option> - <option <%= request.format == Mime[:text] ? 'selected' : '' %> value="?part=text%2Fplain">View as plain-text email</option> + <option <%= request.format == Mime[:html] ? 'selected' : '' %> value="?<%= part_query('text/html') %>">View as HTML email</option> + <option <%= request.format == Mime[:text] ? 'selected' : '' %> value="?<%= part_query('text/plain') %>">View as plain-text email</option> </select> </dd> <% end %> @@ -107,7 +107,7 @@ </header> <% if @part && @part.mime_type %> - <iframe seamless name="messageBody" src="?part=<%= Rack::Utils.escape(@part.mime_type) %>"></iframe> + <iframe seamless name="messageBody" src="?<%= part_query(@part.mime_type) %>"></iframe> <% else %> <p> You are trying to preview an email that does not have any content. diff --git a/railties/test/application/mailer_previews_test.rb b/railties/test/application/mailer_previews_test.rb index c3a360e5d4..f5c013dab6 100644 --- a/railties/test/application/mailer_previews_test.rb +++ b/railties/test/application/mailer_previews_test.rb @@ -485,6 +485,57 @@ module ApplicationTests assert_match '<li><a href="/my_app/rails/mailers/notifier/foo">foo</a></li>', last_response.body end + test "mailer preview receives query params" do + mailer "notifier", <<-RUBY + class Notifier < ActionMailer::Base + default from: "from@example.com" + + def foo(name) + @name = name + mail to: "to@example.org" + end + end + RUBY + + html_template "notifier/foo", <<-RUBY + <p>Hello, <%= @name %>!</p> + RUBY + + text_template "notifier/foo", <<-RUBY + Hello, <%= @name %>! + RUBY + + mailer_preview "notifier", <<-RUBY + class NotifierPreview < ActionMailer::Preview + def foo + Notifier.foo(params[:name] || "World") + end + end + RUBY + + app("development") + + get "/rails/mailers/notifier/foo.txt" + assert_equal 200, last_response.status + assert_match '<iframe seamless name="messageBody" src="?part=text%2Fplain">', last_response.body + assert_match '<option selected value="?part=text%2Fplain">', last_response.body + assert_match '<option value="?part=text%2Fhtml">', last_response.body + + get "/rails/mailers/notifier/foo?part=text%2Fplain" + assert_equal 200, last_response.status + assert_match %r[Hello, World!], last_response.body + + get "/rails/mailers/notifier/foo.html?name=Ruby" + assert_equal 200, last_response.status + assert_match '<iframe seamless name="messageBody" src="?name=Ruby&part=text%2Fhtml">', last_response.body + assert_match '<option selected value="?name=Ruby&part=text%2Fhtml">', last_response.body + assert_match '<option value="?name=Ruby&part=text%2Fplain">', last_response.body + + get "/rails/mailers/notifier/foo?name=Ruby&part=text%2Fhtml" + assert_equal 200, last_response.status + assert_match %r[<p>Hello, Ruby!</p>], last_response.body + end + test "plain text mailer preview with attachment" do image_file "pixel.png", "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAAA1BMVEWzIioca/JlAAAACklEQVQI12NgAAAAAgAB4iG8MwAAAABJRU5ErkJgggo=" diff --git a/railties/test/application/middleware/exceptions_test.rb b/railties/test/application/middleware/exceptions_test.rb index cbb990f13b..fe07ad3cbe 100644 --- a/railties/test/application/middleware/exceptions_test.rb +++ b/railties/test/application/middleware/exceptions_test.rb @@ -100,6 +100,20 @@ module ApplicationTests end end + test "routing to an nonexistent controller when action_dispatch.show_exceptions and consider_all_requests_local are set shows diagnostics" do + app_file "config/routes.rb", <<-RUBY + Rails.application.routes.draw do + resources :articles + end + RUBY + + app.config.action_dispatch.show_exceptions = true + app.config.consider_all_requests_local = true + + get "/articles" + assert_match "<title>Action Controller: Exception caught</title>", last_response.body + end + test "displays diagnostics message when exception raised in template that contains UTF-8" do controller :foo, <<-RUBY class FooController < ActionController::Base diff --git a/railties/test/isolation/abstract_unit.rb b/railties/test/isolation/abstract_unit.rb index 924503a522..2e742a005e 100644 --- a/railties/test/isolation/abstract_unit.rb +++ b/railties/test/isolation/abstract_unit.rb @@ -119,7 +119,7 @@ module TestHelpers end routes = File.read("#{app_path}/config/routes.rb") - if routes =~ /(\n\s*end\s*)\Z/ + if routes =~ /(\n\s*end\s*)\z/ File.open("#{app_path}/config/routes.rb", "w") do |f| f.puts $` + "\nActiveSupport::Deprecation.silence { match ':controller(/:action(/:id))(.:format)', via: :all }\n" + $1 end @@ -251,7 +251,7 @@ module TestHelpers def add_to_config(str) environment = File.read("#{app_path}/config/application.rb") - if environment =~ /(\n\s*end\s*end\s*)\Z/ + if environment =~ /(\n\s*end\s*end\s*)\z/ File.open("#{app_path}/config/application.rb", "w") do |f| f.puts $` + "\n#{str}\n" + $1 end @@ -260,7 +260,7 @@ module TestHelpers def add_to_env_config(env, str) environment = File.read("#{app_path}/config/environments/#{env}.rb") - if environment =~ /(\n\s*end\s*)\Z/ + if environment =~ /(\n\s*end\s*)\z/ File.open("#{app_path}/config/environments/#{env}.rb", "w") do |f| f.puts $` + "\n#{str}\n" + $1 end |