diff options
31 files changed, 81 insertions, 55 deletions
diff --git a/actionmailer/lib/action_mailer/base.rb b/actionmailer/lib/action_mailer/base.rb index 1ab68d2953..798241aaf8 100644 --- a/actionmailer/lib/action_mailer/base.rb +++ b/actionmailer/lib/action_mailer/base.rb @@ -39,11 +39,8 @@ module ActionMailer # in the same manner as <tt>attachments[]=</tt> # # * <tt>headers[]=</tt> - Allows you to specify any header field in your email such - # as <tt>headers['X-No-Spam'] = 'True'</tt>. Note, while most fields like <tt>To:</tt> - # <tt>From:</tt> can only appear once in an email header, other fields like <tt>X-Anything</tt> - # can appear multiple times. If you want to change a field that can appear multiple times, - # you need to set it to nil first so that Mail knows you are replacing it and not adding - # another field of the same name. + # as <tt>headers['X-No-Spam'] = 'True'</tt>. Note that declaring a header multiple times + # will add many fields of the same name. Read #headers doc for more information. # # * <tt>headers(hash)</tt> - Allows you to specify multiple headers in your email such # as <tt>headers({'X-No-Spam' => 'True', 'In-Reply-To' => '1234@message.id'})</tt> @@ -625,6 +622,26 @@ module ActionMailer # The resulting <tt>Mail::Message</tt> will have the following in its header: # # X-Special-Domain-Specific-Header: SecretValue + # + # Note about replacing already defined headers: + # + # * +subject+ + # * +sender+ + # * +from+ + # * +to+ + # * +cc+ + # * +bcc+ + # * +reply-to+ + # * +orig-date+ + # * +message-id+ + # * +references+ + # + # Fields can only appear once in email headers while other fields such as + # <tt>X-Anything</tt> can appear multiple times. + # + # If you want to replace any header which already exists, first set it to + # +nil+ in order to reset the value otherwise another field will be added + # for the same header. def headers(args = nil) if args @_message.headers(args) diff --git a/actionmailer/lib/action_mailer/message_delivery.rb b/actionmailer/lib/action_mailer/message_delivery.rb index 7118f9b02c..c18e914f37 100644 --- a/actionmailer/lib/action_mailer/message_delivery.rb +++ b/actionmailer/lib/action_mailer/message_delivery.rb @@ -46,6 +46,7 @@ module ActionMailer # # * <tt>:wait</tt> - Enqueue the email to be delivered with a delay # * <tt>:wait_until</tt> - Enqueue the email to be delivered at (after) a specific date / time + # * <tt>:queue</tt> - Enqueue the email on the specified queue def deliver_later!(options={}) enqueue_delivery :deliver_now!, options end @@ -61,6 +62,7 @@ module ActionMailer # # * <tt>:wait</tt> - Enqueue the email to be delivered with a delay # * <tt>:wait_until</tt> - Enqueue the email to be delivered at (after) a specific date / time + # * <tt>:queue</tt> - Enqueue the email on the specified queue def deliver_later(options={}) enqueue_delivery :deliver_now, options end diff --git a/actionpack/lib/action_controller/metal.rb b/actionpack/lib/action_controller/metal.rb index bfbc15a901..6dd213b2f7 100644 --- a/actionpack/lib/action_controller/metal.rb +++ b/actionpack/lib/action_controller/metal.rb @@ -165,7 +165,7 @@ module ActionController headers["Location"] = url end - # basic url_for that can be overridden for more robust functionality + # Basic url_for that can be overridden for more robust functionality def url_for(string) string end @@ -182,7 +182,7 @@ module ActionController body = [body] unless body.nil? || body.respond_to?(:each) super end - + # Tests if render or redirect has already happened. def performed? response_body || (response && response.committed?) @@ -237,7 +237,7 @@ module ActionController end end - def _status_code + def _status_code #:nodoc: @_status end end diff --git a/actionpack/lib/action_controller/metal/rack_delegation.rb b/actionpack/lib/action_controller/metal/rack_delegation.rb index 6921834044..545d4a7e6e 100644 --- a/actionpack/lib/action_controller/metal/rack_delegation.rb +++ b/actionpack/lib/action_controller/metal/rack_delegation.rb @@ -6,7 +6,7 @@ module ActionController extend ActiveSupport::Concern delegate :headers, :status=, :location=, :content_type=, - :status, :location, :content_type, :_status_code, :to => "@_response" + :status, :location, :content_type, :response_code, :to => "@_response" def dispatch(action, request) set_response!(request) diff --git a/actionpack/lib/action_dispatch/http/response.rb b/actionpack/lib/action_dispatch/http/response.rb index c5e18048da..99d46af953 100644 --- a/actionpack/lib/action_dispatch/http/response.rb +++ b/actionpack/lib/action_dispatch/http/response.rb @@ -309,9 +309,6 @@ module ActionDispatch # :nodoc: cookies end - def _status_code - @status - end private def before_committed diff --git a/activejob/Rakefile b/activejob/Rakefile index a66df8939e..7e66860b36 100644 --- a/activejob/Rakefile +++ b/activejob/Rakefile @@ -35,6 +35,7 @@ namespace :test do t.libs << 'test' t.test_files = FileList['test/cases/**/*_test.rb'] t.verbose = true + t.warning = true t.ruby_opts = ["--dev"] if defined?(JRUBY_VERSION) end @@ -53,6 +54,7 @@ namespace :test do t.libs << 'test' t.test_files = FileList['test/integration/**/*_test.rb'] t.verbose = true + t.warning = true t.ruby_opts = ["--dev"] if defined?(JRUBY_VERSION) end end diff --git a/activejob/lib/active_job/base.rb b/activejob/lib/active_job/base.rb index 8f4b37222a..0c4a29090e 100644 --- a/activejob/lib/active_job/base.rb +++ b/activejob/lib/active_job/base.rb @@ -9,14 +9,14 @@ require 'active_job/logging' module ActiveJob #:nodoc: # = Active Job # - # Active job objects can be configured to work with different backend + # Active Job objects can be configured to work with different backend # queuing frameworks. To specify a queue adapter to use: # # ActiveJob::Base.queue_adapter = :inline # # A list of supported adapters can be found in QueueAdapters. # - # Active job objects can be defined by creating a class that inherits + # Active Job objects can be defined by creating a class that inherits # from the ActiveJob::Base class. The only necessary method to # implement is the "perform" method. # @@ -34,16 +34,20 @@ module ActiveJob #:nodoc: # Records that are passed in are serialized/deserialized using Global # Id. More information can be found in Arguments. # - # To queue a job to be processed asynchronously immediately: + # To enqueue a job to be performed as soon the queueing system is free: # # ProcessPhotoJob.perform_later(photo) # - # To queue a job to be processed at some point in the future: + # To enqueue a job to be processed at some point in the future: # # ProcessPhotoJob.set(wait_until: Date.tomorrow.noon).perform_later(photo) # # More information can be found in ActiveJob::Core::ClassMethods#set # + # A job can also be processed immediately without sending to the queue: + # + # ProcessPhotoJob.perform_now(photo) + # # == Exceptions # # * DeserializationError - Error class for deserialization errors. diff --git a/activejob/lib/active_job/enqueuing.rb b/activejob/lib/active_job/enqueuing.rb index 74bcc1fa5d..cca0a2a8d6 100644 --- a/activejob/lib/active_job/enqueuing.rb +++ b/activejob/lib/active_job/enqueuing.rb @@ -10,7 +10,7 @@ module ActiveJob # GlobalID::Identification instances. Arbitrary Ruby objects # are not supported. # - # Returns an instance of the job class queued with args available in + # Returns an instance of the job class queued with arguments available in # Job#arguments. def perform_later(*args) job_or_instantiate(*args).enqueue diff --git a/activejob/lib/active_job/test_helper.rb b/activejob/lib/active_job/test_helper.rb index af62fae9b9..ade7a94c9d 100644 --- a/activejob/lib/active_job/test_helper.rb +++ b/activejob/lib/active_job/test_helper.rb @@ -71,7 +71,7 @@ module ActiveJob # # Note: This assertion is simply a shortcut for: # - # assert_enqueued_jobs 0 + # assert_enqueued_jobs 0, &block def assert_no_enqueued_jobs(&block) assert_enqueued_jobs 0, &block end @@ -130,7 +130,7 @@ module ActiveJob # # Note: This assertion is simply a shortcut for: # - # assert_performed_jobs 0 + # assert_performed_jobs 0, &block def assert_no_performed_jobs(&block) assert_performed_jobs 0, &block end diff --git a/activejob/test/cases/logging_test.rb b/activejob/test/cases/logging_test.rb index 9c56ee08b6..3d4e561117 100644 --- a/activejob/test/cases/logging_test.rb +++ b/activejob/test/cases/logging_test.rb @@ -33,7 +33,7 @@ class AdapterTest < ActiveSupport::TestCase def teardown super ActiveJob::Logging::LogSubscriber.log_subscribers.pop - ActiveJob::Base.logger = @old_logger + set_logger @old_logger end def set_logger(logger) diff --git a/activejob/test/cases/rescue_test.rb b/activejob/test/cases/rescue_test.rb index 1b6c2e9fac..58c9ca8992 100644 --- a/activejob/test/cases/rescue_test.rb +++ b/activejob/test/cases/rescue_test.rb @@ -2,8 +2,6 @@ require 'helper' require 'jobs/rescue_job' require 'models/person' -require 'active_support/core_ext/object/inclusion' - class RescueTest < ActiveSupport::TestCase setup do JobBuffer.clear diff --git a/activejob/test/helper.rb b/activejob/test/helper.rb index ce22833b11..ec0c8a8ede 100644 --- a/activejob/test/helper.rb +++ b/activejob/test/helper.rb @@ -26,5 +26,4 @@ end require 'active_support/testing/autorun' -ActiveJob::Base.logger.level = Logger::DEBUG ActiveSupport::TestCase.test_order = :random diff --git a/activejob/test/support/integration/adapters/backburner.rb b/activejob/test/support/integration/adapters/backburner.rb index 0cda36a273..2e82562948 100644 --- a/activejob/test/support/integration/adapters/backburner.rb +++ b/activejob/test/support/integration/adapters/backburner.rb @@ -29,7 +29,7 @@ module BackburnerJobsManager def can_run? begin Backburner::Worker.connection.send :connect! - rescue => e + rescue return false end true diff --git a/activejob/test/support/integration/adapters/qu.rb b/activejob/test/support/integration/adapters/qu.rb index e913f04a24..3a5b66a057 100644 --- a/activejob/test/support/integration/adapters/qu.rb +++ b/activejob/test/support/integration/adapters/qu.rb @@ -30,7 +30,7 @@ module QuJobsManager def can_run? begin Qu.backend.connection.client.connect - rescue => e + rescue return false end true diff --git a/activejob/test/support/integration/adapters/resque.rb b/activejob/test/support/integration/adapters/resque.rb index 9de3e7c879..82acb17b2b 100644 --- a/activejob/test/support/integration/adapters/resque.rb +++ b/activejob/test/support/integration/adapters/resque.rb @@ -41,7 +41,7 @@ module ResqueJobsManager def can_run? begin Resque.redis.client.connect - rescue => e + rescue return false end true diff --git a/activejob/test/support/integration/adapters/sidekiq.rb b/activejob/test/support/integration/adapters/sidekiq.rb index 0a0a549c9e..3cc9a34993 100644 --- a/activejob/test/support/integration/adapters/sidekiq.rb +++ b/activejob/test/support/integration/adapters/sidekiq.rb @@ -49,7 +49,7 @@ module SidekiqJobsManager def can_run? begin Sidekiq.redis { |conn| conn.connect } - rescue => e + rescue return false end true diff --git a/activejob/test/support/integration/adapters/sneakers.rb b/activejob/test/support/integration/adapters/sneakers.rb index f21bb38a32..875803a2d8 100644 --- a/activejob/test/support/integration/adapters/sneakers.rb +++ b/activejob/test/support/integration/adapters/sneakers.rb @@ -68,7 +68,7 @@ module SneakersJobsManager def can_run? begin bunny_publisher - rescue => e + rescue return false end true diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md index b12d048169..e0e107e89d 100644 --- a/activerecord/CHANGELOG.md +++ b/activerecord/CHANGELOG.md @@ -1,3 +1,10 @@ +* `AR::UnknownAttributeError` now includes the class name of a record. + + User.new(name: "Yuki Nishijima", project_attributes: {name: "kaminari"}) + # => ActiveRecord::UnknownAttributeError: unknown attribute 'name' for User. + + *Yuki Nishijima* + * Fix regression causing `after_create` callbacks to run before associated records are autosaved. diff --git a/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb b/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb index ff8b3e9890..1a3ed28d66 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb @@ -337,8 +337,9 @@ module ActiveRecord # Returns an ActiveRecord::Result instance. def select(sql, name = nil, binds = []) + exec_query(sql, name, binds) end - undef_method :select + # Returns the last auto-generated ID from the affected table. def insert_sql(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil) diff --git a/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb b/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb index 38bdddefba..5b83131f0e 100644 --- a/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb @@ -232,11 +232,6 @@ module ActiveRecord alias exec_without_stmt exec_query - # Returns an ActiveRecord::Result instance. - def select(sql, name = nil, binds = []) - exec_query(sql, name) - end - def insert_sql(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil) super id_value || @connection.last_id diff --git a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb index da3aecf69a..cff6798eb3 100644 --- a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb @@ -465,7 +465,7 @@ module ActiveRecord def select(sql, name = nil, binds = []) @connection.query_with_result = true - rows = exec_query(sql, name, binds) + rows = super @connection.more_results && @connection.next_result # invoking stored procedures with CLIENT_MULTI_RESULTS requires this to tidy up else connection will be dropped rows end diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb index fe7648291d..3294238fa0 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb @@ -698,12 +698,6 @@ module ActiveRecord exec_query("SELECT currval('#{sequence_name}')", 'SQL') end - # Executes a SELECT query and returns the results, performing any data type - # conversions that are required to be performed here instead of in PostgreSQLColumn. - def select(sql, name = nil, binds = []) - exec_query(sql, name, binds) - end - # Returns the list of a table's column names, data types, and default values. # # The underlying query is roughly: diff --git a/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb b/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb index ebb311df57..4756896ac5 100644 --- a/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb @@ -514,10 +514,6 @@ module ActiveRecord register_class_with_limit m, %r(char)i, SQLite3String end - def select(sql, name = nil, binds = []) #:nodoc: - exec_query(sql, name, binds) - end - def table_structure(table_name) structure = exec_query("PRAGMA table_info(#{quote_table_name(table_name)})", 'SCHEMA').to_hash raise(ActiveRecord::StatementInvalid, "Could not find table '#{table_name}'") if structure.empty? diff --git a/activerecord/lib/active_record/errors.rb b/activerecord/lib/active_record/errors.rb index 52c70977ef..5b3fdf16f5 100644 --- a/activerecord/lib/active_record/errors.rb +++ b/activerecord/lib/active_record/errors.rb @@ -167,7 +167,7 @@ module ActiveRecord def initialize(record, attribute) @record = record @attribute = attribute.to_s - super("unknown attribute: #{attribute}") + super("unknown attribute '#{attribute}' for #{@record.class}.") end end diff --git a/activerecord/lib/active_record/relation/merger.rb b/activerecord/lib/active_record/relation/merger.rb index ac41d0aa80..545bf5debc 100644 --- a/activerecord/lib/active_record/relation/merger.rb +++ b/activerecord/lib/active_record/relation/merger.rb @@ -13,7 +13,7 @@ module ActiveRecord @hash = hash end - def merge + def merge #:nodoc: Merger.new(relation, other).merge end diff --git a/activerecord/test/cases/attribute_methods_test.rb b/activerecord/test/cases/attribute_methods_test.rb index 7ca7349528..c3e8ceb0da 100644 --- a/activerecord/test/cases/attribute_methods_test.rb +++ b/activerecord/test/cases/attribute_methods_test.rb @@ -736,11 +736,11 @@ class AttributeMethodsTest < ActiveRecord::TestCase def test_bulk_update_raise_unknown_attribute_error error = assert_raises(ActiveRecord::UnknownAttributeError) { - @target.new(:hello => "world") + Topic.new(hello: "world") } - assert_instance_of @target, error.record + assert_instance_of Topic, error.record assert_equal "hello", error.attribute - assert_equal "unknown attribute: hello", error.message + assert_equal "unknown attribute 'hello' for Topic.", error.message end def test_methods_override_in_multi_level_subclass diff --git a/activerecord/test/cases/serialized_attribute_test.rb b/activerecord/test/cases/serialized_attribute_test.rb index 46d4da53df..66f345d805 100644 --- a/activerecord/test/cases/serialized_attribute_test.rb +++ b/activerecord/test/cases/serialized_attribute_test.rb @@ -143,7 +143,7 @@ class SerializedAttributeTest < ActiveRecord::TestCase def test_serialized_attribute_should_raise_exception_on_assignment_with_wrong_type Topic.serialize(:content, Hash) assert_raise(ActiveRecord::SerializationTypeMismatch) do - topic = Topic.new(content: 'string') + Topic.new(content: 'string') end end diff --git a/activesupport/lib/active_support/core_ext/object/with_options.rb b/activesupport/lib/active_support/core_ext/object/with_options.rb index 42e87c4424..7d38e1d134 100644 --- a/activesupport/lib/active_support/core_ext/object/with_options.rb +++ b/activesupport/lib/active_support/core_ext/object/with_options.rb @@ -47,7 +47,21 @@ class Object # end # # <tt>with_options</tt> can also be nested since the call is forwarded to its receiver. - # Each nesting level will merge inherited defaults in addition to their own. + # + # NOTE: Each nesting level will merge inherited defaults in addition to their own. + # + # class Post < ActiveRecord::Base + # with_options if: :persisted?, length: { minimum: 50 } do + # validates :content, if: -> { content.present? } + # end + # end + # + # The code is equivalent to: + # + # validates :content, length: { minimum: 50 }, if: -> { content.present? } + # + # Hence the inherited default for `if` key is ignored. + # def with_options(options, &block) option_merger = ActiveSupport::OptionMerger.new(self, options) block.arity.zero? ? option_merger.instance_eval(&block) : block.call(option_merger) diff --git a/guides/source/active_record_validations.md b/guides/source/active_record_validations.md index cba4b852a1..1c1b863fe9 100644 --- a/guides/source/active_record_validations.md +++ b/guides/source/active_record_validations.md @@ -706,7 +706,7 @@ we don't want names and surnames to begin with lower case. ```ruby class Person < ActiveRecord::Base validates_each :name, :surname do |record, attr, value| - record.errors.add(attr, 'must start with upper case') if value =~ /\A[a-z]/ + record.errors.add(attr, 'must start with upper case') if value =~ /\A[[:lower:]]/ end end ``` diff --git a/guides/source/contributing_to_ruby_on_rails.md b/guides/source/contributing_to_ruby_on_rails.md index 302c4ca9c0..4eb360cc7a 100644 --- a/guides/source/contributing_to_ruby_on_rails.md +++ b/guides/source/contributing_to_ruby_on_rails.md @@ -193,7 +193,7 @@ Now get busy and add/edit code. You're on your branch now, so you can write what * Update the (surrounding) documentation, examples elsewhere, and the guides: whatever is affected by your contribution. -TIP: Changes that are cosmetic in nature and do not add anything substantial to the stability, functionality, or testability of Rails will generally not be accepted. +TIP: Changes that are cosmetic in nature and do not add anything substantial to the stability, functionality, or testability of Rails will generally not be accepted (read more about [our rationales behind this decision](https://github.com/rails/rails/pull/13771#issuecomment-32746700)). #### Follow the Coding Conventions diff --git a/railties/test/railties/engine_test.rb b/railties/test/railties/engine_test.rb index 1976466229..6239af2066 100644 --- a/railties/test/railties/engine_test.rb +++ b/railties/test/railties/engine_test.rb @@ -523,7 +523,7 @@ YAML end end - test "engine is a rack app and can have his own middleware stack" do + test "engine is a rack app and can have its own middleware stack" do add_to_config("config.action_dispatch.show_exceptions = false") @plugin.write "lib/bukkits.rb", <<-RUBY |