aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Gemfile2
-rw-r--r--actionmailer/README.rdoc37
-rw-r--r--actionpack/lib/action_controller/metal/live.rb2
-rw-r--r--actionpack/lib/action_dispatch/middleware/debug_exceptions.rb30
-rw-r--r--actionpack/lib/action_dispatch/middleware/exception_wrapper.rb22
-rw-r--r--actionview/lib/action_view/helpers/tag_helper.rb2
-rw-r--r--actionview/lib/action_view/template/handlers/raw.rb2
-rw-r--r--activejob/lib/active_job/callbacks.rb2
-rw-r--r--activejob/lib/active_job/core.rb2
-rw-r--r--activejob/lib/active_job/enqueuing.rb1
-rw-r--r--activejob/lib/active_job/execution.rb1
-rw-r--r--activejob/lib/active_job/logging.rb2
-rw-r--r--activejob/lib/active_job/queue_adapter.rb3
-rw-r--r--activejob/lib/active_job/queue_adapters.rb2
-rw-r--r--activejob/lib/active_job/queue_adapters/delayed_job_adapter.rb4
-rw-r--r--activejob/lib/active_job/queue_name.rb1
-rw-r--r--activejob/lib/active_job/test_helper.rb4
-rw-r--r--activemodel/lib/active_model/validations/format.rb2
-rw-r--r--activemodel/test/cases/validations/validates_test.rb1
-rw-r--r--activerecord/CHANGELOG.md14
-rw-r--r--activerecord/lib/active_record/associations/has_many_through_association.rb2
-rw-r--r--activerecord/lib/active_record/associations/preloader/through_association.rb1
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract_adapter.rb11
-rw-r--r--activerecord/lib/active_record/connection_adapters/mysql_adapter.rb2
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/database_statements.rb2
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb11
-rw-r--r--activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb2
-rw-r--r--activerecord/lib/active_record/fixtures.rb2
-rw-r--r--activerecord/lib/active_record/railties/databases.rake3
-rw-r--r--activerecord/lib/active_record/relation.rb19
-rw-r--r--activerecord/lib/active_record/relation/calculations.rb3
-rw-r--r--activerecord/lib/active_record/relation/finder_methods.rb11
-rw-r--r--activerecord/lib/active_record/relation/predicate_builder/relation_handler.rb2
-rw-r--r--activerecord/lib/active_record/relation/query_methods.rb37
-rw-r--r--activerecord/lib/active_record/sanitization.rb5
-rw-r--r--activerecord/test/cases/adapters/postgresql/json_test.rb8
-rw-r--r--activerecord/test/cases/base_test.rb4
-rw-r--r--activerecord/test/cases/finder_test.rb10
-rw-r--r--activerecord/test/cases/relation/where_test.rb1
-rw-r--r--activerecord/test/cases/sanitize_test.rb4
-rw-r--r--activerecord/test/cases/schema_dumper_test.rb7
-rw-r--r--activerecord/test/cases/serialization_test.rb9
-rw-r--r--activerecord/test/models/author.rb1
-rw-r--r--activerecord/test/models/post.rb4
-rw-r--r--activerecord/test/schema/postgresql_specific_schema.rb15
-rw-r--r--activerecord/test/schema/schema.rb5
-rw-r--r--activesupport/CHANGELOG.md4
-rw-r--r--activesupport/lib/active_support/core_ext/hash/slice.rb10
-rw-r--r--activesupport/lib/active_support/core_ext/string/filters.rb16
-rw-r--r--activesupport/lib/active_support/dependencies/autoload.rb2
-rw-r--r--activesupport/lib/active_support/duration.rb1
-rw-r--r--activesupport/lib/active_support/inflector/methods.rb2
-rw-r--r--activesupport/test/core_ext/duration_test.rb1
-rw-r--r--activesupport/test/core_ext/string_ext_test.rb16
-rw-r--r--guides/source/4_2_release_notes.md22
-rw-r--r--guides/source/_welcome.html.erb2
-rw-r--r--guides/source/action_controller_overview.md12
-rw-r--r--guides/source/active_job_basics.md25
-rw-r--r--guides/source/active_record_validations.md1
-rw-r--r--guides/source/asset_pipeline.md3
-rw-r--r--guides/source/configuring.md2
-rw-r--r--guides/source/form_helpers.md2
-rw-r--r--guides/source/getting_started.md8
-rw-r--r--guides/source/ruby_on_rails_guides_guidelines.md1
-rw-r--r--railties/lib/rails/application.rb13
-rw-r--r--railties/lib/rails/engine.rb9
-rw-r--r--railties/test/application/configuration_test.rb14
-rw-r--r--railties/test/application/rake/dbs_test.rb10
-rw-r--r--railties/test/isolation/abstract_unit.rb9
-rw-r--r--tools/README.md4
70 files changed, 335 insertions, 171 deletions
diff --git a/Gemfile b/Gemfile
index f6fd0f3ac0..931c8e85bc 100644
--- a/Gemfile
+++ b/Gemfile
@@ -14,7 +14,7 @@ gem 'rack-cache', '~> 1.2'
gem 'jquery-rails', '~> 4.0.0.beta2'
gem 'coffee-rails', '~> 4.1.0'
gem 'turbolinks'
-gem 'arel', '~> 6.0.0.beta2'
+gem 'arel', github: 'rails/arel'
# require: false so bcrypt is loaded only when has_secure_password is used.
# This is to avoid ActiveModel (and by extension the entire framework)
diff --git a/actionmailer/README.rdoc b/actionmailer/README.rdoc
index b4eb40f54d..a4e660d621 100644
--- a/actionmailer/README.rdoc
+++ b/actionmailer/README.rdoc
@@ -74,14 +74,17 @@ Or you can just chain the methods together like:
== Setting defaults
-It is possible to set default values that will be used in every method in your Action Mailer class.
-To implement this functionality, you just call the public class method <tt>default</tt> which you get for free from
-<tt>ActionMailer::Base</tt>. This method accepts a Hash as the parameter. You can use any of the headers, email messages
-have, like <tt>:from</tt> as the key. You can also pass in a string as the key, like "Content-Type", but Action Mailer
-does this out of the box for you, so you won't need to worry about that.
-Finally, it is also possible to pass in a Proc that will get evaluated when it is needed.
-
-Note that every value you set with this method will get overwritten if you use the same key in your mailer method.
+It is possible to set default values that will be used in every method in your
+Action Mailer class. To implement this functionality, you just call the public
+class method +default+ which you get for free from <tt>ActionMailer::Base</tt>.
+This method accepts a Hash as the parameter. You can use any of the headers,
+email messages have, like +:from+ as the key. You can also pass in a string as
+the key, like "Content-Type", but Action Mailer does this out of the box for you,
+so you won't need to worry about that. Finally, it is also possible to pass in a
+Proc that will get evaluated when it is needed.
+
+Note that every value you set with this method will get overwritten if you use the
+same key in your mailer method.
Example:
@@ -92,10 +95,11 @@ Example:
== Receiving emails
-To receive emails, you need to implement a public instance method called <tt>receive</tt> that takes an
-email object as its single parameter. The Action Mailer framework has a corresponding class method,
-which is also called <tt>receive</tt>, that accepts a raw, unprocessed email as a string, which it then turns
-into the email object and calls the receive instance method.
+To receive emails, you need to implement a public instance method called
++receive+ that takes an email object as its single parameter. The Action Mailer
+framework has a corresponding class method, which is also called +receive+, that
+accepts a raw, unprocessed email as a string, which it then turns into the email
+object and calls the receive instance method.
Example:
@@ -116,13 +120,14 @@ Example:
end
end
-This Mailman can be the target for Postfix or other MTAs. In Rails, you would use the runner in the
-trivial case like this:
+This Mailman can be the target for Postfix or other MTAs. In Rails, you would use
+the runner in the trivial case like this:
rails runner 'Mailman.receive(STDIN.read)'
-However, invoking Rails in the runner for each mail to be received is very resource intensive. A single
-instance of Rails should be run within a daemon, if it is going to process more than just a limited amount of email.
+However, invoking Rails in the runner for each mail to be received is very
+resource intensive. A single instance of Rails should be run within a daemon, if
+it is going to process more than just a limited amount of email.
== Configuration
diff --git a/actionpack/lib/action_controller/metal/live.rb b/actionpack/lib/action_controller/metal/live.rb
index c9ef3a3dad..1e13b3761f 100644
--- a/actionpack/lib/action_controller/metal/live.rb
+++ b/actionpack/lib/action_controller/metal/live.rb
@@ -102,7 +102,7 @@ module ActionController
end
end
- message = json.gsub("\n", "\ndata: ")
+ message = json.gsub(/\n/, "\ndata: ")
@stream.write "data: #{message}\n\n"
end
end
diff --git a/actionpack/lib/action_dispatch/middleware/debug_exceptions.rb b/actionpack/lib/action_dispatch/middleware/debug_exceptions.rb
index ff72592b94..798c087d64 100644
--- a/actionpack/lib/action_dispatch/middleware/debug_exceptions.rb
+++ b/actionpack/lib/action_dispatch/middleware/debug_exceptions.rb
@@ -35,7 +35,7 @@ module ActionDispatch
if env['action_dispatch.show_detailed_exceptions']
request = Request.new(env)
- traces = traces_from_wrapper(wrapper)
+ traces = wrapper.traces
trace_to_show = 'Application Trace'
if traces[trace_to_show].empty?
@@ -106,33 +106,5 @@ module ActionDispatch
ActionDispatch::Routing::RoutesInspector.new(@routes_app.routes.routes)
end
end
-
- # Augment the exception traces by providing ids for all unique stack frame
- def traces_from_wrapper(wrapper)
- application_trace = wrapper.application_trace
- framework_trace = wrapper.framework_trace
- full_trace = wrapper.full_trace
-
- appplication_trace_with_ids = []
- framework_trace_with_ids = []
- full_trace_with_ids = []
-
- if full_trace
- full_trace.each_with_index do |trace, idx|
- id_trace = {
- id: idx,
- trace: trace
- }
- appplication_trace_with_ids << id_trace if application_trace.include? trace
- framework_trace_with_ids << id_trace if framework_trace.include? trace
- full_trace_with_ids << id_trace
- end
- end
- {
- "Application Trace" => appplication_trace_with_ids,
- "Framework Trace" => framework_trace_with_ids,
- "Full Trace" => full_trace_with_ids
- }
- end
end
end
diff --git a/actionpack/lib/action_dispatch/middleware/exception_wrapper.rb b/actionpack/lib/action_dispatch/middleware/exception_wrapper.rb
index a6285848b5..e0140b0692 100644
--- a/actionpack/lib/action_dispatch/middleware/exception_wrapper.rb
+++ b/actionpack/lib/action_dispatch/middleware/exception_wrapper.rb
@@ -57,6 +57,28 @@ module ActionDispatch
clean_backtrace(:all)
end
+ def traces
+ appplication_trace_with_ids = []
+ framework_trace_with_ids = []
+ full_trace_with_ids = []
+
+ if full_trace
+ full_trace.each_with_index do |trace, idx|
+ trace_with_id = { id: idx, trace: trace }
+
+ appplication_trace_with_ids << trace_with_id if application_trace.include?(trace)
+ framework_trace_with_ids << trace_with_id if framework_trace.include?(trace)
+ full_trace_with_ids << trace_with_id
+ end
+ end
+
+ {
+ "Application Trace" => appplication_trace_with_ids,
+ "Framework Trace" => framework_trace_with_ids,
+ "Full Trace" => full_trace_with_ids
+ }
+ end
+
def self.status_code_for_exception(class_name)
Rack::Utils.status_code(@@rescue_responses[class_name])
end
diff --git a/actionview/lib/action_view/helpers/tag_helper.rb b/actionview/lib/action_view/helpers/tag_helper.rb
index 385d57a7a5..b2038576a2 100644
--- a/actionview/lib/action_view/helpers/tag_helper.rb
+++ b/actionview/lib/action_view/helpers/tag_helper.rb
@@ -123,7 +123,7 @@ module ActionView
# cdata_section("hello]]>world")
# # => <![CDATA[hello]]]]><![CDATA[>world]]>
def cdata_section(content)
- splitted = content.to_s.gsub(']]>', ']]]]><![CDATA[>')
+ splitted = content.to_s.gsub(/\]\]\>/, ']]]]><![CDATA[>')
"<![CDATA[#{splitted}]]>".html_safe
end
diff --git a/actionview/lib/action_view/template/handlers/raw.rb b/actionview/lib/action_view/template/handlers/raw.rb
index 0c0d1fffcb..397c86014a 100644
--- a/actionview/lib/action_view/template/handlers/raw.rb
+++ b/actionview/lib/action_view/template/handlers/raw.rb
@@ -2,7 +2,7 @@ module ActionView
module Template::Handlers
class Raw
def call(template)
- escaped = template.source.gsub(':', '\:')
+ escaped = template.source.gsub(/:/, '\:')
'%q:' + escaped + ':;'
end
diff --git a/activejob/lib/active_job/callbacks.rb b/activejob/lib/active_job/callbacks.rb
index 29e2a878b4..c4ceb484cc 100644
--- a/activejob/lib/active_job/callbacks.rb
+++ b/activejob/lib/active_job/callbacks.rb
@@ -22,6 +22,8 @@ module ActiveJob
define_callbacks :enqueue
end
+ # These methods will be included into any Active Job object, adding
+ # callbacks for +perform+ and +enqueue+ methods.
module ClassMethods
# Defines a callback that will get called right before the
# job's perform method is executed.
diff --git a/activejob/lib/active_job/core.rb b/activejob/lib/active_job/core.rb
index 68d46e6466..a0e55a0028 100644
--- a/activejob/lib/active_job/core.rb
+++ b/activejob/lib/active_job/core.rb
@@ -17,6 +17,8 @@ module ActiveJob
attr_writer :queue_name
end
+ # These methods will be included into any Active Job object, adding
+ # helpers for de/serialization and creation of job instances.
module ClassMethods
# Creates a new job instance from a hash created with +serialize+
def deserialize(job_data)
diff --git a/activejob/lib/active_job/enqueuing.rb b/activejob/lib/active_job/enqueuing.rb
index 53d944021a..430c17e1bf 100644
--- a/activejob/lib/active_job/enqueuing.rb
+++ b/activejob/lib/active_job/enqueuing.rb
@@ -4,6 +4,7 @@ module ActiveJob
module Enqueuing
extend ActiveSupport::Concern
+ # Includes the +perform_later+ method for job initialization.
module ClassMethods
# Push a job onto the queue. The arguments must be legal JSON types
# (string, int, float, nil, true, false, hash or array) or
diff --git a/activejob/lib/active_job/execution.rb b/activejob/lib/active_job/execution.rb
index 7ff857206d..79d232da4a 100644
--- a/activejob/lib/active_job/execution.rb
+++ b/activejob/lib/active_job/execution.rb
@@ -6,6 +6,7 @@ module ActiveJob
extend ActiveSupport::Concern
include ActiveSupport::Rescuable
+ # Includes methods for executing and performing jobs instantly.
module ClassMethods
# Performs the job immediately.
#
diff --git a/activejob/lib/active_job/logging.rb b/activejob/lib/active_job/logging.rb
index 6e703faaa7..21d2fda3ff 100644
--- a/activejob/lib/active_job/logging.rb
+++ b/activejob/lib/active_job/logging.rb
@@ -75,7 +75,7 @@ module ActiveJob
def perform(event)
info do
job = event.payload[:job]
- "Performed #{job.class.name} from #{queue_name(event)} in #{event.duration.round(2).to_s}ms"
+ "Performed #{job.class.name} from #{queue_name(event)} in #{event.duration.round(2)}ms"
end
end
diff --git a/activejob/lib/active_job/queue_adapter.rb b/activejob/lib/active_job/queue_adapter.rb
index 4bd28522ab..85d7c44bb8 100644
--- a/activejob/lib/active_job/queue_adapter.rb
+++ b/activejob/lib/active_job/queue_adapter.rb
@@ -2,9 +2,12 @@ require 'active_job/queue_adapters/inline_adapter'
require 'active_support/core_ext/string/inflections'
module ActiveJob
+ # The <tt>ActionJob::QueueAdapter</tt> module is used to load the
+ # correct adapter. The default queue adapter is the :inline queue.
module QueueAdapter #:nodoc:
extend ActiveSupport::Concern
+ # Includes the setter method for changing the active queue adapter.
module ClassMethods
mattr_reader(:queue_adapter) { ActiveJob::QueueAdapters::InlineAdapter }
diff --git a/activejob/lib/active_job/queue_adapters.rb b/activejob/lib/active_job/queue_adapters.rb
index efbcd3cb3a..f22b0502dc 100644
--- a/activejob/lib/active_job/queue_adapters.rb
+++ b/activejob/lib/active_job/queue_adapters.rb
@@ -13,7 +13,7 @@ module ActiveJob
# * {Sneakers}[https://github.com/jondot/sneakers]
# * {Sucker Punch}[https://github.com/brandonhilkert/sucker_punch]
#
- # #### Backends Features
+ # === Backends Features
#
# | | Async | Queues | Delayed | Priorities | Timeout | Retries |
# |-------------------|-------|--------|-----------|------------|---------|---------|
diff --git a/activejob/lib/active_job/queue_adapters/delayed_job_adapter.rb b/activejob/lib/active_job/queue_adapters/delayed_job_adapter.rb
index 4d27c4fff8..69d9e70de3 100644
--- a/activejob/lib/active_job/queue_adapters/delayed_job_adapter.rb
+++ b/activejob/lib/active_job/queue_adapters/delayed_job_adapter.rb
@@ -6,10 +6,10 @@ module ActiveJob
#
# Delayed::Job (or DJ) encapsulates the common pattern of asynchronously
# executing longer tasks in the background. Although DJ can have many
- # storage backends one of the most used is based on Active Record.
+ # storage backends, one of the most used is based on Active Record.
# Read more about Delayed Job {here}[https://github.com/collectiveidea/delayed_job].
#
- # To use Delayed Job set the queue_adapter config to +:delayed_job+.
+ # To use Delayed Job, set the queue_adapter config to +:delayed_job+.
#
# Rails.application.config.active_job.queue_adapter = :delayed_job
class DelayedJobAdapter
diff --git a/activejob/lib/active_job/queue_name.rb b/activejob/lib/active_job/queue_name.rb
index 6ee7142ce6..9ae0345120 100644
--- a/activejob/lib/active_job/queue_name.rb
+++ b/activejob/lib/active_job/queue_name.rb
@@ -2,6 +2,7 @@ module ActiveJob
module QueueName
extend ActiveSupport::Concern
+ # Includes the ability to override the default queue name and prefix.
module ClassMethods
mattr_accessor(:queue_name_prefix)
mattr_accessor(:default_queue_name) { "default" }
diff --git a/activejob/lib/active_job/test_helper.rb b/activejob/lib/active_job/test_helper.rb
index ade7a94c9d..bb20d93947 100644
--- a/activejob/lib/active_job/test_helper.rb
+++ b/activejob/lib/active_job/test_helper.rb
@@ -53,7 +53,7 @@ module ActiveJob
end
end
- # Assert that no job have been enqueued.
+ # Asserts that no jobs have been enqueued.
#
# def test_jobs
# assert_no_enqueued_jobs
@@ -137,7 +137,7 @@ module ActiveJob
# Asserts that the job passed in the block has been enqueued with the given arguments.
#
- # def assert_enqueued_job
+ # def test_assert_enqueued_with
# assert_enqueued_with(job: MyJob, args: [1,2,3], queue: 'low') do
# MyJob.perform_later(1,2,3)
# end
diff --git a/activemodel/lib/active_model/validations/format.rb b/activemodel/lib/active_model/validations/format.rb
index ff3e95da34..02478dd5b6 100644
--- a/activemodel/lib/active_model/validations/format.rb
+++ b/activemodel/lib/active_model/validations/format.rb
@@ -54,7 +54,7 @@ module ActiveModel
module HelperMethods
# Validates whether the value of the specified attribute is of the correct
- # form, going by the regular expression provided.You can require that the
+ # form, going by the regular expression provided. You can require that the
# attribute matches the regular expression:
#
# class Person < ActiveRecord::Base
diff --git a/activemodel/test/cases/validations/validates_test.rb b/activemodel/test/cases/validations/validates_test.rb
index 699a872e42..8d4b74ee49 100644
--- a/activemodel/test/cases/validations/validates_test.rb
+++ b/activemodel/test/cases/validations/validates_test.rb
@@ -3,7 +3,6 @@ require 'cases/helper'
require 'models/person'
require 'models/topic'
require 'models/person_with_validator'
-require 'validators/email_validator'
require 'validators/namespace/email_validator'
class ValidatesTest < ActiveModel::TestCase
diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md
index ad4ee0f489..1961ba93c6 100644
--- a/activerecord/CHANGELOG.md
+++ b/activerecord/CHANGELOG.md
@@ -1,3 +1,17 @@
+* Added SchemaDumper support for tables with jsonb columns.
+
+ *Ted O'Meara*
+
+* Deprecate `sanitize_sql_hash_for_conditions` without replacement. Using a
+ `Relation` for performing queries and updates is the prefered API.
+
+ *Sean Griffin*
+
+* Queries now properly type cast values that are part of a join statement,
+ even when using type decorators such as `serialize`.
+
+ *Melanie Gilman & Sean Griffin*
+
* MySQL enum type lookups, with values matching another type, no longer result
in an endless loop.
diff --git a/activerecord/lib/active_record/associations/has_many_through_association.rb b/activerecord/lib/active_record/associations/has_many_through_association.rb
index 04a69ba446..bde23fc116 100644
--- a/activerecord/lib/active_record/associations/has_many_through_association.rb
+++ b/activerecord/lib/active_record/associations/has_many_through_association.rb
@@ -161,7 +161,7 @@ module ActiveRecord
if scope.klass.primary_key
count = scope.destroy_all.length
else
- scope.to_a.each do |record|
+ scope.each do |record|
record._run_destroy_callbacks
end
diff --git a/activerecord/lib/active_record/associations/preloader/through_association.rb b/activerecord/lib/active_record/associations/preloader/through_association.rb
index d57da366bd..12bf3ef138 100644
--- a/activerecord/lib/active_record/associations/preloader/through_association.rb
+++ b/activerecord/lib/active_record/associations/preloader/through_association.rb
@@ -81,6 +81,7 @@ module ActiveRecord
unless reflection_scope.where_values.empty?
scope.includes_values = Array(reflection_scope.values[:includes] || options[:source])
scope.where_values = reflection_scope.values[:where]
+ scope.bind_values = reflection_scope.bind_values
end
scope.references! reflection_scope.values[:references]
diff --git a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb
index a0d9086875..582dd360f0 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb
@@ -14,10 +14,7 @@ module ActiveRecord
module ConnectionAdapters # :nodoc:
extend ActiveSupport::Autoload
- autoload_at 'active_record/connection_adapters/column' do
- autoload :Column
- autoload :NullColumn
- end
+ autoload :Column
autoload :ConnectionSpecification
autoload_at 'active_record/connection_adapters/abstract/schema_definitions' do
@@ -267,7 +264,7 @@ module ActiveRecord
# Returns a bind substitution value given a bind +index+ and +column+
# NOTE: The column param is currently being used by the sqlserver-adapter
- def substitute_at(column, index)
+ def substitute_at(column, index = 0)
Arel::Nodes::BindParam.new '?'
end
@@ -386,6 +383,10 @@ module ActiveRecord
type_map.lookup(sql_type)
end
+ def column_name_for_operation(operation, node) # :nodoc:
+ node.to_sql
+ end
+
protected
def initialize_type_map(m) # :nodoc:
diff --git a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb
index cff6798eb3..3357ed52e5 100644
--- a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb
@@ -88,7 +88,7 @@ module ActiveRecord
end
def clear
- cache.values.each do |hash|
+ cache.each_value do |hash|
hash[:stmt].close
end
cache.clear
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/database_statements.rb b/activerecord/lib/active_record/connection_adapters/postgresql/database_statements.rb
index 89a7257d77..cf379ab210 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql/database_statements.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql/database_statements.rb
@@ -156,7 +156,7 @@ module ActiveRecord
end
end
- def substitute_at(column, index)
+ def substitute_at(column, index = 0)
Arel::Nodes::BindParam.new "$#{index + 1}"
end
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
index 8e209e1051..9941f74766 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
@@ -104,6 +104,7 @@ module ActiveRecord
macaddr: { name: "macaddr" },
uuid: { name: "uuid" },
json: { name: "json" },
+ jsonb: { name: "jsonb" },
ltree: { name: "ltree" },
citext: { name: "citext" },
point: { name: "point" },
@@ -393,6 +394,16 @@ module ActiveRecord
super(oid)
end
+ def column_name_for_operation(operation, node) # :nodoc:
+ OPERATION_ALIASES.fetch(operation) { operation.downcase }
+ end
+
+ OPERATION_ALIASES = { # :nodoc:
+ "maximum" => "max",
+ "minimum" => "min",
+ "average" => "avg",
+ }
+
protected
# Returns the version of the connected PostgreSQL server.
diff --git a/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb b/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb
index 4756896ac5..1b5e3bdbac 100644
--- a/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb
@@ -115,7 +115,7 @@ module ActiveRecord
end
def clear
- cache.values.each do |hash|
+ cache.each_value do |hash|
dealloc hash[:stmt]
end
cache.clear
diff --git a/activerecord/lib/active_record/fixtures.rb b/activerecord/lib/active_record/fixtures.rb
index 125a119b5f..db6421dacb 100644
--- a/activerecord/lib/active_record/fixtures.rb
+++ b/activerecord/lib/active_record/fixtures.rb
@@ -649,7 +649,7 @@ module ActiveRecord
model_class
end
- reflection_class._reflections.values.each do |association|
+ reflection_class._reflections.each_value do |association|
case association.macro
when :belongs_to
# Do not replace association name with association foreign key if they are named the same
diff --git a/activerecord/lib/active_record/railties/databases.rake b/activerecord/lib/active_record/railties/databases.rake
index 44765bd050..3ec25f9f17 100644
--- a/activerecord/lib/active_record/railties/databases.rake
+++ b/activerecord/lib/active_record/railties/databases.rake
@@ -196,7 +196,8 @@ db_namespace = namespace :db do
fixture_files = if ENV['FIXTURES']
ENV['FIXTURES'].split(',')
else
- Pathname.glob("#{fixtures_dir}/**/*.yml").map {|f| f.basename.sub_ext('').to_s }
+ # The use of String#[] here is to support namespaced fixtures
+ Dir["#{fixtures_dir}/**/*.yml"].map {|f| f[(fixtures_dir.size + 1)..-5] }
end
ActiveRecord::FixtureSet.create_fixtures(fixtures_dir, fixture_files)
diff --git a/activerecord/lib/active_record/relation.rb b/activerecord/lib/active_record/relation.rb
index 7f51e4134d..03bce4f5b7 100644
--- a/activerecord/lib/active_record/relation.rb
+++ b/activerecord/lib/active_record/relation.rb
@@ -79,22 +79,27 @@ module ActiveRecord
scope.unscope!(where: @klass.inheritance_column)
end
- um = scope.where(@klass.arel_table[@klass.primary_key].eq(id_was || id)).arel.compile_update(substitutes, @klass.primary_key)
+ relation = scope.where(@klass.primary_key => (id_was || id))
+ bvs = binds + relation.bind_values
+ um = relation
+ .arel
+ .compile_update(substitutes, @klass.primary_key)
+ reorder_bind_params(um.ast, bvs)
@klass.connection.update(
um,
'SQL',
- binds)
+ bvs,
+ )
end
def substitute_values(values) # :nodoc:
- substitutes = values.sort_by { |arel_attr,_| arel_attr.name }
- binds = substitutes.map do |arel_attr, value|
+ binds = values.map do |arel_attr, value|
[@klass.columns_hash[arel_attr.name], value]
end
- substitutes.each_with_index do |tuple, i|
- tuple[1] = @klass.connection.substitute_at(binds[i][0], i)
+ substitutes = values.each_with_index.map do |(arel_attr, _), i|
+ [arel_attr, @klass.connection.substitute_at(binds[i][0], i)]
end
[substitutes, binds]
@@ -337,7 +342,7 @@ module ActiveRecord
stmt.wheres = arel.constraints
end
- bvs = bind_values + arel.bind_values
+ bvs = arel.bind_values + bind_values
@klass.connection.update stmt, 'SQL', bvs
end
diff --git a/activerecord/lib/active_record/relation/calculations.rb b/activerecord/lib/active_record/relation/calculations.rb
index e20cc0e76d..c8ebb41131 100644
--- a/activerecord/lib/active_record/relation/calculations.rb
+++ b/activerecord/lib/active_record/relation/calculations.rb
@@ -253,7 +253,8 @@ module ActiveRecord
select_value = operation_over_aggregate_column(column, operation, distinct)
- column_alias = select_value.alias || select_value.to_sql
+ column_alias = select_value.alias
+ column_alias ||= @klass.connection.column_name_for_operation(operation, select_value)
relation.select_values = [select_value]
query_builder = relation.arel
diff --git a/activerecord/lib/active_record/relation/finder_methods.rb b/activerecord/lib/active_record/relation/finder_methods.rb
index 145b7378cf..eacae73ebb 100644
--- a/activerecord/lib/active_record/relation/finder_methods.rb
+++ b/activerecord/lib/active_record/relation/finder_methods.rb
@@ -82,12 +82,16 @@ module ActiveRecord
# Post.find_by "published_at < ?", 2.weeks.ago
def find_by(*args)
where(*args).take
+ rescue RangeError
+ nil
end
# Like <tt>find_by</tt>, except that if no record is found, raises
# an <tt>ActiveRecord::RecordNotFound</tt> error.
def find_by!(*args)
where(*args).take!
+ rescue RangeError
+ raise RecordNotFound, "Couldn't find #{@klass.name} with an out of range value"
end
# Gives a record (or N records if a parameter is supplied) without any implied
@@ -446,10 +450,7 @@ module ActiveRecord
MSG
end
- column = columns_hash[primary_key]
- substitute = connection.substitute_at(column, bind_values.length)
- relation = where(table[primary_key].eq(substitute))
- relation.bind_values += [[column, id]]
+ relation = where(primary_key => id)
record = relation.take
raise_record_not_found_exception!(id, 0, 1) unless record
@@ -458,7 +459,7 @@ module ActiveRecord
end
def find_some(ids)
- result = where(table[primary_key].in(ids)).to_a
+ result = where(primary_key => ids).to_a
expected_size =
if limit_value && ids.size > limit_value
diff --git a/activerecord/lib/active_record/relation/predicate_builder/relation_handler.rb b/activerecord/lib/active_record/relation/predicate_builder/relation_handler.rb
index 618fa3cdd9..063150958a 100644
--- a/activerecord/lib/active_record/relation/predicate_builder/relation_handler.rb
+++ b/activerecord/lib/active_record/relation/predicate_builder/relation_handler.rb
@@ -6,7 +6,7 @@ module ActiveRecord
value = value.select(value.klass.arel_table[value.klass.primary_key])
end
- attribute.in(value.arel.ast)
+ attribute.in(value.arel)
end
end
end
diff --git a/activerecord/lib/active_record/relation/query_methods.rb b/activerecord/lib/active_record/relation/query_methods.rb
index 2c3cfb7631..a686e3263b 100644
--- a/activerecord/lib/active_record/relation/query_methods.rb
+++ b/activerecord/lib/active_record/relation/query_methods.rb
@@ -439,7 +439,7 @@ module ActiveRecord
self
end
- def bind(value)
+ def bind(value) # :nodoc:
spawn.bind!(value)
end
@@ -883,12 +883,15 @@ module ActiveRecord
# Reorder bind indexes if joins produced bind values
bvs = arel.bind_values + bind_values
- arel.ast.grep(Arel::Nodes::BindParam).each_with_index do |bp, i|
+ reorder_bind_params(arel.ast, bvs)
+ arel
+ end
+
+ def reorder_bind_params(ast, bvs)
+ ast.grep(Arel::Nodes::BindParam).each_with_index do |bp, i|
column = bvs[i].first
bp.replace connection.substitute_at(column, i)
end
-
- arel
end
def symbol_unscoping(scope)
@@ -958,8 +961,7 @@ module ActiveRecord
when Hash
opts = PredicateBuilder.resolve_column_aliases(klass, opts)
- bv_len = bind_values.length
- tmp_opts, bind_values = create_binds(opts, bv_len)
+ tmp_opts, bind_values = create_binds(opts)
self.bind_values += bind_values
attributes = @klass.send(:expand_hash_conditions_for_aggregates, tmp_opts)
@@ -971,7 +973,7 @@ module ActiveRecord
end
end
- def create_binds(opts, idx)
+ def create_binds(opts)
bindable, non_binds = opts.partition do |column, value|
case value
when String, Integer, ActiveRecord::StatementCache::Substitute
@@ -981,12 +983,23 @@ module ActiveRecord
end
end
+ association_binds, non_binds = non_binds.partition do |column, value|
+ value.is_a?(Hash) && association_for_table(column)
+ end
+
new_opts = {}
binds = []
- bindable.each_with_index do |(column,value), index|
+ bindable.each do |(column,value)|
binds.push [@klass.columns_hash[column.to_s], value]
- new_opts[column] = connection.substitute_at(column, index + idx)
+ new_opts[column] = connection.substitute_at(column)
+ end
+
+ association_binds.each do |(column, value)|
+ association_relation = association_for_table(column).klass.send(:relation)
+ association_new_opts, association_bind = association_relation.send(:create_binds, value)
+ new_opts[column] = association_new_opts
+ binds += association_bind
end
non_binds.each { |column,value| new_opts[column] = value }
@@ -994,6 +1007,12 @@ module ActiveRecord
[new_opts, binds]
end
+ def association_for_table(table_name)
+ table_name = table_name.to_s
+ @klass._reflect_on_association(table_name) ||
+ @klass._reflect_on_association(table_name.singularize)
+ end
+
def build_from
opts, name = from_value
case opts
diff --git a/activerecord/lib/active_record/sanitization.rb b/activerecord/lib/active_record/sanitization.rb
index ff70cbed0f..6a130c145b 100644
--- a/activerecord/lib/active_record/sanitization.rb
+++ b/activerecord/lib/active_record/sanitization.rb
@@ -87,6 +87,9 @@ module ActiveRecord
# { address: Address.new("123 abc st.", "chicago") }
# # => "address_street='123 abc st.' and address_city='chicago'"
def sanitize_sql_hash_for_conditions(attrs, default_table_name = self.table_name)
+ ActiveSupport::Deprecation.warn(<<-EOWARN)
+sanitize_sql_hash_for_conditions is deprecated, and will be removed in Rails 5.0
+ EOWARN
attrs = PredicateBuilder.resolve_column_aliases self, attrs
attrs = expand_hash_conditions_for_aggregates(attrs)
@@ -134,7 +137,7 @@ module ActiveRecord
raise_if_bind_arity_mismatch(statement, statement.count('?'), values.size)
bound = values.dup
c = connection
- statement.gsub('?') do
+ statement.gsub(/\?/) do
replace_bind_variable(bound.shift, c)
end
end
diff --git a/activerecord/test/cases/adapters/postgresql/json_test.rb b/activerecord/test/cases/adapters/postgresql/json_test.rb
index 86ba849445..7a9fdd45e8 100644
--- a/activerecord/test/cases/adapters/postgresql/json_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/json_test.rb
@@ -3,8 +3,11 @@
require "cases/helper"
require 'active_record/base'
require 'active_record/connection_adapters/postgresql_adapter'
+require 'support/schema_dumping_helper'
module PostgresqlJSONSharedTestCases
+ include SchemaDumpingHelper
+
class JsonDataType < ActiveRecord::Base
self.table_name = 'json_data_type'
@@ -64,6 +67,11 @@ module PostgresqlJSONSharedTestCases
JsonDataType.reset_column_information
end
+ def test_schema_dumping
+ output = dump_table_schema("json_data_type")
+ assert_match(/t.#{column_type.to_s}\s+"payload",\s+default: {}/, output)
+ end
+
def test_cast_value_on_write
x = JsonDataType.new payload: {"string" => "foo", :symbol => :bar}
assert_equal({"string" => "foo", :symbol => :bar}, x.payload_before_type_cast)
diff --git a/activerecord/test/cases/base_test.rb b/activerecord/test/cases/base_test.rb
index 4e1685f151..3675401555 100644
--- a/activerecord/test/cases/base_test.rb
+++ b/activerecord/test/cases/base_test.rb
@@ -522,6 +522,10 @@ class BasicsTest < ActiveRecord::TestCase
assert_equal Topic.find(['1-meowmeow', '2-hello']), Topic.find([1, 2])
end
+ def test_find_by_slug_with_range
+ assert_equal Topic.where(id: '1-meowmeow'..'2-hello'), Topic.where(id: 1..2)
+ end
+
def test_equality_of_new_records
assert_not_equal Topic.new, Topic.new
assert_equal false, Topic.new == Topic.new
diff --git a/activerecord/test/cases/finder_test.rb b/activerecord/test/cases/finder_test.rb
index d1ff8516e8..dc73faa5be 100644
--- a/activerecord/test/cases/finder_test.rb
+++ b/activerecord/test/cases/finder_test.rb
@@ -210,6 +210,16 @@ class FinderTest < ActiveRecord::TestCase
assert_nil Topic.find_by_id('9999999999999999999999999999999')
end
+ def test_find_on_relation_with_large_number
+ assert_nil Topic.where('1=1').find_by(id: 9999999999999999999999999999999)
+ end
+
+ def test_find_by_bang_on_relation_with_large_number
+ assert_raises(ActiveRecord::RecordNotFound) do
+ Topic.where('1=1').find_by!(id: 9999999999999999999999999999999)
+ end
+ end
+
def test_find_an_empty_array
assert_equal [], Topic.find([])
end
diff --git a/activerecord/test/cases/relation/where_test.rb b/activerecord/test/cases/relation/where_test.rb
index 39c8afdd23..a453203e15 100644
--- a/activerecord/test/cases/relation/where_test.rb
+++ b/activerecord/test/cases/relation/where_test.rb
@@ -7,6 +7,7 @@ require 'models/comment'
require 'models/edge'
require 'models/topic'
require 'models/binary'
+require 'models/vertex'
module ActiveRecord
class WhereTest < ActiveRecord::TestCase
diff --git a/activerecord/test/cases/sanitize_test.rb b/activerecord/test/cases/sanitize_test.rb
index dca85fb5eb..f477cf7d92 100644
--- a/activerecord/test/cases/sanitize_test.rb
+++ b/activerecord/test/cases/sanitize_test.rb
@@ -13,7 +13,9 @@ class SanitizeTest < ActiveRecord::TestCase
quoted_table_name = ActiveRecord::Base.connection.quote_table_name("adorable_animals")
expected_value = "#{quoted_table_name}.#{quoted_column_name} = #{quoted_bambi}"
- assert_equal expected_value, Binary.send(:sanitize_sql_hash, {adorable_animals: {name: 'Bambi'}})
+ assert_deprecated do
+ assert_equal expected_value, Binary.send(:sanitize_sql_hash, {adorable_animals: {name: 'Bambi'}})
+ end
end
def test_sanitize_sql_array_handles_string_interpolation
diff --git a/activerecord/test/cases/schema_dumper_test.rb b/activerecord/test/cases/schema_dumper_test.rb
index 2241c41f36..6303393c22 100644
--- a/activerecord/test/cases/schema_dumper_test.rb
+++ b/activerecord/test/cases/schema_dumper_test.rb
@@ -271,13 +271,6 @@ class SchemaDumperTest < ActiveRecord::TestCase
end
end
- def test_schema_dump_includes_json_shorthand_definition
- output = standard_dump
- if %r{create_table "postgresql_json_data_type"} =~ output
- assert_match %r|t.json "json_data", default: {}|, output
- end
- end
-
def test_schema_dump_includes_inet_shorthand_definition
output = standard_dump
if %r{create_table "postgresql_network_addresses"} =~ output
diff --git a/activerecord/test/cases/serialization_test.rb b/activerecord/test/cases/serialization_test.rb
index 3f52e80e11..35b13ea247 100644
--- a/activerecord/test/cases/serialization_test.rb
+++ b/activerecord/test/cases/serialization_test.rb
@@ -2,6 +2,8 @@ require "cases/helper"
require 'models/contact'
require 'models/topic'
require 'models/book'
+require 'models/author'
+require 'models/post'
class SerializationTest < ActiveRecord::TestCase
fixtures :books
@@ -92,4 +94,11 @@ class SerializationTest < ActiveRecord::TestCase
book = klazz.find(books(:awdr).id)
assert_equal 'paperback', book.read_attribute_for_serialization(:format)
end
+
+ def test_find_records_by_serialized_attributes_through_join
+ author = Author.create!(name: "David")
+ author.serialized_posts.create!(title: "Hello")
+
+ assert_equal 1, Author.joins(:serialized_posts).where(name: "David", serialized_posts: { title: "Hello" }).length
+ end
end
diff --git a/activerecord/test/models/author.rb b/activerecord/test/models/author.rb
index 3f34d09a04..3da3a1fd59 100644
--- a/activerecord/test/models/author.rb
+++ b/activerecord/test/models/author.rb
@@ -1,5 +1,6 @@
class Author < ActiveRecord::Base
has_many :posts
+ has_many :serialized_posts
has_one :post
has_many :very_special_comments, :through => :posts
has_many :posts_with_comments, -> { includes(:comments) }, :class_name => "Post"
diff --git a/activerecord/test/models/post.rb b/activerecord/test/models/post.rb
index 67027cbc22..36cf221d45 100644
--- a/activerecord/test/models/post.rb
+++ b/activerecord/test/models/post.rb
@@ -233,3 +233,7 @@ class PostWithCommentWithDefaultScopeReferencesAssociation < ActiveRecord::Base
has_many :comment_with_default_scope_references_associations, foreign_key: :post_id
has_one :first_comment, class_name: "CommentWithDefaultScopeReferencesAssociation", foreign_key: :post_id
end
+
+class SerializedPost < ActiveRecord::Base
+ serialize :title
+end
diff --git a/activerecord/test/schema/postgresql_specific_schema.rb b/activerecord/test/schema/postgresql_specific_schema.rb
index e9294a11b9..7c3b170c08 100644
--- a/activerecord/test/schema/postgresql_specific_schema.rb
+++ b/activerecord/test/schema/postgresql_specific_schema.rb
@@ -1,7 +1,9 @@
ActiveRecord::Schema.define do
- %w(postgresql_tsvectors postgresql_hstores postgresql_arrays postgresql_moneys postgresql_numbers postgresql_times postgresql_network_addresses postgresql_uuids postgresql_ltrees
- postgresql_oids postgresql_xml_data_type defaults geometrics postgresql_timestamp_with_zones postgresql_partitioned_table postgresql_partitioned_table_parent postgresql_json_data_type postgresql_citext).each do |table_name|
+ %w(postgresql_tsvectors postgresql_hstores postgresql_arrays postgresql_moneys postgresql_numbers postgresql_times
+ postgresql_network_addresses postgresql_uuids postgresql_ltrees postgresql_oids postgresql_xml_data_type defaults
+ geometrics postgresql_timestamp_with_zones postgresql_partitioned_table postgresql_partitioned_table_parent
+ postgresql_citext).each do |table_name|
execute "DROP TABLE IF EXISTS #{quote_table_name table_name}"
end
@@ -108,15 +110,6 @@ _SQL
_SQL
end
- if 't' == select_value("select 'json'=ANY(select typname from pg_type)")
- execute <<_SQL
- CREATE TABLE postgresql_json_data_type (
- id SERIAL PRIMARY KEY,
- json_data json default '{}'::json
- );
-_SQL
- end
-
execute <<_SQL
CREATE TABLE postgresql_numbers (
id SERIAL PRIMARY KEY,
diff --git a/activerecord/test/schema/schema.rb b/activerecord/test/schema/schema.rb
index 2b68236256..539a0d2a49 100644
--- a/activerecord/test/schema/schema.rb
+++ b/activerecord/test/schema/schema.rb
@@ -585,6 +585,11 @@ ActiveRecord::Schema.define do
t.integer :tags_with_nullify_count, default: 0
end
+ create_table :serialized_posts, force: true do |t|
+ t.integer :author_id
+ t.string :title, null: false
+ end
+
create_table :price_estimates, force: true do |t|
t.string :estimate_of_type
t.integer :estimate_of_id
diff --git a/activesupport/CHANGELOG.md b/activesupport/CHANGELOG.md
index 4ad602b066..b2b3cf4bd4 100644
--- a/activesupport/CHANGELOG.md
+++ b/activesupport/CHANGELOG.md
@@ -1,3 +1,7 @@
+* `String#remove` and `String#remove!` accept multiple arguments.
+
+ *Pavel Pravosud*
+
* TimeWithZone#strftime now delegates every directive to Time#strftime except for '%Z',
it also now correctly handles escaped '%' characters placed just before time zone related directives.
diff --git a/activesupport/lib/active_support/core_ext/hash/slice.rb b/activesupport/lib/active_support/core_ext/hash/slice.rb
index 8ad600b171..41b2279013 100644
--- a/activesupport/lib/active_support/core_ext/hash/slice.rb
+++ b/activesupport/lib/active_support/core_ext/hash/slice.rb
@@ -1,6 +1,12 @@
class Hash
- # Slice a hash to include only the given keys. This is useful for
- # limiting an options hash to valid keys before passing to a method:
+ # Slice a hash to include only the given keys. Returns a hash containing
+ # the given keys.
+ #
+ # { a: 1, b: 2, c: 3, d: 4 }.slice(:a, :b)
+ # # => {:a=>1, :b=>2}
+ #
+ # This is useful for limiting an options hash to valid keys before
+ # passing to a method:
#
# def search(criteria = {})
# criteria.assert_valid_keys(:mass, :velocity, :time)
diff --git a/activesupport/lib/active_support/core_ext/string/filters.rb b/activesupport/lib/active_support/core_ext/string/filters.rb
index 2b1583d4ac..499b9b26bc 100644
--- a/activesupport/lib/active_support/core_ext/string/filters.rb
+++ b/activesupport/lib/active_support/core_ext/string/filters.rb
@@ -20,14 +20,18 @@ class String
self
end
- # Returns a new string with all occurrences of the pattern removed. Short-hand for String#gsub(pattern, '').
- def remove(pattern)
- gsub pattern, ''
+ # Returns a new string with all occurrences of the patterns removed.
+ def remove(*patterns)
+ dup.remove!(*patterns)
end
- # Alters the string by removing all occurrences of the pattern. Short-hand for String#gsub!(pattern, '').
- def remove!(pattern)
- gsub! pattern, ''
+ # Alters the string by removing all occurrences of the patterns.
+ def remove!(*patterns)
+ patterns.each do |pattern|
+ gsub! pattern, ""
+ end
+
+ self
end
# Truncates a given +text+ after a given <tt>length</tt> if +text+ is longer than <tt>length</tt>:
diff --git a/activesupport/lib/active_support/dependencies/autoload.rb b/activesupport/lib/active_support/dependencies/autoload.rb
index c0dba5f7fd..13036d521d 100644
--- a/activesupport/lib/active_support/dependencies/autoload.rb
+++ b/activesupport/lib/active_support/dependencies/autoload.rb
@@ -67,7 +67,7 @@ module ActiveSupport
end
def eager_load!
- @_autoloads.values.each { |file| require file }
+ @_autoloads.each_value { |file| require file }
end
def autoloads
diff --git a/activesupport/lib/active_support/duration.rb b/activesupport/lib/active_support/duration.rb
index 584fc1e1c5..baa83223d2 100644
--- a/activesupport/lib/active_support/duration.rb
+++ b/activesupport/lib/active_support/duration.rb
@@ -1,4 +1,3 @@
-require 'active_support/proxy_object'
require 'active_support/core_ext/array/conversions'
require 'active_support/core_ext/object/acts_like'
diff --git a/activesupport/lib/active_support/inflector/methods.rb b/activesupport/lib/active_support/inflector/methods.rb
index 637736c5df..74b3a7c2a9 100644
--- a/activesupport/lib/active_support/inflector/methods.rb
+++ b/activesupport/lib/active_support/inflector/methods.rb
@@ -73,7 +73,7 @@ module ActiveSupport
string = string.sub(/^(?:#{inflections.acronym_regex}(?=\b|[A-Z_])|\w)/) { $&.downcase }
end
string.gsub!(/(?:_|(\/))([a-z\d]*)/i) { "#{$1}#{inflections.acronyms[$2] || $2.capitalize}" }
- string.gsub!('/', '::')
+ string.gsub!(/\//, '::')
string
end
diff --git a/activesupport/test/core_ext/duration_test.rb b/activesupport/test/core_ext/duration_test.rb
index 5a2af7f943..a5d254e115 100644
--- a/activesupport/test/core_ext/duration_test.rb
+++ b/activesupport/test/core_ext/duration_test.rb
@@ -30,7 +30,6 @@ class DurationTest < ActiveSupport::TestCase
assert ActiveSupport::Duration === 1.day
assert !(ActiveSupport::Duration === 1.day.to_i)
assert !(ActiveSupport::Duration === 'foo')
- assert !(ActiveSupport::Duration === ActiveSupport::ProxyObject.new)
end
def test_equals
diff --git a/activesupport/test/core_ext/string_ext_test.rb b/activesupport/test/core_ext/string_ext_test.rb
index 2f4691817f..b97aa56aef 100644
--- a/activesupport/test/core_ext/string_ext_test.rb
+++ b/activesupport/test/core_ext/string_ext_test.rb
@@ -260,8 +260,18 @@ class StringInflectionsTest < ActiveSupport::TestCase
end
def test_remove
- assert_equal "Summer", "Fast Summer".remove(/Fast /)
- assert_equal "Summer", "Fast Summer".remove!(/Fast /)
+ original = "This is a good day to die"
+ assert_equal "This is a good day", original.remove(" to die")
+ assert_equal "This is a good day", original.remove(" to ", /die/)
+ assert_equal "This is a good day to die", original
+ end
+
+ def test_remove!
+ original = "This is a very good day to die"
+ assert_equal "This is a good day to die", original.remove!(" very")
+ assert_equal "This is a good day to die", original
+ assert_equal "This is a good day", original.remove!(" to ", /die/)
+ assert_equal "This is a good day", original
end
def test_constantize
@@ -408,7 +418,7 @@ class StringConversionsTest < ActiveSupport::TestCase
now = Time.now
assert_equal Time.local(now.year, now.month, now.day, 23, 50), "23:50".to_time
assert_equal Time.utc(now.year, now.month, now.day, 23, 50), "23:50".to_time(:utc)
- assert_equal Time.local(now.year, now.month, now.day, 18, 50), "13:50 -0100".to_time
+ assert_equal Time.local(now.year, now.month, now.day, 17, 50), "13:50 -0100".to_time
assert_equal Time.utc(now.year, now.month, now.day, 23, 50), "22:50 -0100".to_time(:utc)
end
end
diff --git a/guides/source/4_2_release_notes.md b/guides/source/4_2_release_notes.md
index d9f49aac55..17894b2752 100644
--- a/guides/source/4_2_release_notes.md
+++ b/guides/source/4_2_release_notes.md
@@ -49,13 +49,13 @@ bog down the controller or model.
The new GlobalID library makes it easy to pass Active Record objects to jobs by
serializing them in a generic form. This means you no longer have to manually
pack and unpack your Active Records by passing ids. Just give the job the
-straight Active Record object, and it'll serialize it using GlobalID, and
-deserialize it at run time.
+Active Record object, and it'll serialize it using GlobalID, and deserialize
+it at run time.
### Adequate Record
Adequate Record is a set of refactorings that make Active Record `find` and
-`find_by` methods and some association queries upto 2x faster.
+`find_by` methods and some association queries up to 2x faster.
It works by caching SQL query patterns while executing the Active Record calls.
The cache helps skip parts of the computation involved in the transformation of
@@ -88,7 +88,7 @@ The caching is not used in the following scenarios:
Post.find [1,2]
```
-- `find_by` with sql fragments:
+- `find_by` with SQL fragments:
```ruby
Post.find_by "published_at < ?", 2.weeks.ago
@@ -196,9 +196,9 @@ end
Due to a [change in Rack](https://github.com/rack/rack/commit/28b014484a8ac0bbb388e7eaeeef159598ec64fc),
`rails server` now listens on `localhost` instead of `0.0.0.0` by default. This
should have minimal impact on the standard development workflow as both http://127.0.0.1:3000
-and http://localhost:3000 would continue to work as before on your own machine.
+and http://localhost:3000 will continue to work as before on your own machine.
-However, with this change you would no longer be able to access the Rails server
+However, with this change you will no longer be able to access the Rails server
from a different machine (e.g. your development environment is in a virtual
machine and you would like to access it from the host machine), you would need
to start the server with `rails server -b 0.0.0.0` to restore the old behavior.
@@ -471,7 +471,7 @@ Please refer to the [Changelog][action-pack] for detailed changes.
([Pull Request](https://github.com/rails/rails/pull/14280))
* When the Rails server is set to serve static assets, gzip assets will now be
- served if the client supports it and a pre-generated gzip file (.gz) is on disk.
+ served if the client supports it and a pre-generated gzip file (`.gz`) is on disk.
By default the asset pipeline generates `.gz` files for all compressible assets.
Serving gzip files minimizes data transfer and speeds up asset requests. Always
[use a CDN](http://guides.rubyonrails.org/asset_pipeline.html#cdns) if you are
@@ -479,7 +479,7 @@ Please refer to the [Changelog][action-pack] for detailed changes.
([Pull Request](https://github.com/rails/rails/pull/16466))
* The way `assert_select` works has changed; specifically a different library
- is used to interpret css selectors, build the transient DOM that the
+ is used to interpret CSS selectors, build the transient DOM that the
selectors are applied against, and to extract the data from that DOM. These
changes should only affect edge cases. Examples:
* Values in attribute selectors may need to be quoted if they contain
@@ -537,7 +537,7 @@ Please refer to the [Changelog][action-mailer] for detailed changes.
* Deprecated `*_path` helpers in mailers. Always use `*_url` helpers instead.
([Pull Request](https://github.com/rails/rails/pull/15840))
-* Deprecated `deliver` / `deliver!` in favour of `deliver_now` / `deliver_now!`.
+* Deprecated `deliver` / `deliver!` in favor of `deliver_now` / `deliver_now!`.
([Pull Request](https://github.com/rails/rails/pull/16582))
### Notable changes
@@ -596,7 +596,7 @@ Please refer to the [Changelog][active-record] for detailed changes.
([Pull Request](https://github.com/rails/rails/pull/15704))
* Deprecated returning `nil` from `column_for_attribute` when no column
- exists. It will return a null object in Rails 5.0
+ exists. It will return a null object in Rails 5.0.
([Pull Request](https://github.com/rails/rails/pull/15878))
* Deprecated using `.joins`, `.preload` and `.eager_load` with associations
@@ -648,7 +648,7 @@ Please refer to the [Changelog][active-record] for detailed changes.
([Commit](https://github.com/rails/rails/commit/e2f232aba15937a4b9d14bd91e0392c6d55be58d))
* `ActiveRecord::Dirty` now detects in-place changes to mutable values.
- Serialized attributes on ActiveRecord models will no longer save when
+ Serialized attributes on Active Record models will no longer save when
unchanged. This also works with other types such as string columns and json
columns on PostgreSQL.
(Pull Requests [1](https://github.com/rails/rails/pull/15674),
diff --git a/guides/source/_welcome.html.erb b/guides/source/_welcome.html.erb
index f84f1cb376..f2315bfe22 100644
--- a/guides/source/_welcome.html.erb
+++ b/guides/source/_welcome.html.erb
@@ -15,5 +15,5 @@
</p>
<% end %>
<p>
- The guides for earlier releases: <a href="http://guides.rubyonrails.org/v4.1.4/">Rails 4.1.4</a>, <a href="http://guides.rubyonrails.org/v4.0.8/">Rails 4.0.8</a>, <a href="http://guides.rubyonrails.org/v3.2.19/">Rails 3.2.19</a> and <a href="http://guides.rubyonrails.org/v2.3.11/">Rails 2.3.11</a>.
+ The guides for earlier releases: <a href="http://guides.rubyonrails.org/v4.1.6/">Rails 4.1.6</a>, <a href="http://guides.rubyonrails.org/v4.0.10/">Rails 4.0.10</a>, <a href="http://guides.rubyonrails.org/v3.2.19/">Rails 3.2.19</a> and <a href="http://guides.rubyonrails.org/v2.3.11/">Rails 2.3.11</a>.
</p>
diff --git a/guides/source/action_controller_overview.md b/guides/source/action_controller_overview.md
index 8890ea453e..1ca0d9ed55 100644
--- a/guides/source/action_controller_overview.md
+++ b/guides/source/action_controller_overview.md
@@ -1213,12 +1213,12 @@ Create the controller and views.
* `app/views`
```
- errors/
- not_found.html.erb
- unprocessable_entity.html.erb
- server_error.html.erb
- layouts/
- error.html.erb
+ errors/
+ not_found.html.erb
+ unprocessable_entity.html.erb
+ server_error.html.erb
+ layouts/
+ error.html.erb
```
Do not forget to set the correct status code on the controller as shown before.
diff --git a/guides/source/active_job_basics.md b/guides/source/active_job_basics.md
index de69ab3211..ca851371a9 100644
--- a/guides/source/active_job_basics.md
+++ b/guides/source/active_job_basics.md
@@ -41,10 +41,12 @@ This section will provide a step-by-step guide to creating a job and enqueuing i
### Create the Job
Active Job provides a Rails generator to create jobs. The following will create a
-job in `app/jobs`:
+job in `app/jobs` (with an attached test case under `test/jobs`):
```bash
$ bin/rails generate job guests_cleanup
+invoke test_unit
+create test/jobs/guests_cleanup_job_test.rb
create app/jobs/guests_cleanup_job.rb
```
@@ -52,7 +54,6 @@ You can also create a job that will run on a specific queue:
```bash
$ bin/rails generate job guests_cleanup --queue urgent
-create app/jobs/guests_cleanup_job.rb
```
As you can see, you can generate jobs just like you use other generators with
@@ -78,15 +79,18 @@ end
Enqueue a job like so:
```ruby
-MyJob.perform_later record # Enqueue a job to be performed as soon the queueing system is free.
+# Enqueue a job to be performed as soon the queueing system is free.
+MyJob.perform_later record
```
```ruby
-MyJob.set(wait_until: Date.tomorrow.noon).perform_later(record) # Enqueue a job to be performed tomorrow at noon.
+# Enqueue a job to be performed tomorrow at noon.
+MyJob.set(wait_until: Date.tomorrow.noon).perform_later(record)
```
```ruby
-MyJob.set(wait: 1.week).perform_later(record) # Enqueue a job to be performed 1 week from now.
+# Enqueue a job to be performed 1 week from now.
+MyJob.set(wait: 1.week).perform_later(record)
```
That's it!
@@ -108,9 +112,9 @@ see the API Documentation for [ActiveJob::QueueAdapters](http://api.rubyonrails.
You can easily change your queueing backend:
```ruby
-# be sure to have the adapter gem in your Gemfile and follow the adapter specific
-# installation and deployment instructions
-Rails.application.config.active_job.queue_adapter = :sidekiq
+# be sure to have the adapter gem in your Gemfile and follow
+# the adapter specific installation and deployment instructions
+config.active_job.queue_adapter = :sidekiq
```
@@ -262,12 +266,13 @@ UserMailer.welcome(@user).deliver_later
GlobalID
--------
+
Active Job supports GlobalID for parameters. This makes it possible to pass live
Active Record objects to your job instead of class/id pairs, which you then have
to manually deserialize. Before, jobs would look like this:
```ruby
-class TrashableCleanupJob
+class TrashableCleanupJob < ActiveJob::Base
def perform(trashable_class, trashable_id, depth)
trashable = trashable_class.constantize.find(trashable_id)
trashable.cleanup(depth)
@@ -278,7 +283,7 @@ end
Now you can simply do:
```ruby
-class TrashableCleanupJob
+class TrashableCleanupJob < ActiveJob::Base
def perform(trashable, depth)
trashable.cleanup(depth)
end
diff --git a/guides/source/active_record_validations.md b/guides/source/active_record_validations.md
index 6f45ca698d..546c0608ee 100644
--- a/guides/source/active_record_validations.md
+++ b/guides/source/active_record_validations.md
@@ -533,6 +533,7 @@ validates :boolean_field_name, presence: true
validates :boolean_field_name, inclusion: { in: [true, false] }
validates :boolean_field_name, exclusion: { in: [nil] }
```
+
By using one of these validations, you will ensure the value will NOT be `nil`
which would result in a `NULL` value in most cases.
diff --git a/guides/source/asset_pipeline.md b/guides/source/asset_pipeline.md
index e552c3804d..ae0f19c02a 100644
--- a/guides/source/asset_pipeline.md
+++ b/guides/source/asset_pipeline.md
@@ -1347,7 +1347,8 @@ config.assets.digest = true
Rails 4 no longer sets default config values for Sprockets in `test.rb`, so
`test.rb` now requires Sprockets configuration. The old defaults in the test
-environment are: `config.assets.compile = true`, `config.assets.compress = false`, `config.assets.debug = false` and `config.assets.digest = false`.
+environment are: `config.assets.compile = true`, `config.assets.compress = false`,
+`config.assets.debug = false` and `config.assets.digest = false`.
The following should also be added to `Gemfile`:
diff --git a/guides/source/configuring.md b/guides/source/configuring.md
index 58c3f217eb..2957232186 100644
--- a/guides/source/configuring.md
+++ b/guides/source/configuring.md
@@ -153,7 +153,7 @@ pipeline is enabled. It is set to true by default.
* `config.assets.manifest` defines the full path to be used for the asset precompiler's manifest file. Defaults to a file named `manifest-<random>.json` in the `config.assets.prefix` directory within the public folder.
-* `config.assets.digest` enables the use of MD5 fingerprints in asset names. Set to `true` by default in `production.rb`.
+* `config.assets.digest` enables the use of MD5 fingerprints in asset names. Set to `true` by default in `production.rb` and `development.rb`.
* `config.assets.debug` disables the concatenation and compression of assets. Set to `true` by default in `development.rb`.
diff --git a/guides/source/form_helpers.md b/guides/source/form_helpers.md
index 16fa23c129..cb45e38614 100644
--- a/guides/source/form_helpers.md
+++ b/guides/source/form_helpers.md
@@ -506,7 +506,7 @@ As the name implies, this only generates option tags. To generate a working sele
<%= collection_select(:person, :city_id, City.all, :id, :name) %>
```
-As with other helpers, if you were to use the collection_select helper on a form builder scoped to the @person object, the syntax would be:
+As with other helpers, if you were to use the `collection_select` helper on a form builder scoped to the `@person` object, the syntax would be:
```erb
<%= f.collection_select(:city_id, City.all, :id, :name) %>
diff --git a/guides/source/getting_started.md b/guides/source/getting_started.md
index 1769448531..92f8ef5b08 100644
--- a/guides/source/getting_started.md
+++ b/guides/source/getting_started.md
@@ -195,8 +195,8 @@ TIP: Compiling CoffeeScript and JavaScript asset compression requires you
have a JavaScript runtime available on your system, in the absence
of a runtime you will see an `execjs` error during asset compilation.
Usually Mac OS X and Windows come with a JavaScript runtime installed.
-Rails adds the `therubyracer` gem to the generated `Gemfile` in a
-commented line for new apps and you can uncomment if you need it.
+Rails adds the `therubyracer` gem to the generated `Gemfile` in a
+commented line for new apps and you can uncomment if you need it.
`therubyrhino` is the recommended runtime for JRuby users and is added by
default to the `Gemfile` in apps generated under JRuby. You can investigate
all the supported runtimes at [ExecJS](https://github.com/sstephenson/execjs#readme).
@@ -338,8 +338,8 @@ You can create, read, update and destroy items for a resource and these
operations are referred to as _CRUD_ operations.
Rails provides a `resources` method which can be used to declare a standard REST
-resource. Here's what `config/routes.rb` should look like after the
-_article resource_ is declared.
+resource. You need to add the _article resource_ to the
+`config/routes.rb` as follows:
```ruby
Rails.application.routes.draw do
diff --git a/guides/source/ruby_on_rails_guides_guidelines.md b/guides/source/ruby_on_rails_guides_guidelines.md
index 6206b3c715..c0438f6341 100644
--- a/guides/source/ruby_on_rails_guides_guidelines.md
+++ b/guides/source/ruby_on_rails_guides_guidelines.md
@@ -54,6 +54,7 @@ API Documentation Guidelines
The guides and the API should be coherent and consistent where appropriate. In particular, these sections of the [API Documentation Guidelines](api_documentation_guidelines.html) also apply to the guides:
* [Wording](api_documentation_guidelines.html#wording)
+* [English](api_documentation_guidelines.html#english)
* [Example Code](api_documentation_guidelines.html#example-code)
* [Filenames](api_documentation_guidelines.html#file-names)
* [Fonts](api_documentation_guidelines.html#fonts)
diff --git a/railties/lib/rails/application.rb b/railties/lib/rails/application.rb
index bc966e87c6..18d9cb72d6 100644
--- a/railties/lib/rails/application.rb
+++ b/railties/lib/rails/application.rb
@@ -88,6 +88,7 @@ module Rails
def inherited(base)
super
Rails.app_class = base
+ add_lib_to_load_path!(find_root(base.called_from))
end
def instance
@@ -98,6 +99,10 @@ module Rails
new(initial_variable_values, &block).run_load_hooks!
end
+ def find_root(from)
+ find_root_with_flag "config.ru", from, Dir.pwd
+ end
+
# Makes the +new+ method public.
#
# Note that Rails::Application inherits from Rails::Engine, which
@@ -129,8 +134,6 @@ module Rails
# are these actually used?
@initial_variable_values = initial_variable_values
@block = block
-
- add_lib_to_load_path!
end
# Returns true if the application is initialized.
@@ -313,8 +316,8 @@ module Rails
# are changing config.root inside your application definition or having a custom
# Rails application, you will need to add lib to $LOAD_PATH on your own in case
# you need to load files in lib/ during the application configuration as well.
- def add_lib_to_load_path! #:nodoc:
- path = File.join config.root, 'lib'
+ def self.add_lib_to_load_path!(root) #:nodoc:
+ path = File.join root, 'lib'
if File.exist?(path) && !$LOAD_PATH.include?(path)
$LOAD_PATH.unshift(path)
end
@@ -358,7 +361,7 @@ module Rails
end
def config #:nodoc:
- @config ||= Application::Configuration.new(find_root_with_flag("config.ru", Dir.pwd))
+ @config ||= Application::Configuration.new(self.class.find_root(self.class.called_from))
end
def config=(configuration) #:nodoc:
diff --git a/railties/lib/rails/engine.rb b/railties/lib/rails/engine.rb
index dc3da1eb41..d985518fd9 100644
--- a/railties/lib/rails/engine.rb
+++ b/railties/lib/rails/engine.rb
@@ -364,6 +364,10 @@ module Rails
super
end
+ def find_root(from)
+ find_root_with_flag "lib", from
+ end
+
def endpoint(endpoint = nil)
@endpoint ||= nil
@endpoint = endpoint if endpoint
@@ -531,7 +535,7 @@ module Rails
# Define the configuration object for the engine.
def config
- @config ||= Engine::Configuration.new(find_root_with_flag("lib"))
+ @config ||= Engine::Configuration.new(self.class.find_root(self.class.called_from))
end
# Load data from db/seeds.rb file. It can be used in to load engines'
@@ -658,8 +662,7 @@ module Rails
paths["db/migrate"].existent.any?
end
- def find_root_with_flag(flag, default=nil) #:nodoc:
- root_path = self.class.called_from
+ def self.find_root_with_flag(flag, root_path, default=nil) #:nodoc:
while root_path && File.directory?(root_path) && !File.exist?("#{root_path}/#{flag}")
parent = File.dirname(root_path)
diff --git a/railties/test/application/configuration_test.rb b/railties/test/application/configuration_test.rb
index 0eddf644d9..2b6eb3624a 100644
--- a/railties/test/application/configuration_test.rb
+++ b/railties/test/application/configuration_test.rb
@@ -59,6 +59,20 @@ module ApplicationTests
end
end
+ test "lib dir is on LOAD_PATH during config" do
+ app_file 'lib/my_logger.rb', <<-RUBY
+ require "logger"
+ class MyLogger < ::Logger
+ end
+ RUBY
+ add_to_top_of_config <<-RUBY
+ require 'my_logger'
+ config.logger = MyLogger.new STDOUT
+ RUBY
+ require "#{app_path}/config/environment"
+ assert_equal 'MyLogger', Rails.application.config.logger.class.name
+ end
+
test "a renders exception on pending migration" do
add_to_config <<-RUBY
config.active_record.migration_error = :page_load
diff --git a/railties/test/application/rake/dbs_test.rb b/railties/test/application/rake/dbs_test.rb
index 267469b6f5..524c70aad2 100644
--- a/railties/test/application/rake/dbs_test.rb
+++ b/railties/test/application/rake/dbs_test.rb
@@ -109,6 +109,16 @@ module ApplicationTests
db_fixtures_load database_url_db_name
end
+ test 'db:fixtures:load with namespaced fixture' do
+ require "#{app_path}/config/environment"
+ Dir.chdir(app_path) do
+ `rails generate model admin::book title:string;
+ bundle exec rake db:migrate db:fixtures:load`
+ require "#{app_path}/app/models/admin/book"
+ assert_equal 2, Admin::Book.count
+ end
+ end
+
def db_structure_dump_and_load(expected_database)
Dir.chdir(app_path) do
`rails generate model book title:string;
diff --git a/railties/test/isolation/abstract_unit.rb b/railties/test/isolation/abstract_unit.rb
index 40469e31d7..bf2992005b 100644
--- a/railties/test/isolation/abstract_unit.rb
+++ b/railties/test/isolation/abstract_unit.rb
@@ -231,6 +231,15 @@ module TestHelpers
end
end
+ def add_to_top_of_config(str)
+ environment = File.read("#{app_path}/config/application.rb")
+ if environment =~ /(Rails::Application\s*)/
+ File.open("#{app_path}/config/application.rb", 'w') do |f|
+ f.puts $` + $1 + "\n#{str}\n" + $'
+ end
+ end
+ end
+
def add_to_config(str)
environment = File.read("#{app_path}/config/application.rb")
if environment =~ /(\n\s*end\s*end\s*)\Z/
diff --git a/tools/README.md b/tools/README.md
index 13be763dac..25ab798bd5 100644
--- a/tools/README.md
+++ b/tools/README.md
@@ -3,5 +3,5 @@
This is a collection of utilities used for Rails internal development.
They aren't used by Rails apps directly.
- * `console` drops you in irb and loads this local Rails repos
- * `profile` profiles `Kernel#require` to help reduce startup times
+ * `console` drops you in irb and loads local Rails repos
+ * `profile` profiles `Kernel#require` to help reduce startup time