aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--actionpack/lib/action_controller/metal/mime_responds.rb20
-rw-r--r--actionpack/lib/action_controller/metal/renderers.rb3
-rw-r--r--actionpack/lib/action_controller/test_case.rb3
-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--actionpack/lib/action_dispatch/testing/integration.rb4
-rw-r--r--actionpack/test/abstract_unit.rb1
-rw-r--r--actionpack/test/controller/integration_test.rb36
-rw-r--r--actionpack/test/controller/test_case_test.rb12
-rw-r--r--actionpack/test/controller/url_for_test.rb5
-rw-r--r--activejob/README.md9
-rw-r--r--activejob/lib/active_job/base.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.rb1
-rw-r--r--activejob/lib/active_job/queue_name.rb1
-rw-r--r--activemodel/lib/active_model/dirty.rb2
-rw-r--r--activerecord/CHANGELOG.md25
-rw-r--r--activerecord/lib/active_record/associations.rb2
-rw-r--r--activerecord/lib/active_record/associations/builder/has_and_belongs_to_many.rb2
-rw-r--r--activerecord/lib/active_record/associations/collection_association.rb11
-rw-r--r--activerecord/lib/active_record/associations/has_many_through_association.rb2
-rw-r--r--activerecord/lib/active_record/associations/preloader/association.rb1
-rw-r--r--activerecord/lib/active_record/associations/singular_association.rb3
-rw-r--r--activerecord/lib/active_record/attribute_set/builder.rb21
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb4
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract_adapter.rb5
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb32
-rw-r--r--activerecord/lib/active_record/connection_adapters/mysql_adapter.rb2
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb1
-rw-r--r--activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb10
-rw-r--r--activerecord/lib/active_record/fixtures.rb2
-rw-r--r--activerecord/lib/active_record/inheritance.rb12
-rw-r--r--activerecord/lib/active_record/persistence.rb32
-rw-r--r--activerecord/lib/active_record/querying.rb2
-rw-r--r--activerecord/lib/active_record/railties/databases.rake3
-rw-r--r--activerecord/lib/active_record/relation/finder_methods.rb4
-rw-r--r--activerecord/lib/active_record/relation/predicate_builder/relation_handler.rb2
-rw-r--r--activerecord/lib/active_record/result.rb9
-rw-r--r--activerecord/lib/active_record/sanitization.rb3
-rw-r--r--activerecord/lib/active_record/tasks/mysql_database_tasks.rb1
-rw-r--r--activerecord/lib/active_record/type/string.rb8
-rw-r--r--activerecord/test/cases/adapters/postgresql/bytea_test.rb9
-rw-r--r--activerecord/test/cases/adapters/postgresql/datatype_test.rb7
-rw-r--r--activerecord/test/cases/adapters/postgresql/enum_test.rb2
-rw-r--r--activerecord/test/cases/adapters/postgresql/hstore_test.rb54
-rw-r--r--activerecord/test/cases/adapters/postgresql/json_test.rb11
-rw-r--r--activerecord/test/cases/adapters/postgresql/sql_types_test.rb18
-rw-r--r--activerecord/test/cases/adapters/postgresql/uuid_test.rb27
-rw-r--r--activerecord/test/cases/associations/belongs_to_associations_test.rb29
-rw-r--r--activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb11
-rw-r--r--activerecord/test/cases/associations/has_many_associations_test.rb41
-rw-r--r--activerecord/test/cases/finder_test.rb10
-rw-r--r--activerecord/test/cases/readonly_test.rb12
-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/type/string_test.rb4
-rw-r--r--activerecord/test/cases/validations/uniqueness_validation_test.rb2
-rw-r--r--activerecord/test/config.example.yml6
-rw-r--r--activerecord/test/fixtures/computers.yml5
-rw-r--r--activerecord/test/fixtures/developers.yml1
-rw-r--r--activerecord/test/models/developer.rb2
-rw-r--r--activerecord/test/schema/postgresql_specific_schema.rb15
-rw-r--r--activerecord/test/schema/schema.rb5
-rw-r--r--activesupport/CHANGELOG.md10
-rw-r--r--activesupport/lib/active_support/core_ext/hash/compact.rb6
-rw-r--r--activesupport/lib/active_support/core_ext/hash/except.rb10
-rw-r--r--activesupport/lib/active_support/core_ext/hash/slice.rb10
-rw-r--r--activesupport/lib/active_support/core_ext/string/filters.rb25
-rw-r--r--activesupport/lib/active_support/dependencies/autoload.rb2
-rw-r--r--activesupport/lib/active_support/duration.rb3
-rw-r--r--activesupport/lib/active_support/notifications.rb2
-rw-r--r--activesupport/test/core_ext/duration_test.rb13
-rw-r--r--activesupport/test/core_ext/range_ext_test.rb4
-rw-r--r--activesupport/test/core_ext/string_ext_test.rb24
-rw-r--r--activesupport/test/dependencies_test.rb225
-rw-r--r--guides/source/4_1_release_notes.md2
-rw-r--r--guides/source/4_2_release_notes.md43
-rw-r--r--guides/source/_welcome.html.erb2
-rw-r--r--guides/source/action_controller_overview.md12
-rw-r--r--guides/source/active_record_validations.md1
-rw-r--r--guides/source/command_line.md21
-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/testing.md64
-rw-r--r--guides/source/upgrading_ruby_on_rails.md4
-rw-r--r--railties/CHANGELOG.md2
-rw-r--r--railties/lib/rails/application.rb13
-rw-r--r--railties/lib/rails/code_statistics.rb1
-rw-r--r--railties/lib/rails/commands/destroy.rb2
-rw-r--r--railties/lib/rails/commands/generate.rb2
-rw-r--r--railties/lib/rails/engine.rb9
-rw-r--r--railties/lib/rails/info.rb3
-rw-r--r--railties/lib/rails/source_annotation_extractor.rb5
-rw-r--r--railties/lib/rails/tasks/statistics.rake3
-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
103 files changed, 812 insertions, 400 deletions
diff --git a/actionpack/lib/action_controller/metal/mime_responds.rb b/actionpack/lib/action_controller/metal/mime_responds.rb
index 591f881a53..ac1f209232 100644
--- a/actionpack/lib/action_controller/metal/mime_responds.rb
+++ b/actionpack/lib/action_controller/metal/mime_responds.rb
@@ -135,18 +135,6 @@ module ActionController #:nodoc:
#
# render json: @people
#
- # Since this is a common pattern, you can use the class method respond_to
- # with the respond_with method to have the same results:
- #
- # class PeopleController < ApplicationController
- # respond_to :html, :xml, :json
- #
- # def index
- # @people = Person.all
- # respond_with(@people)
- # end
- # end
- #
# Formats can have different variants.
#
# The request variant is a specialization of the request format, like <tt>:tablet</tt>,
@@ -214,8 +202,8 @@ module ActionController #:nodoc:
# format.html.phone # this gets rendered
# end
#
- # Be sure to check the documentation of +respond_with+ and
- # <tt>ActionController::MimeResponds.respond_to</tt> for more examples.
+ # Be sure to check the documentation of <tt>ActionController::MimeResponds.respond_to</tt>
+ # for more examples.
def respond_to(*mimes)
raise ArgumentError, "respond_to takes either types or a block, never both" if mimes.any? && block_given?
@@ -234,8 +222,8 @@ module ActionController #:nodoc:
# A container for responses available from the current controller for
# requests for different mime-types sent to a particular action.
#
- # The public controller methods +respond_with+ and +respond_to+ may be called
- # with a block that is used to define responses to different mime-types, e.g.
+ # The public controller methods +respond_to+ may be called with a block
+ # that is used to define responses to different mime-types, e.g.
# for +respond_to+ :
#
# respond_to do |format|
diff --git a/actionpack/lib/action_controller/metal/renderers.rb b/actionpack/lib/action_controller/metal/renderers.rb
index bc94536c8c..45d3962494 100644
--- a/actionpack/lib/action_controller/metal/renderers.rb
+++ b/actionpack/lib/action_controller/metal/renderers.rb
@@ -86,8 +86,7 @@ module ActionController
# end
# end
# To use renderers and their mime types in more concise ways, see
- # <tt>ActionController::MimeResponds::ClassMethods.respond_to</tt> and
- # <tt>ActionController::MimeResponds#respond_with</tt>
+ # <tt>ActionController::MimeResponds::ClassMethods.respond_to</tt>
def self.add(key, &block)
define_method(_render_with_renderer_method_name(key), &block)
RENDERERS << key.to_sym
diff --git a/actionpack/lib/action_controller/test_case.rb b/actionpack/lib/action_controller/test_case.rb
index 41d33d4396..aa475dc4c4 100644
--- a/actionpack/lib/action_controller/test_case.rb
+++ b/actionpack/lib/action_controller/test_case.rb
@@ -710,7 +710,8 @@ module ActionController
:relative_url_root => nil,
:_recall => @request.path_parameters)
- url, query_string = @routes.path_for(options).split("?", 2)
+ route_name = options.delete :use_route
+ url, query_string = @routes.path_for(options, route_name).split("?", 2)
@request.env["SCRIPT_NAME"] = @controller.config.relative_url_root
@request.env["PATH_INFO"] = url
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/actionpack/lib/action_dispatch/testing/integration.rb b/actionpack/lib/action_dispatch/testing/integration.rb
index c300a4ea0d..fb816aa875 100644
--- a/actionpack/lib/action_dispatch/testing/integration.rb
+++ b/actionpack/lib/action_dispatch/testing/integration.rb
@@ -326,6 +326,10 @@ module ActionDispatch
@integration_session = Integration::Session.new(app)
end
+ def remove! # :nodoc:
+ @integration_session = nil
+ end
+
%w(get post patch put head delete cookies assigns
xml_http_request xhr get_via_redirect post_via_redirect).each do |method|
define_method(method) do |*args|
diff --git a/actionpack/test/abstract_unit.rb b/actionpack/test/abstract_unit.rb
index 69312e4c22..63c9ab04c9 100644
--- a/actionpack/test/abstract_unit.rb
+++ b/actionpack/test/abstract_unit.rb
@@ -194,6 +194,7 @@ class ActionDispatch::IntegrationTest < ActiveSupport::TestCase
yield temporary_routes
ensure
self.class.app = old_app
+ self.remove!
silence_warnings { Object.const_set(:SharedTestRoutes, old_routes) }
end
diff --git a/actionpack/test/controller/integration_test.rb b/actionpack/test/controller/integration_test.rb
index d91a1657b3..27b30536b0 100644
--- a/actionpack/test/controller/integration_test.rb
+++ b/actionpack/test/controller/integration_test.rb
@@ -814,3 +814,39 @@ class HeadWithStatusActionIntegrationTest < ActionDispatch::IntegrationTest
assert_response :ok
end
end
+
+class IntegrationWithRoutingTest < ActionDispatch::IntegrationTest
+ class FooController < ActionController::Base
+ def index
+ render plain: 'ok'
+ end
+ end
+
+ def test_with_routing_resets_session
+ klass_namespace = self.class.name.underscore
+
+ with_routing do |routes|
+ routes.draw do
+ namespace klass_namespace do
+ resources :foo, path: '/with'
+ end
+ end
+
+ get '/integration_with_routing_test/with'
+ assert_response 200
+ assert_equal 'ok', response.body
+ end
+
+ with_routing do |routes|
+ routes.draw do
+ namespace klass_namespace do
+ resources :foo, path: '/routing'
+ end
+ end
+
+ get '/integration_with_routing_test/routing'
+ assert_response 200
+ assert_equal 'ok', response.body
+ end
+ end
+end
diff --git a/actionpack/test/controller/test_case_test.rb b/actionpack/test/controller/test_case_test.rb
index 9d7abd5e94..957c0a5288 100644
--- a/actionpack/test/controller/test_case_test.rb
+++ b/actionpack/test/controller/test_case_test.rb
@@ -499,6 +499,18 @@ XML
end
end
+ def test_use_route
+ with_routing do |set|
+ set.draw do
+ get 'via_unnamed_route', to: 'test_case_test/test#test_uri'
+ get 'via_named_route', as: :a_named_route, to: 'test_case_test/test#test_uri'
+ end
+
+ get :test_uri, use_route: :a_named_route
+ assert_equal '/via_named_route', @response.body
+ end
+ end
+
def test_assert_realistic_path_parameters
get :test_params, :id => 20, :foo => Object.new
diff --git a/actionpack/test/controller/url_for_test.rb b/actionpack/test/controller/url_for_test.rb
index 969129d9ba..c05cde87e4 100644
--- a/actionpack/test/controller/url_for_test.rb
+++ b/actionpack/test/controller/url_for_test.rb
@@ -25,8 +25,7 @@ module AbstractController
path = klass.new.fun_path({:controller => :articles,
:baz => "baz",
- :zot => "zot",
- :only_path => true })
+ :zot => "zot"})
# :bar key isn't provided
assert_equal '/foo/zot', path
end
@@ -291,7 +290,7 @@ module AbstractController
assert_equal '/brave/new/world',
controller.url_for(:controller => 'brave', :action => 'new', :id => 'world', :only_path => true)
- assert_equal("/home/sweet/home/alabama", controller.home_path(:user => 'alabama', :host => 'unused', :only_path => true))
+ assert_equal("/home/sweet/home/alabama", controller.home_path(:user => 'alabama', :host => 'unused'))
assert_equal("/home/sweet/home/alabama", controller.home_path('alabama'))
end
end
diff --git a/activejob/README.md b/activejob/README.md
index b5d27272b1..8c83d3669a 100644
--- a/activejob/README.md
+++ b/activejob/README.md
@@ -5,7 +5,7 @@ of queueing backends. These jobs can be everything from regularly scheduled
clean-ups, to billing charges, to mailings. Anything that can be chopped up into
small units of work and run in parallel, really.
-It also serves as the backend for ActionMailer's #deliver_later functionality
+It also serves as the backend for Action Mailer's #deliver_later functionality
that makes it easy to turn any mailing into a job for running later. That's
one of the most common jobs in a modern web application: Sending emails outside
of the request-response cycle, so the user doesn't have to wait on it.
@@ -26,7 +26,8 @@ Set the queue adapter for Active Job:
ActiveJob::Base.queue_adapter = :inline # default queue adapter
```
Note: To learn how to use your preferred queueing backend see its adapter
-documentation at ActiveJob::QueueAdapters.
+documentation at
+[ActiveJob::QueueAdapters](http://api.rubyonrails.org/classes/ActiveJob/QueueAdapters.html).
Declare a job like so:
@@ -110,7 +111,7 @@ Source code can be downloaded as part of the Rails project on GitHub
## License
-ActiveJob is released under the MIT license:
+Active Job is released under the MIT license:
* http://www.opensource.org/licenses/MIT
@@ -128,5 +129,3 @@ Bug reports can be filed for the Ruby on Rails project here:
Feature requests should be discussed on the rails-core mailing list here:
* https://groups.google.com/forum/?fromgroups#!forum/rubyonrails-core
-
-
diff --git a/activejob/lib/active_job/base.rb b/activejob/lib/active_job/base.rb
index 0c4a29090e..fd49b3fda5 100644
--- a/activejob/lib/active_job/base.rb
+++ b/activejob/lib/active_job/base.rb
@@ -32,7 +32,7 @@ module ActiveJob #:nodoc:
# end
#
# Records that are passed in are serialized/deserialized using Global
- # Id. More information can be found in Arguments.
+ # ID. More information can be found in Arguments.
#
# To enqueue a job to be performed as soon the queueing system is free:
#
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 b42ec3b638..85d7c44bb8 100644
--- a/activejob/lib/active_job/queue_adapter.rb
+++ b/activejob/lib/active_job/queue_adapter.rb
@@ -7,6 +7,7 @@ module ActiveJob
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_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/activemodel/lib/active_model/dirty.rb b/activemodel/lib/active_model/dirty.rb
index ae185694ca..4e389c8692 100644
--- a/activemodel/lib/active_model/dirty.rb
+++ b/activemodel/lib/active_model/dirty.rb
@@ -255,7 +255,7 @@ module ActiveModel
end
# Remove changes information for the provided attributes.
- def clear_attribute_changes(attributes)
+ def clear_attribute_changes(attributes) # :doc:
attributes_changed_by_setter.except!(*attributes)
end
end
diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md
index ab85f2a472..2c66ddb983 100644
--- a/activerecord/CHANGELOG.md
+++ b/activerecord/CHANGELOG.md
@@ -1,3 +1,28 @@
+* Cache `CollectionAssociation#reader` proxies separately before and after
+ the owner has been saved so that the proxy is not cached without the
+ owner's id.
+
+ *Ben Woosley*
+
+* `ActiveRecord::ReadOnlyRecord` now has a descriptive message.
+
+ *Franky W.*
+
+* Fix preloading of associations which unscope a default scope.
+
+ Fixes #11036.
+
+ *Byron Bischoff*
+
+* 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`.
diff --git a/activerecord/lib/active_record/associations.rb b/activerecord/lib/active_record/associations.rb
index 8911506694..d2bcdc55bf 100644
--- a/activerecord/lib/active_record/associations.rb
+++ b/activerecord/lib/active_record/associations.rb
@@ -1700,7 +1700,7 @@ module ActiveRecord
hm_options[:through] = middle_reflection.name
hm_options[:source] = join_model.right_reflection.name
- [:before_add, :after_add, :before_remove, :after_remove, :autosave, :validate, :join_table].each do |k|
+ [:before_add, :after_add, :before_remove, :after_remove, :autosave, :validate, :join_table, :class_name].each do |k|
hm_options[k] = options[k] if options.key? k
end
diff --git a/activerecord/lib/active_record/associations/builder/has_and_belongs_to_many.rb b/activerecord/lib/active_record/associations/builder/has_and_belongs_to_many.rb
index 815e8eb97f..357b28ac94 100644
--- a/activerecord/lib/active_record/associations/builder/has_and_belongs_to_many.rb
+++ b/activerecord/lib/active_record/associations/builder/has_and_belongs_to_many.rb
@@ -98,7 +98,7 @@ module ActiveRecord::Associations::Builder
def middle_options(join_model)
middle_options = {}
- middle_options[:class] = join_model
+ middle_options[:class_name] = "#{lhs_model.name}::#{join_model.name}"
middle_options[:source] = join_model.left_reflection.name
if options.key? :foreign_key
middle_options[:foreign_key] = options[:foreign_key]
diff --git a/activerecord/lib/active_record/associations/collection_association.rb b/activerecord/lib/active_record/associations/collection_association.rb
index bdfd569be2..93f611dd8d 100644
--- a/activerecord/lib/active_record/associations/collection_association.rb
+++ b/activerecord/lib/active_record/associations/collection_association.rb
@@ -33,7 +33,13 @@ module ActiveRecord
reload
end
- @proxy ||= CollectionProxy.create(klass, self)
+ if owner.new_record?
+ # Cache the proxy separately before the owner has an id
+ # or else a post-save proxy will still lack the id
+ @new_record_proxy ||= CollectionProxy.create(klass, self)
+ else
+ @proxy ||= CollectionProxy.create(klass, self)
+ end
end
# Implements the writer method, e.g. foo.items= for Foo.has_many :items
@@ -409,7 +415,8 @@ module ActiveRecord
def get_records
if reflection.scope_chain.any?(&:any?) ||
scope.eager_loading? ||
- klass.current_scope
+ klass.current_scope ||
+ klass.default_scopes.any?
return scope.to_a
end
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/association.rb b/activerecord/lib/active_record/associations/preloader/association.rb
index c0639742be..496c426986 100644
--- a/activerecord/lib/active_record/associations/preloader/association.rb
+++ b/activerecord/lib/active_record/associations/preloader/association.rb
@@ -159,6 +159,7 @@ module ActiveRecord
scope.where!(klass.table_name => { reflection.type => model.base_class.sti_name })
end
+ scope.unscope_values = Array(values[:unscope])
klass.default_scoped.merge(scope)
end
end
diff --git a/activerecord/lib/active_record/associations/singular_association.rb b/activerecord/lib/active_record/associations/singular_association.rb
index c360ef1b2c..c44242a0f0 100644
--- a/activerecord/lib/active_record/associations/singular_association.rb
+++ b/activerecord/lib/active_record/associations/singular_association.rb
@@ -41,7 +41,8 @@ module ActiveRecord
def get_records
if reflection.scope_chain.any?(&:any?) ||
scope.eager_loading? ||
- klass.current_scope
+ klass.current_scope ||
+ klass.default_scopes.any?
return scope.limit(1).to_a
end
diff --git a/activerecord/lib/active_record/attribute_set/builder.rb b/activerecord/lib/active_record/attribute_set/builder.rb
index d4a787f2fe..0a62c68bfb 100644
--- a/activerecord/lib/active_record/attribute_set/builder.rb
+++ b/activerecord/lib/active_record/attribute_set/builder.rb
@@ -8,18 +8,33 @@ module ActiveRecord
end
def build_from_database(values = {}, additional_types = {})
- attributes = build_attributes_from_values(values, additional_types)
+ build_from_database_pairs(values.keys, values.values, additional_types)
+ end
+
+ def build_from_database_pairs(columns, values, additional_types)
+ attributes = build_attributes_from_values(columns, values, additional_types)
add_uninitialized_attributes(attributes)
AttributeSet.new(attributes)
end
private
- def build_attributes_from_values(values, additional_types)
- values.each_with_object({}) do |(name, value), hash|
+ def build_attributes_from_values(columns, values, additional_types)
+ # We are performing manual iteration here as this method is a performance
+ # hotspot
+ hash = {}
+ index = 0
+ length = columns.length
+
+ while index < length
+ name = columns[index]
+ value = values[index]
type = additional_types.fetch(name, types[name])
hash[name] = Attribute.from_database(name, value, type)
+ index += 1
end
+
+ hash
end
def add_uninitialized_attributes(attributes)
diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb
index f8b6daea5a..dd4c4ae9fc 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb
@@ -124,8 +124,8 @@ module ActiveRecord
# which is one of the following:
# <tt>:primary_key</tt>, <tt>:string</tt>, <tt>:text</tt>,
# <tt>:integer</tt>, <tt>:float</tt>, <tt>:decimal</tt>,
- # <tt>:datetime</tt>, <tt>:timestamp</tt>, <tt>:time</tt>,
- # <tt>:date</tt>, <tt>:binary</tt>, <tt>:boolean</tt>.
+ # <tt>:datetime</tt>, <tt>:time</tt>, <tt>:date</tt>,
+ # <tt>:binary</tt>, <tt>:boolean</tt>.
#
# You may use a type not in this list as long as it is supported by your
# database (for example, "polygon" in MySQL), but this will not be database
diff --git a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb
index dc1f3c9457..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
diff --git a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb
index 7f04e35042..26015528e5 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb
@@ -585,14 +585,6 @@ module ActiveRecord
end
end
- def add_column_position!(sql, options)
- if options[:first]
- sql << " FIRST"
- elsif options[:after]
- sql << " AFTER #{quote_column_name(options[:after])}"
- end
- end
-
# SHOW VARIABLES LIKE 'name'
def show_variable(name)
variables = select_all("SHOW VARIABLES LIKE '#{name}'", 'SCHEMA')
@@ -656,6 +648,8 @@ module ActiveRecord
def initialize_type_map(m) # :nodoc:
super
+ register_class_with_limit m, %r(char)i, MysqlString
+
m.register_type %r(tinytext)i, Type::Text.new(limit: 2**8 - 1)
m.register_type %r(tinyblob)i, Type::Binary.new(limit: 2**8 - 1)
m.register_type %r(text)i, Type::Text.new(limit: 2**16 - 1)
@@ -680,7 +674,7 @@ module ActiveRecord
m.register_type(%r(enum)i) do |sql_type|
limit = sql_type[/^enum\((.+)\)/i, 1]
.split(',').map{|enum| enum.strip.length - 2}.max
- Type::String.new(limit: limit)
+ MysqlString.new(limit: limit)
end
end
@@ -855,6 +849,26 @@ module ActiveRecord
end
end
end
+
+ class MysqlString < Type::String # :nodoc:
+ def type_cast_for_database(value)
+ case value
+ when true then "1"
+ when false then "0"
+ else super
+ end
+ end
+
+ private
+
+ def cast_value(value)
+ case value
+ when true then "1"
+ when false then "0"
+ else super
+ end
+ end
+ end
end
end
end
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_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
index e472741660..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" },
diff --git a/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb b/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb
index 4756896ac5..b18cb353f1 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
@@ -179,10 +179,6 @@ module ActiveRecord
true
end
- def supports_add_column?
- true
- end
-
def supports_views?
true
end
@@ -451,12 +447,12 @@ module ActiveRecord
# See: http://www.sqlite.org/lang_altertable.html
# SQLite has an additional restriction on the ALTER TABLE statement
- def valid_alter_table_options( type, options)
+ def valid_alter_table_type?(type)
type.to_sym != :primary_key
end
def add_column(table_name, column_name, type, options = {}) #:nodoc:
- if supports_add_column? && valid_alter_table_options( type, options )
+ if valid_alter_table_type?(type)
super(table_name, column_name, type, options)
else
alter_table(table_name) do |definition|
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/inheritance.rb b/activerecord/lib/active_record/inheritance.rb
index f58145ab05..4aad3217cb 100644
--- a/activerecord/lib/active_record/inheritance.rb
+++ b/activerecord/lib/active_record/inheritance.rb
@@ -165,15 +165,19 @@ module ActiveRecord
# record instance. For single-table inheritance, we check the record
# for a +type+ column and return the corresponding class.
def discriminate_class_for_record(record)
- if using_single_table_inheritance?(record)
- find_sti_class(record[inheritance_column])
+ discriminate_class_for_value(record[inheritance_column])
+ end
+
+ def discriminate_class_for_value(value)
+ if using_single_table_inheritance?(value)
+ find_sti_class(value)
else
super
end
end
- def using_single_table_inheritance?(record)
- record[inheritance_column].present? && columns_hash.include?(inheritance_column)
+ def using_single_table_inheritance?(value)
+ value.present? && columns_hash.include?(inheritance_column)
end
def find_sti_class(type_name)
diff --git a/activerecord/lib/active_record/persistence.rb b/activerecord/lib/active_record/persistence.rb
index 755ff2b2f1..06c8bceb30 100644
--- a/activerecord/lib/active_record/persistence.rb
+++ b/activerecord/lib/active_record/persistence.rb
@@ -65,19 +65,41 @@ module ActiveRecord
# how this "single-table" inheritance mapping is implemented.
def instantiate(attributes, column_types = {})
klass = discriminate_class_for_record(attributes)
- attributes = klass.attributes_builder.build_from_database(attributes, column_types)
- klass.allocate.init_with('attributes' => attributes, 'new_record' => false)
+ klass.instantiate_pairs(attributes.keys, attributes.values, column_types)
+ end
+
+ def instantiate_pairs(columns, values, column_types = {}) # :nodoc:
+ attributes = attributes_builder.build_from_database_pairs(columns, values, column_types)
+ allocate.init_with('attributes' => attributes, 'new_record' => false)
+ end
+
+ def instantiate_result_set(result_set, column_types = {}) # :nodoc:
+ inheritance_column_index = inheritance_column && result_set.columns.find_index(inheritance_column)
+
+ result_set.each_pair.map do |columns, values|
+ inheritance_value = inheritance_column_index && values[inheritance_column_index]
+ klass = discriminate_class_for_value(inheritance_value)
+ klass.instantiate_pairs(columns, values, column_types)
+ end
end
private
# Called by +instantiate+ to decide which class to use for a new
# record instance.
#
- # See +ActiveRecord::Inheritance#discriminate_class_for_record+ for
+ # See +ActiveRecord::Inheritance#discriminate_class_for_value+ for
# the single-table inheritance discriminator.
+ def discriminate_class_for_value(*)
+ self
+ end
+
def discriminate_class_for_record(record)
self
end
+
+ def inheritance_column
+ nil
+ end
end
# Returns true if this object hasn't been saved yet -- that is, a record
@@ -166,7 +188,7 @@ module ActiveRecord
# and <tt>destroy</tt> returns +false+. See
# ActiveRecord::Callbacks for further details.
def destroy
- raise ReadOnlyRecord if readonly?
+ raise ReadOnlyRecord, "#{self.class} is marked as readonly" if readonly?
destroy_associations
destroy_row if persisted?
@destroyed = true
@@ -497,7 +519,7 @@ module ActiveRecord
end
def create_or_update
- raise ReadOnlyRecord if readonly?
+ raise ReadOnlyRecord, "#{self.class} is marked as readonly" if readonly?
result = new_record? ? _create_record : _update_record
result != false
end
diff --git a/activerecord/lib/active_record/querying.rb b/activerecord/lib/active_record/querying.rb
index e8de4db3a7..9d4df81b07 100644
--- a/activerecord/lib/active_record/querying.rb
+++ b/activerecord/lib/active_record/querying.rb
@@ -47,7 +47,7 @@ module ActiveRecord
}
message_bus.instrument('instantiation.active_record', payload) do
- result_set.map { |record| instantiate(record, column_types) }
+ instantiate_result_set(result_set, column_types)
end
end
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/finder_methods.rb b/activerecord/lib/active_record/relation/finder_methods.rb
index 6dd932e530..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
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/result.rb b/activerecord/lib/active_record/result.rb
index 3a3e65ef32..c84ad586e2 100644
--- a/activerecord/lib/active_record/result.rb
+++ b/activerecord/lib/active_record/result.rb
@@ -54,6 +54,15 @@ module ActiveRecord
end
end
+ def each_pair
+ return to_enum(__method__) unless block_given?
+
+ columns = @columns.map { |c| c.dup.freeze }
+ @rows.each do |row|
+ yield columns, row
+ end
+ end
+
def to_hash
hash_rows
end
diff --git a/activerecord/lib/active_record/sanitization.rb b/activerecord/lib/active_record/sanitization.rb
index 2c5cf944a4..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)
diff --git a/activerecord/lib/active_record/tasks/mysql_database_tasks.rb b/activerecord/lib/active_record/tasks/mysql_database_tasks.rb
index d890196f47..eafbb2c249 100644
--- a/activerecord/lib/active_record/tasks/mysql_database_tasks.rb
+++ b/activerecord/lib/active_record/tasks/mysql_database_tasks.rb
@@ -31,6 +31,7 @@ module ActiveRecord
end
establish_connection configuration
else
+ $stderr.puts error.inspect
$stderr.puts "Couldn't create database for #{configuration.inspect}, #{creation_options.inspect}"
$stderr.puts "(If you set the charset manually, make sure you have a matching collation)" if configuration['encoding']
end
diff --git a/activerecord/lib/active_record/type/string.rb b/activerecord/lib/active_record/type/string.rb
index 150defb106..fbc0af2c5a 100644
--- a/activerecord/lib/active_record/type/string.rb
+++ b/activerecord/lib/active_record/type/string.rb
@@ -15,8 +15,8 @@ module ActiveRecord
case value
when ::Numeric, ActiveSupport::Duration then value.to_s
when ::String then ::String.new(value)
- when true then "1"
- when false then "0"
+ when true then "t"
+ when false then "f"
else super
end
end
@@ -25,8 +25,8 @@ module ActiveRecord
def cast_value(value)
case value
- when true then "1"
- when false then "0"
+ when true then "t"
+ when false then "f"
# String.new is slightly faster than dup
else ::String.new(value.to_s)
end
diff --git a/activerecord/test/cases/adapters/postgresql/bytea_test.rb b/activerecord/test/cases/adapters/postgresql/bytea_test.rb
index 7872f91943..aeebec034d 100644
--- a/activerecord/test/cases/adapters/postgresql/bytea_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/bytea_test.rb
@@ -17,7 +17,6 @@ class PostgresqlByteaTest < ActiveRecord::TestCase
end
end
@column = ByteaDataType.columns_hash['payload']
- assert(@column.is_a?(ActiveRecord::ConnectionAdapters::PostgreSQLColumn))
end
teardown do
@@ -25,9 +24,17 @@ class PostgresqlByteaTest < ActiveRecord::TestCase
end
def test_column
+ assert @column.is_a?(ActiveRecord::ConnectionAdapters::PostgreSQLColumn)
assert_equal :binary, @column.type
end
+ def test_binary_columns_are_limitless_the_upper_limit_is_one_GB
+ assert_equal 'bytea', @connection.type_to_sql(:binary, 100_000)
+ assert_raise ActiveRecord::ActiveRecordError do
+ @connection.type_to_sql :binary, 4294967295
+ end
+ end
+
def test_type_cast_binary_converts_the_encoding
assert @column
diff --git a/activerecord/test/cases/adapters/postgresql/datatype_test.rb b/activerecord/test/cases/adapters/postgresql/datatype_test.rb
index a0a34e4b87..2c4839338c 100644
--- a/activerecord/test/cases/adapters/postgresql/datatype_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/datatype_test.rb
@@ -94,6 +94,13 @@ class PostgresqlDataTypeTest < ActiveRecord::TestCase
assert @first_oid.reload
assert_equal new_value, @first_oid.obj_id
end
+
+ def test_text_columns_are_limitless_the_upper_limit_is_one_GB
+ assert_equal 'text', @connection.type_to_sql(:text, 100_000)
+ assert_raise ActiveRecord::ActiveRecordError do
+ @connection.type_to_sql :text, 4294967295
+ end
+ end
end
class PostgresqlInternalDataTypeTest < ActiveRecord::TestCase
diff --git a/activerecord/test/cases/adapters/postgresql/enum_test.rb b/activerecord/test/cases/adapters/postgresql/enum_test.rb
index d99c4a292e..83cedc5a7b 100644
--- a/activerecord/test/cases/adapters/postgresql/enum_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/enum_test.rb
@@ -1,8 +1,6 @@
# -*- coding: utf-8 -*-
require "cases/helper"
require 'support/connection_helper'
-require 'active_record/base'
-require 'active_record/connection_adapters/postgresql_adapter'
class PostgresqlEnumTest < ActiveRecord::TestCase
include ConnectionHelper
diff --git a/activerecord/test/cases/adapters/postgresql/hstore_test.rb b/activerecord/test/cases/adapters/postgresql/hstore_test.rb
index 1296eb72c0..6a9c6483fe 100644
--- a/activerecord/test/cases/adapters/postgresql/hstore_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/hstore_test.rb
@@ -1,41 +1,38 @@
# encoding: utf-8
-
require "cases/helper"
-require 'active_record/base'
-require 'active_record/connection_adapters/postgresql_adapter'
-class PostgresqlHstoreTest < ActiveRecord::TestCase
- class Hstore < ActiveRecord::Base
- self.table_name = 'hstores'
+if ActiveRecord::Base.connection.supports_extensions?
+ class PostgresqlHstoreTest < ActiveRecord::TestCase
+ class Hstore < ActiveRecord::Base
+ self.table_name = 'hstores'
- store_accessor :settings, :language, :timezone
- end
+ store_accessor :settings, :language, :timezone
+ end
- def setup
- @connection = ActiveRecord::Base.connection
+ def setup
+ @connection = ActiveRecord::Base.connection
- unless @connection.extension_enabled?('hstore')
- @connection.enable_extension 'hstore'
- @connection.commit_db_transaction
- end
+ unless @connection.extension_enabled?('hstore')
+ @connection.enable_extension 'hstore'
+ @connection.commit_db_transaction
+ end
- @connection.reconnect!
+ @connection.reconnect!
- @connection.transaction do
- @connection.create_table('hstores') do |t|
- t.hstore 'tags', :default => ''
- t.hstore 'payload', array: true
- t.hstore 'settings'
+ @connection.transaction do
+ @connection.create_table('hstores') do |t|
+ t.hstore 'tags', :default => ''
+ t.hstore 'payload', array: true
+ t.hstore 'settings'
+ end
end
+ @column = Hstore.columns_hash['tags']
end
- @column = Hstore.columns_hash['tags']
- end
- teardown do
- @connection.execute 'drop table if exists hstores'
- end
+ teardown do
+ @connection.execute 'drop table if exists hstores'
+ end
- if ActiveRecord::Base.connection.supports_extensions?
def test_hstore_included_in_extensions
assert @connection.respond_to?(:extensions), "connection should have a list of extensions"
assert @connection.extensions.include?('hstore'), "extension list should include hstore"
@@ -315,10 +312,8 @@ class PostgresqlHstoreTest < ActiveRecord::TestCase
dupe = record.dup
assert_equal({"one" => "two"}, dupe.tags.to_hash)
end
- end
-
- private
+ private
def assert_array_cycle(array)
# test creation
x = Hstore.create!(payload: array)
@@ -346,4 +341,5 @@ class PostgresqlHstoreTest < ActiveRecord::TestCase
x.reload
assert_equal(hash, x.tags)
end
+ end
end
diff --git a/activerecord/test/cases/adapters/postgresql/json_test.rb b/activerecord/test/cases/adapters/postgresql/json_test.rb
index 86ba849445..340ca29c0e 100644
--- a/activerecord/test/cases/adapters/postgresql/json_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/json_test.rb
@@ -1,10 +1,10 @@
# encoding: utf-8
-
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 +64,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/adapters/postgresql/sql_types_test.rb b/activerecord/test/cases/adapters/postgresql/sql_types_test.rb
deleted file mode 100644
index d7d40f6385..0000000000
--- a/activerecord/test/cases/adapters/postgresql/sql_types_test.rb
+++ /dev/null
@@ -1,18 +0,0 @@
-require "cases/helper"
-
-class SqlTypesTest < ActiveRecord::TestCase
- def test_binary_types
- assert_equal 'bytea', type_to_sql(:binary, 100_000)
- assert_raise ActiveRecord::ActiveRecordError do
- type_to_sql :binary, 4294967295
- end
- assert_equal 'text', type_to_sql(:text, 100_000)
- assert_raise ActiveRecord::ActiveRecordError do
- type_to_sql :text, 4294967295
- end
- end
-
- def type_to_sql(*args)
- ActiveRecord::Base.connection.type_to_sql(*args)
- end
-end
diff --git a/activerecord/test/cases/adapters/postgresql/uuid_test.rb b/activerecord/test/cases/adapters/postgresql/uuid_test.rb
index 376dc2490e..5753da1173 100644
--- a/activerecord/test/cases/adapters/postgresql/uuid_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/uuid_test.rb
@@ -1,8 +1,6 @@
# encoding: utf-8
-
require "cases/helper"
-require 'active_record/base'
-require 'active_record/connection_adapters/postgresql_adapter'
+require 'support/schema_dumping_helper'
module PostgresqlUUIDHelper
def connection
@@ -112,6 +110,8 @@ end
class PostgresqlLargeKeysTest < ActiveRecord::TestCase
include PostgresqlUUIDHelper
+ include SchemaDumpingHelper
+
def setup
connection.create_table('big_serials', id: :bigserial) do |t|
t.string 'name'
@@ -119,10 +119,8 @@ class PostgresqlLargeKeysTest < ActiveRecord::TestCase
end
def test_omg
- schema = StringIO.new
- ActiveRecord::SchemaDumper.dump(connection, schema)
- assert_match "create_table \"big_serials\", id: :bigserial, force: true",
- schema.string
+ schema = dump_table_schema "big_serials"
+ assert_match "create_table \"big_serials\", id: :bigserial, force: true", schema
end
def teardown
@@ -132,6 +130,7 @@ end
class PostgresqlUUIDGenerationTest < ActiveRecord::TestCase
include PostgresqlUUIDHelper
+ include SchemaDumpingHelper
class UUID < ActiveRecord::Base
self.table_name = 'pg_uuids'
@@ -191,17 +190,15 @@ class PostgresqlUUIDGenerationTest < ActiveRecord::TestCase
end
def test_schema_dumper_for_uuid_primary_key
- schema = StringIO.new
- ActiveRecord::SchemaDumper.dump(connection, schema)
- assert_match(/\bcreate_table "pg_uuids", id: :uuid, default: "uuid_generate_v1\(\)"/, schema.string)
- assert_match(/t\.uuid "other_uuid", default: "uuid_generate_v4\(\)"/, schema.string)
+ schema = dump_table_schema "pg_uuids"
+ assert_match(/\bcreate_table "pg_uuids", id: :uuid, default: "uuid_generate_v1\(\)"/, schema)
+ assert_match(/t\.uuid "other_uuid", default: "uuid_generate_v4\(\)"/, schema)
end
def test_schema_dumper_for_uuid_primary_key_with_custom_default
- schema = StringIO.new
- ActiveRecord::SchemaDumper.dump(connection, schema)
- assert_match(/\bcreate_table "pg_uuids_2", id: :uuid, default: "my_uuid_generator\(\)"/, schema.string)
- assert_match(/t\.uuid "other_uuid_2", default: "my_uuid_generator\(\)"/, schema.string)
+ schema = dump_table_schema "pg_uuids_2"
+ assert_match(/\bcreate_table "pg_uuids_2", id: :uuid, default: "my_uuid_generator\(\)"/, schema)
+ assert_match(/t\.uuid "other_uuid_2", default: "my_uuid_generator\(\)"/, schema)
end
end
end
diff --git a/activerecord/test/cases/associations/belongs_to_associations_test.rb b/activerecord/test/cases/associations/belongs_to_associations_test.rb
index 25555bd75c..bcd0cf82d5 100644
--- a/activerecord/test/cases/associations/belongs_to_associations_test.rb
+++ b/activerecord/test/cases/associations/belongs_to_associations_test.rb
@@ -57,6 +57,35 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase
end
end
+ def test_default_scope_on_relations_is_not_cached
+ counter = 0
+
+ comments = Class.new(ActiveRecord::Base) {
+ self.table_name = 'comments'
+ self.inheritance_column = 'not_there'
+
+ posts = Class.new(ActiveRecord::Base) {
+ self.table_name = 'posts'
+ self.inheritance_column = 'not_there'
+
+ default_scope -> {
+ counter += 1
+ where("id = :inc", :inc => counter)
+ }
+
+ has_many :comments, :class => comments
+ }
+ belongs_to :post, :class => posts, :inverse_of => false
+ }
+
+ assert_equal 0, counter
+ comment = comments.first
+ assert_equal 0, counter
+ sql = capture_sql { comment.post }
+ comment.reload
+ assert_not_equal sql, capture_sql { comment.post }
+ end
+
def test_proxy_assignment
account = Account.find(1)
assert_nothing_raised { account.firm = account.firm }
diff --git a/activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb b/activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb
index 859310575e..9a57683ee3 100644
--- a/activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb
+++ b/activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb
@@ -1,5 +1,6 @@
require "cases/helper"
require 'models/developer'
+require 'models/computer'
require 'models/project'
require 'models/company'
require 'models/customer'
@@ -80,7 +81,7 @@ end
class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase
fixtures :accounts, :companies, :categories, :posts, :categories_posts, :developers, :projects, :developers_projects,
- :parrots, :pirates, :parrots_pirates, :treasures, :price_estimates, :tags, :taggings
+ :parrots, :pirates, :parrots_pirates, :treasures, :price_estimates, :tags, :taggings, :computers
def setup_data_for_habtm_case
ActiveRecord::Base.connection.execute('delete from countries_treaties')
@@ -883,4 +884,12 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase
child.special_projects << SpecialProject.new("name" => "Special Project")
assert child.save, 'child object should be saved'
end
+
+ def test_habtm_with_reflection_using_class_name_and_fixtures
+ assert_not_nil Developer._reflections['shared_computers']
+ # Checking the fixture for named association is important here, because it's the only way
+ # we've been able to reproduce this bug
+ assert_not_nil File.read(File.expand_path("../../../fixtures/developers.yml", __FILE__)).index("shared_computers")
+ assert_equal developers(:david).shared_computers.first, computers(:laptop)
+ end
end
diff --git a/activerecord/test/cases/associations/has_many_associations_test.rb b/activerecord/test/cases/associations/has_many_associations_test.rb
index e34b993029..69f7bde4bc 100644
--- a/activerecord/test/cases/associations/has_many_associations_test.rb
+++ b/activerecord/test/cases/associations/has_many_associations_test.rb
@@ -76,6 +76,32 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
dev.developer_projects.map(&:project_id).sort
end
+ def test_default_scope_on_relations_is_not_cached
+ counter = 0
+ posts = Class.new(ActiveRecord::Base) {
+ self.table_name = 'posts'
+ self.inheritance_column = 'not_there'
+ post = self
+
+ comments = Class.new(ActiveRecord::Base) {
+ self.table_name = 'comments'
+ self.inheritance_column = 'not_there'
+ belongs_to :post, :class => post
+ default_scope -> {
+ counter += 1
+ where("id = :inc", :inc => counter)
+ }
+ }
+ has_many :comments, :class => comments, :foreign_key => 'post_id'
+ }
+ assert_equal 0, counter
+ post = posts.first
+ assert_equal 0, counter
+ sql = capture_sql { post.comments.to_a }
+ post.comments.reset
+ assert_not_equal sql, capture_sql { post.comments.to_a }
+ end
+
def test_has_many_build_with_options
college = College.create(name: 'UFMT')
Student.create(active: true, college_id: college.id, name: 'Sarah')
@@ -387,6 +413,13 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
assert_equal "Summit", Firm.all.merge!(:order => "id").first.clients_using_primary_key.first.name
end
+ def test_update_all_on_association_accessed_before_save
+ firm = Firm.new(name: 'Firm')
+ firm.clients << Client.first
+ firm.save!
+ assert_equal firm.clients.count, firm.clients.update_all(description: 'Great!')
+ end
+
def test_belongs_to_sanity
c = Client.new
assert_nil c.firm, "belongs_to failed sanity check on new object"
@@ -1895,6 +1928,14 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
assert_equal [bulb1, bulb2], car.all_bulbs.sort_by(&:id)
end
+ test 'unscopes the default scope of associated model when used with include' do
+ car = Car.create!
+ bulb = Bulb.create! name: "other", car: car
+
+ assert_equal bulb, Car.find(car.id).all_bulbs.first
+ assert_equal bulb, Car.includes(:all_bulbs).find(car.id).all_bulbs.first
+ end
+
test "raises RecordNotDestroyed when replaced child can't be destroyed" do
car = Car.create!
original_child = FailedBulb.create!(car: car)
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/readonly_test.rb b/activerecord/test/cases/readonly_test.rb
index 2afd25c989..5b903e4f2c 100644
--- a/activerecord/test/cases/readonly_test.rb
+++ b/activerecord/test/cases/readonly_test.rb
@@ -22,9 +22,15 @@ class ReadOnlyTest < ActiveRecord::TestCase
assert !dev.save
dev.name = 'Forbidden.'
end
- assert_raise(ActiveRecord::ReadOnlyRecord) { dev.save }
- assert_raise(ActiveRecord::ReadOnlyRecord) { dev.save! }
- assert_raise(ActiveRecord::ReadOnlyRecord) { dev.destroy }
+
+ e = assert_raise(ActiveRecord::ReadOnlyRecord) { dev.save }
+ assert_equal "Developer is marked as readonly", e.message
+
+ e = assert_raise(ActiveRecord::ReadOnlyRecord) { dev.save! }
+ assert_equal "Developer is marked as readonly", e.message
+
+ e = assert_raise(ActiveRecord::ReadOnlyRecord) { dev.destroy }
+ assert_equal "Developer is marked as readonly", e.message
end
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/type/string_test.rb b/activerecord/test/cases/type/string_test.rb
index 420177ed49..4d78f287f1 100644
--- a/activerecord/test/cases/type/string_test.rb
+++ b/activerecord/test/cases/type/string_test.rb
@@ -4,8 +4,8 @@ module ActiveRecord
class StringTypeTest < ActiveRecord::TestCase
test "type casting" do
type = Type::String.new
- assert_equal "1", type.type_cast_from_user(true)
- assert_equal "0", type.type_cast_from_user(false)
+ assert_equal "t", type.type_cast_from_user(true)
+ assert_equal "f", type.type_cast_from_user(false)
assert_equal "123", type.type_cast_from_user(123)
end
diff --git a/activerecord/test/cases/validations/uniqueness_validation_test.rb b/activerecord/test/cases/validations/uniqueness_validation_test.rb
index 18221cc73d..c6b58d469d 100644
--- a/activerecord/test/cases/validations/uniqueness_validation_test.rb
+++ b/activerecord/test/cases/validations/uniqueness_validation_test.rb
@@ -41,7 +41,7 @@ class TopicWithUniqEvent < Topic
end
class UniquenessValidationTest < ActiveRecord::TestCase
- fixtures :topics, 'warehouse-things', :developers
+ fixtures :topics, 'warehouse-things'
repair_validations(Topic, Reply)
diff --git a/activerecord/test/config.example.yml b/activerecord/test/config.example.yml
index ce30cff9e7..e3b55d640e 100644
--- a/activerecord/test/config.example.yml
+++ b/activerecord/test/config.example.yml
@@ -69,12 +69,6 @@ connections:
username: rails
encoding: utf8
- openbase:
- arunit:
- username: admin
- arunit2:
- username: admin
-
oracle:
arunit:
adapter: oracle_enhanced
diff --git a/activerecord/test/fixtures/computers.yml b/activerecord/test/fixtures/computers.yml
index 7281a4d768..ad5ae2ec71 100644
--- a/activerecord/test/fixtures/computers.yml
+++ b/activerecord/test/fixtures/computers.yml
@@ -3,3 +3,8 @@ workstation:
system: 'Linux'
developer: 1
extendedWarranty: 1
+
+laptop:
+ system: 'MacOS 1'
+ developer: 1
+ extendedWarranty: 1
diff --git a/activerecord/test/fixtures/developers.yml b/activerecord/test/fixtures/developers.yml
index 1a74563dc6..54b74e7a74 100644
--- a/activerecord/test/fixtures/developers.yml
+++ b/activerecord/test/fixtures/developers.yml
@@ -2,6 +2,7 @@ david:
id: 1
name: David
salary: 80000
+ shared_computers: laptop
jamis:
id: 2
diff --git a/activerecord/test/models/developer.rb b/activerecord/test/models/developer.rb
index 3627cfdd09..d2a5a7fc49 100644
--- a/activerecord/test/models/developer.rb
+++ b/activerecord/test/models/developer.rb
@@ -15,6 +15,8 @@ class Developer < ActiveRecord::Base
accepts_nested_attributes_for :projects
+ has_and_belongs_to_many :shared_computers, class_name: "Computer"
+
has_and_belongs_to_many :projects_extended_by_name,
-> { extending(DeveloperProjectsAssociationExtension) },
:class_name => "Project",
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 539a0d2a49..720a127585 100644
--- a/activerecord/test/schema/schema.rb
+++ b/activerecord/test/schema/schema.rb
@@ -228,6 +228,11 @@ ActiveRecord::Schema.define do
t.integer :extendedWarranty, null: false
end
+ create_table :computers_developers, id: false, force: true do |t|
+ t.references :computer
+ t.references :developer
+ end
+
create_table :contracts, force: true do |t|
t.integer :developer_id
t.integer :company_id
diff --git a/activesupport/CHANGELOG.md b/activesupport/CHANGELOG.md
index 4ad602b066..468b990f39 100644
--- a/activesupport/CHANGELOG.md
+++ b/activesupport/CHANGELOG.md
@@ -1,9 +1,13 @@
-* TimeWithZone#strftime now delegates every directive to Time#strftime except for '%Z',
+* `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.
*Pablo Herrero*
-* Corrected Inflector#underscore handling of multiple successive acroynms.
+* Corrected `Inflector#underscore` handling of multiple successive acroynms.
*James Le Cuirot*
@@ -156,7 +160,7 @@
* Fixed `ActiveSupport::Cache::FileStore` exploding with long paths.
- *Adam Panzer / Michael Grosser*
+ *Adam Panzer*, *Michael Grosser*
* Fixed `ActiveSupport::TimeWithZone#-` so precision is not unnecessarily lost
when working with objects with a nanosecond component.
diff --git a/activesupport/lib/active_support/core_ext/hash/compact.rb b/activesupport/lib/active_support/core_ext/hash/compact.rb
index 6566215a4d..5dc9a05ec7 100644
--- a/activesupport/lib/active_support/core_ext/hash/compact.rb
+++ b/activesupport/lib/active_support/core_ext/hash/compact.rb
@@ -1,6 +1,6 @@
class Hash
# Returns a hash with non +nil+ values.
- #
+ #
# hash = { a: true, b: false, c: nil}
# hash.compact # => { a: true, b: false}
# hash # => { a: true, b: false, c: nil}
@@ -8,9 +8,9 @@ class Hash
def compact
self.select { |_, value| !value.nil? }
end
-
+
# Replaces current hash with non +nil+ values.
- #
+ #
# hash = { a: true, b: false, c: nil}
# hash.compact! # => { a: true, b: false}
# hash # => { a: true, b: false}
diff --git a/activesupport/lib/active_support/core_ext/hash/except.rb b/activesupport/lib/active_support/core_ext/hash/except.rb
index 682d089881..6e397abf51 100644
--- a/activesupport/lib/active_support/core_ext/hash/except.rb
+++ b/activesupport/lib/active_support/core_ext/hash/except.rb
@@ -1,13 +1,19 @@
class Hash
- # Returns a hash that includes everything but the given keys. This is useful for
- # limiting a set of parameters to everything but a few known toggles:
+ # Returns a hash that includes everything but the given keys.
+ # hash = { a: true, b: false, c: nil}
+ # hash.except(:c) # => { a: true, b: false}
+ # hash # => { a: true, b: false, c: nil}
#
+ # This is useful for limiting a set of parameters to everything but a few known toggles:
# @person.update(params[:person].except(:admin))
def except(*keys)
dup.except!(*keys)
end
# Replaces the hash without the given keys.
+ # hash = { a: true, b: false, c: nil}
+ # hash.except!(:c) # => { a: true, b: false}
+ # hash # => { a: true, b: false }
def except!(*keys)
keys.each { |key| delete(key) }
self
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..096292dc58 100644
--- a/activesupport/lib/active_support/core_ext/string/filters.rb
+++ b/activesupport/lib/active_support/core_ext/string/filters.rb
@@ -13,6 +13,9 @@ class String
end
# Performs a destructive squish. See String#squish.
+ # str = " foo bar \n \t boo"
+ # str.squish! # => "foo bar boo"
+ # str # => "foo bar boo"
def squish!
gsub!(/\A[[:space:]]+/, '')
gsub!(/[[:space:]]+\z/, '')
@@ -20,14 +23,24 @@ 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.
+ # str = "foo bar test"
+ # str.remove(" test") # => "foo bar"
+ # str # => "foo bar test"
+ 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.
+ # str = "foo bar test"
+ # str.remove!(" test") # => "foo bar"
+ # str # => "foo bar"
+ 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..0de1d2c7df 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'
@@ -103,6 +102,8 @@ module ActiveSupport
@value.respond_to?(method, include_private)
end
+ delegate :<=>, to: :value
+
protected
def sum(sign, time = ::Time.current) #:nodoc:
diff --git a/activesupport/lib/active_support/notifications.rb b/activesupport/lib/active_support/notifications.rb
index 325a3d75dc..b9f8e1ab2c 100644
--- a/activesupport/lib/active_support/notifications.rb
+++ b/activesupport/lib/active_support/notifications.rb
@@ -16,7 +16,7 @@ module ActiveSupport
# render text: 'Foo'
# end
#
- # That executes the block first and notifies all subscribers once done.
+ # That first executes the block and then notifies all subscribers once done.
#
# In the example above +render+ is the name of the event, and the rest is called
# the _payload_. The payload is a mechanism that allows instrumenters to pass
diff --git a/activesupport/test/core_ext/duration_test.rb b/activesupport/test/core_ext/duration_test.rb
index 5a2af7f943..2b893c7cd0 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
@@ -200,4 +199,16 @@ class DurationTest < ActiveSupport::TestCase
def test_hash
assert_equal 1.minute.hash, 60.seconds.hash
end
+
+ def test_comparable
+ assert_equal(-1, (0.seconds <=> 1.second))
+ assert_equal(-1, (1.second <=> 1.minute))
+ assert_equal(-1, (1 <=> 1.minute))
+ assert_equal(0, (0.seconds <=> 0.seconds))
+ assert_equal(0, (0.seconds <=> 0.minutes))
+ assert_equal(0, (1.second <=> 1.second))
+ assert_equal(1, (1.second <=> 0.second))
+ assert_equal(1, (1.minute <=> 1.second))
+ assert_equal(1, (61 <=> 1.minute))
+ end
end
diff --git a/activesupport/test/core_ext/range_ext_test.rb b/activesupport/test/core_ext/range_ext_test.rb
index 98c4ec6b5e..f096328cee 100644
--- a/activesupport/test/core_ext/range_ext_test.rb
+++ b/activesupport/test/core_ext/range_ext_test.rb
@@ -115,11 +115,11 @@ class RangeTest < ActiveSupport::TestCase
def test_date_time_with_each
datetime = DateTime.now
- assert ((datetime - 1.hour)..datetime).each {}
+ assert(((datetime - 1.hour)..datetime).each {})
end
def test_date_time_with_step
datetime = DateTime.now
- assert ((datetime - 1.hour)..datetime).step(1) {}
+ assert(((datetime - 1.hour)..datetime).step(1) {})
end
end
diff --git a/activesupport/test/core_ext/string_ext_test.rb b/activesupport/test/core_ext/string_ext_test.rb
index 2f4691817f..e32c178951 100644
--- a/activesupport/test/core_ext/string_ext_test.rb
+++ b/activesupport/test/core_ext/string_ext_test.rb
@@ -260,8 +260,24 @@ 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_for_multiple_occurrences
+ original = "This is a good day to die to die"
+ assert_equal "This is a good day", original.remove(" to die")
+ assert_equal "This is a good day to die 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
@@ -404,11 +420,11 @@ class StringConversionsTest < ActiveSupport::TestCase
end
def test_partial_string_to_time
- with_env_tz "Europe/Moscow" do
+ with_env_tz "Europe/Moscow" do # use timezone which does not observe DST.
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/activesupport/test/dependencies_test.rb b/activesupport/test/dependencies_test.rb
index f2f60167c4..67e31fc1e1 100644
--- a/activesupport/test/dependencies_test.rb
+++ b/activesupport/test/dependencies_test.rb
@@ -16,11 +16,16 @@ module ModuleWithConstant
end
class DependenciesTest < ActiveSupport::TestCase
- def teardown
- ActiveSupport::Dependencies.clear
+ include DependenciesTestHelpers
+
+ setup do
+ @loaded_features_copy = $LOADED_FEATURES.dup
end
- include DependenciesTestHelpers
+ teardown do
+ ActiveSupport::Dependencies.clear
+ $LOADED_FEATURES.replace(@loaded_features_copy)
+ end
def test_depend_on_path
skip "LoadError#path does not exist" if RUBY_VERSION < '2.0.0'
@@ -53,8 +58,7 @@ class DependenciesTest < ActiveSupport::TestCase
assert_equal 2, ActiveSupport::Dependencies.loaded.size
end
ensure
- Object.send(:remove_const, :ServiceOne) if Object.const_defined?(:ServiceOne)
- Object.send(:remove_const, :ServiceTwo) if Object.const_defined?(:ServiceTwo)
+ remove_constants(:ServiceOne, :ServiceTwo)
end
def test_tracking_identical_loaded_files
@@ -64,7 +68,7 @@ class DependenciesTest < ActiveSupport::TestCase
assert_equal 1, ActiveSupport::Dependencies.loaded.size
end
ensure
- Object.send(:remove_const, :ServiceOne) if Object.const_defined?(:ServiceOne)
+ remove_constants(:ServiceOne)
end
def test_missing_dependency_raises_missing_source_file
@@ -84,8 +88,8 @@ class DependenciesTest < ActiveSupport::TestCase
assert_equal 'Loading me failed, so do not add to loaded or history.', e.message
assert_equal count + 1, $raises_exception_load_count
- assert !ActiveSupport::Dependencies.loaded.include?(filename)
- assert !ActiveSupport::Dependencies.history.include?(filename)
+ assert_not ActiveSupport::Dependencies.loaded.include?(filename)
+ assert_not ActiveSupport::Dependencies.history.include?(filename)
end
end
end
@@ -93,7 +97,6 @@ class DependenciesTest < ActiveSupport::TestCase
def test_dependency_which_raises_doesnt_blindly_call_blame_file!
with_loading do
filename = 'dependencies/raises_exception_without_blame_file'
-
assert_raises(Exception) { require_dependency filename }
end
end
@@ -101,13 +104,12 @@ class DependenciesTest < ActiveSupport::TestCase
def test_warnings_should_be_enabled_on_first_load
with_loading 'dependencies' do
old_warnings, ActiveSupport::Dependencies.warnings_on_first_load = ActiveSupport::Dependencies.warnings_on_first_load, true
-
filename = "check_warnings"
expanded = File.expand_path("#{File.dirname(__FILE__)}/dependencies/#{filename}")
$check_warnings_load_count = 0
- assert !ActiveSupport::Dependencies.loaded.include?(expanded)
- assert !ActiveSupport::Dependencies.history.include?(expanded)
+ assert_not ActiveSupport::Dependencies.loaded.include?(expanded)
+ assert_not ActiveSupport::Dependencies.history.include?(expanded)
silence_warnings { require_dependency filename }
assert_equal 1, $check_warnings_load_count
@@ -115,7 +117,7 @@ class DependenciesTest < ActiveSupport::TestCase
assert ActiveSupport::Dependencies.loaded.include?(expanded)
ActiveSupport::Dependencies.clear
- assert !ActiveSupport::Dependencies.loaded.include?(expanded)
+ assert_not ActiveSupport::Dependencies.loaded.include?(expanded)
assert ActiveSupport::Dependencies.history.include?(expanded)
silence_warnings { require_dependency filename }
@@ -124,7 +126,7 @@ class DependenciesTest < ActiveSupport::TestCase
assert ActiveSupport::Dependencies.loaded.include?(expanded)
ActiveSupport::Dependencies.clear
- assert !ActiveSupport::Dependencies.loaded.include?(expanded)
+ assert_not ActiveSupport::Dependencies.loaded.include?(expanded)
assert ActiveSupport::Dependencies.history.include?(expanded)
enable_warnings { require_dependency filename }
@@ -203,43 +205,49 @@ class DependenciesTest < ActiveSupport::TestCase
def test_directories_manifest_as_modules_unless_const_defined
with_autoloading_fixtures do
assert_kind_of Module, ModuleFolder
- Object.__send__ :remove_const, :ModuleFolder
end
+ ensure
+ remove_constants(:ModuleFolder)
end
def test_module_with_nested_class
with_autoloading_fixtures do
assert_kind_of Class, ModuleFolder::NestedClass
- Object.__send__ :remove_const, :ModuleFolder
end
+ ensure
+ remove_constants(:ModuleFolder)
end
def test_module_with_nested_inline_class
with_autoloading_fixtures do
assert_kind_of Class, ModuleFolder::InlineClass
- Object.__send__ :remove_const, :ModuleFolder
end
+ ensure
+ remove_constants(:ModuleFolder)
end
def test_directories_may_manifest_as_nested_classes
with_autoloading_fixtures do
assert_kind_of Class, ClassFolder
- Object.__send__ :remove_const, :ClassFolder
end
+ ensure
+ remove_constants(:ClassFolder)
end
def test_class_with_nested_class
with_autoloading_fixtures do
assert_kind_of Class, ClassFolder::NestedClass
- Object.__send__ :remove_const, :ClassFolder
end
+ ensure
+ remove_constants(:ClassFolder)
end
def test_class_with_nested_inline_class
with_autoloading_fixtures do
assert_kind_of Class, ClassFolder::InlineClass
- Object.__send__ :remove_const, :ClassFolder
end
+ ensure
+ remove_constants(:ClassFolder)
end
def test_class_with_nested_inline_subclass_of_parent
@@ -247,8 +255,9 @@ class DependenciesTest < ActiveSupport::TestCase
assert_kind_of Class, ClassFolder::ClassFolderSubclass
assert_kind_of Class, ClassFolder
assert_equal 'indeed', ClassFolder::ClassFolderSubclass::ConstantInClassFolder
- Object.__send__ :remove_const, :ClassFolder
end
+ ensure
+ remove_constants(:ClassFolder)
end
def test_nested_class_can_access_sibling
@@ -256,16 +265,15 @@ class DependenciesTest < ActiveSupport::TestCase
sibling = ModuleFolder::NestedClass.class_eval "NestedSibling"
assert defined?(ModuleFolder::NestedSibling)
assert_equal ModuleFolder::NestedSibling, sibling
- Object.__send__ :remove_const, :ModuleFolder
end
+ ensure
+ remove_constants(:ModuleFolder)
end
def test_doesnt_break_normal_require
path = File.expand_path("../autoloading_fixtures/load_path", __FILE__)
original_path = $:.dup
- original_features = $".dup
$:.push(path)
-
with_autoloading_fixtures do
# The _ = assignments are to prevent warnings
_ = RequiresConstant
@@ -277,15 +285,13 @@ class DependenciesTest < ActiveSupport::TestCase
assert defined?(LoadedConstant)
end
ensure
- remove_constants(:RequiresConstant, :LoadedConstant, :LoadsConstant)
- $".replace(original_features)
+ remove_constants(:RequiresConstant, :LoadedConstant)
$:.replace(original_path)
end
def test_doesnt_break_normal_require_nested
path = File.expand_path("../autoloading_fixtures/load_path", __FILE__)
original_path = $:.dup
- original_features = $".dup
$:.push(path)
with_autoloading_fixtures do
@@ -300,14 +306,12 @@ class DependenciesTest < ActiveSupport::TestCase
end
ensure
remove_constants(:RequiresConstant, :LoadedConstant, :LoadsConstant)
- $".replace(original_features)
$:.replace(original_path)
end
def test_require_returns_true_when_file_not_yet_required
path = File.expand_path("../autoloading_fixtures/load_path", __FILE__)
original_path = $:.dup
- original_features = $".dup
$:.push(path)
with_loading do
@@ -315,14 +319,12 @@ class DependenciesTest < ActiveSupport::TestCase
end
ensure
remove_constants(:LoadedConstant)
- $".replace(original_features)
$:.replace(original_path)
end
def test_require_returns_true_when_file_not_yet_required_even_when_no_new_constants_added
path = File.expand_path("../autoloading_fixtures/load_path", __FILE__)
original_path = $:.dup
- original_features = $".dup
$:.push(path)
with_loading do
@@ -331,14 +333,12 @@ class DependenciesTest < ActiveSupport::TestCase
end
ensure
remove_constants(:LoadedConstant)
- $".replace(original_features)
$:.replace(original_path)
end
def test_require_returns_false_when_file_already_required
path = File.expand_path("../autoloading_fixtures/load_path", __FILE__)
original_path = $:.dup
- original_features = $".dup
$:.push(path)
with_loading do
@@ -347,7 +347,6 @@ class DependenciesTest < ActiveSupport::TestCase
end
ensure
remove_constants(:LoadedConstant)
- $".replace(original_features)
$:.replace(original_path)
end
@@ -355,14 +354,11 @@ class DependenciesTest < ActiveSupport::TestCase
with_loading do
assert_raise(LoadError) { require 'this_file_dont_exist_dude' }
end
- ensure
- remove_constants(:LoadedConstant)
end
def test_load_returns_true_when_file_found
path = File.expand_path("../autoloading_fixtures/load_path", __FILE__)
original_path = $:.dup
- original_features = $".dup
$:.push(path)
with_loading do
@@ -371,7 +367,6 @@ class DependenciesTest < ActiveSupport::TestCase
end
ensure
remove_constants(:LoadedConstant)
- $".replace(original_features)
$:.replace(original_path)
end
@@ -379,17 +374,16 @@ class DependenciesTest < ActiveSupport::TestCase
with_loading do
assert_raise(LoadError) { load 'this_file_dont_exist_dude.rb' }
end
- ensure
- remove_constants(:LoadedConstant)
end
def failing_test_access_thru_and_upwards_fails
with_autoloading_fixtures do
- assert ! defined?(ModuleFolder)
+ assert_not defined?(ModuleFolder)
assert_raise(NameError) { ModuleFolder::Object }
assert_raise(NameError) { ModuleFolder::NestedClass::Object }
- Object.__send__ :remove_const, :ModuleFolder
end
+ ensure
+ remove_constants(:ModuleFolder)
end
def test_non_existing_const_raises_name_error_with_fully_qualified_name
@@ -402,6 +396,8 @@ class DependenciesTest < ActiveSupport::TestCase
assert_equal "uninitialized constant A::B::DoesNotExist", e.message
assert_equal :DoesNotExist, e.name
end
+ ensure
+ remove_constants(:A)
end
def test_smart_name_error_strings
@@ -491,9 +487,9 @@ class DependenciesTest < ActiveSupport::TestCase
nil_name = Module.new
def nil_name.name() nil end
assert !ActiveSupport::Dependencies.autoloaded?(nil_name)
-
- Object.class_eval { remove_const :ModuleFolder }
end
+ ensure
+ remove_constants(:ModuleFolder)
end
def test_qualified_name_for
@@ -551,6 +547,8 @@ class DependenciesTest < ActiveSupport::TestCase
assert_kind_of Module, ::ModuleWithCustomConstMissing::A
assert_kind_of String, ::ModuleWithCustomConstMissing::A::B
end
+ ensure
+ remove_constants(:ModuleWithCustomConstMissing)
end
def test_const_missing_in_anonymous_modules_loads_top_level_constants
@@ -559,6 +557,8 @@ class DependenciesTest < ActiveSupport::TestCase
klass = Class.new.class_eval "E"
assert_equal E, klass
end
+ ensure
+ remove_constants(:E)
end
def test_const_missing_in_anonymous_modules_raises_if_the_constant_belongs_to_Object
@@ -570,18 +570,22 @@ class DependenciesTest < ActiveSupport::TestCase
assert_equal 'E cannot be autoloaded from an anonymous class or module', e.message
assert_equal :E, e.name
end
+ ensure
+ remove_constants(:E)
end
def test_removal_from_tree_should_be_detected
with_loading 'dependencies' do
c = ServiceOne
ActiveSupport::Dependencies.clear
- assert ! defined?(ServiceOne)
+ assert_not defined?(ServiceOne)
e = assert_raise ArgumentError do
ActiveSupport::Dependencies.load_missing_constant(c, :FakeMissing)
end
assert_match %r{ServiceOne has been removed from the module tree}i, e.message
end
+ ensure
+ remove_constants(:ServiceOne)
end
def test_references_should_work
@@ -590,18 +594,21 @@ class DependenciesTest < ActiveSupport::TestCase
service_one_first = ServiceOne
assert_equal service_one_first, c.get("ServiceOne")
ActiveSupport::Dependencies.clear
- assert ! defined?(ServiceOne)
-
+ assert_not defined?(ServiceOne)
service_one_second = ServiceOne
assert_not_equal service_one_first, c.get("ServiceOne")
assert_equal service_one_second, c.get("ServiceOne")
end
+ ensure
+ remove_constants(:ServiceOne)
end
def test_constantize_shortcut_for_cached_constant_lookups
with_loading 'dependencies' do
assert_equal ServiceOne, ActiveSupport::Dependencies.constantize("ServiceOne")
end
+ ensure
+ remove_constants(:ServiceOne)
end
def test_nested_load_error_isnt_rescued
@@ -613,19 +620,20 @@ class DependenciesTest < ActiveSupport::TestCase
end
def test_autoload_once_paths_do_not_add_to_autoloaded_constants
+ old_path = ActiveSupport::Dependencies.autoload_once_paths
with_autoloading_fixtures do
ActiveSupport::Dependencies.autoload_once_paths = ActiveSupport::Dependencies.autoload_paths.dup
- assert ! ActiveSupport::Dependencies.autoloaded?("ModuleFolder")
- assert ! ActiveSupport::Dependencies.autoloaded?("ModuleFolder::NestedClass")
- assert ! ActiveSupport::Dependencies.autoloaded?(ModuleFolder)
+ assert_not ActiveSupport::Dependencies.autoloaded?("ModuleFolder")
+ assert_not ActiveSupport::Dependencies.autoloaded?("ModuleFolder::NestedClass")
+ assert_not ActiveSupport::Dependencies.autoloaded?(ModuleFolder)
1 if ModuleFolder::NestedClass # 1 if to avoid warning
- assert ! ActiveSupport::Dependencies.autoloaded?(ModuleFolder::NestedClass)
+ assert_not ActiveSupport::Dependencies.autoloaded?(ModuleFolder::NestedClass)
end
ensure
- Object.class_eval { remove_const :ModuleFolder }
- ActiveSupport::Dependencies.autoload_once_paths = []
+ remove_constants(:ModuleFolder)
+ ActiveSupport::Dependencies.autoload_once_paths = old_path
end
def test_autoload_once_pathnames_do_not_add_to_autoloaded_constants
@@ -634,15 +642,15 @@ class DependenciesTest < ActiveSupport::TestCase
ActiveSupport::Dependencies.autoload_paths = pathnames
ActiveSupport::Dependencies.autoload_once_paths = pathnames
- assert ! ActiveSupport::Dependencies.autoloaded?("ModuleFolder")
- assert ! ActiveSupport::Dependencies.autoloaded?("ModuleFolder::NestedClass")
- assert ! ActiveSupport::Dependencies.autoloaded?(ModuleFolder)
+ assert_not ActiveSupport::Dependencies.autoloaded?("ModuleFolder")
+ assert_not ActiveSupport::Dependencies.autoloaded?("ModuleFolder::NestedClass")
+ assert_not ActiveSupport::Dependencies.autoloaded?(ModuleFolder)
1 if ModuleFolder::NestedClass # 1 if to avoid warning
- assert ! ActiveSupport::Dependencies.autoloaded?(ModuleFolder::NestedClass)
+ assert_not ActiveSupport::Dependencies.autoloaded?(ModuleFolder::NestedClass)
end
ensure
- Object.class_eval { remove_const :ModuleFolder }
+ remove_constants(:ModuleFolder)
ActiveSupport::Dependencies.autoload_once_paths = []
end
@@ -652,6 +660,8 @@ class DependenciesTest < ActiveSupport::TestCase
assert_equal 10, ApplicationController
assert ActiveSupport::Dependencies.autoloaded?(:ApplicationController)
end
+ ensure
+ remove_constants(:ApplicationController)
end
def test_preexisting_constants_are_not_marked_as_autoloaded
@@ -667,9 +677,8 @@ class DependenciesTest < ActiveSupport::TestCase
assert ! ActiveSupport::Dependencies.autoloaded?(:E), "E shouldn't be marked autoloaded!"
ActiveSupport::Dependencies.clear
end
-
ensure
- Object.class_eval { remove_const :E }
+ remove_constants(:E)
end
def test_constants_in_capitalized_nesting_marked_as_autoloaded
@@ -678,6 +687,8 @@ class DependenciesTest < ActiveSupport::TestCase
assert ActiveSupport::Dependencies.autoloaded?("HTML::SomeClass")
end
+ ensure
+ remove_constants(:HTML)
end
def test_unloadable
@@ -708,7 +719,7 @@ class DependenciesTest < ActiveSupport::TestCase
assert_equal false, M.unloadable
end
ensure
- Object.class_eval { remove_const :M }
+ remove_constants(:M)
end
def test_unloadable_constants_should_receive_callback
@@ -719,7 +730,7 @@ class DependenciesTest < ActiveSupport::TestCase
ActiveSupport::Dependencies.clear
assert !defined?(C)
ensure
- Object.class_eval { remove_const :C } if defined?(C)
+ remove_constants(:C)
end
def test_new_contants_in_without_constants
@@ -733,7 +744,7 @@ class DependenciesTest < ActiveSupport::TestCase
}.map(&:to_s)
assert ActiveSupport::Dependencies.constant_watch_stack.all? {|k,v| v.empty? }
ensure
- Object.class_eval { remove_const :Hello }
+ remove_constants(:Hello)
end
def test_new_constants_in_with_nesting
@@ -750,9 +761,7 @@ class DependenciesTest < ActiveSupport::TestCase
assert_equal ["OuterAfter", "OuterBefore"], outer.sort.map(&:to_s)
assert ActiveSupport::Dependencies.constant_watch_stack.all? {|k,v| v.empty? }
ensure
- %w(OuterBefore Inner OuterAfter).each do |name|
- Object.class_eval { remove_const name if const_defined?(name) }
- end
+ remove_constants(:OuterBefore, :Inner, :OuterAfter)
end
def test_new_constants_in_module
@@ -771,7 +780,7 @@ class DependenciesTest < ActiveSupport::TestCase
assert_equal ["M::OuterAfter", "M::OuterBefore"], outer.sort
assert ActiveSupport::Dependencies.constant_watch_stack.all? {|k,v| v.empty? }
ensure
- Object.class_eval { remove_const :M }
+ remove_constants(:M)
end
def test_new_constants_in_module_using_name
@@ -789,7 +798,7 @@ class DependenciesTest < ActiveSupport::TestCase
assert_equal ["M::OuterAfter", "M::OuterBefore"], outer.sort
assert ActiveSupport::Dependencies.constant_watch_stack.all? {|k,v| v.empty? }
ensure
- Object.class_eval { remove_const :M }
+ remove_constants(:M)
end
def test_new_constants_in_with_inherited_constants
@@ -807,26 +816,27 @@ class DependenciesTest < ActiveSupport::TestCase
def test_file_with_multiple_constants_and_require_dependency
with_autoloading_fixtures do
- assert ! defined?(MultipleConstantFile)
- assert ! defined?(SiblingConstant)
+ assert_not defined?(MultipleConstantFile)
+ assert_not defined?(SiblingConstant)
require_dependency 'multiple_constant_file'
assert defined?(MultipleConstantFile)
assert defined?(SiblingConstant)
assert ActiveSupport::Dependencies.autoloaded?(:MultipleConstantFile)
assert ActiveSupport::Dependencies.autoloaded?(:SiblingConstant)
-
ActiveSupport::Dependencies.clear
- assert ! defined?(MultipleConstantFile)
- assert ! defined?(SiblingConstant)
+ assert_not defined?(MultipleConstantFile)
+ assert_not defined?(SiblingConstant)
end
+ ensure
+ remove_constants(:MultipleConstantFile, :SiblingConstant)
end
def test_file_with_multiple_constants_and_auto_loading
with_autoloading_fixtures do
- assert ! defined?(MultipleConstantFile)
- assert ! defined?(SiblingConstant)
+ assert_not defined?(MultipleConstantFile)
+ assert_not defined?(SiblingConstant)
assert_equal 10, MultipleConstantFile
@@ -837,15 +847,17 @@ class DependenciesTest < ActiveSupport::TestCase
ActiveSupport::Dependencies.clear
- assert ! defined?(MultipleConstantFile)
- assert ! defined?(SiblingConstant)
+ assert_not defined?(MultipleConstantFile)
+ assert_not defined?(SiblingConstant)
end
+ ensure
+ remove_constants(:MultipleConstantFile, :SiblingConstant)
end
def test_nested_file_with_multiple_constants_and_require_dependency
with_autoloading_fixtures do
- assert ! defined?(ClassFolder::NestedClass)
- assert ! defined?(ClassFolder::SiblingClass)
+ assert_not defined?(ClassFolder::NestedClass)
+ assert_not defined?(ClassFolder::SiblingClass)
require_dependency 'class_folder/nested_class'
@@ -856,15 +868,17 @@ class DependenciesTest < ActiveSupport::TestCase
ActiveSupport::Dependencies.clear
- assert ! defined?(ClassFolder::NestedClass)
- assert ! defined?(ClassFolder::SiblingClass)
+ assert_not defined?(ClassFolder::NestedClass)
+ assert_not defined?(ClassFolder::SiblingClass)
end
+ ensure
+ remove_constants(:ClassFolder)
end
def test_nested_file_with_multiple_constants_and_auto_loading
with_autoloading_fixtures do
- assert ! defined?(ClassFolder::NestedClass)
- assert ! defined?(ClassFolder::SiblingClass)
+ assert_not defined?(ClassFolder::NestedClass)
+ assert_not defined?(ClassFolder::SiblingClass)
assert_kind_of Class, ClassFolder::NestedClass
@@ -875,9 +889,11 @@ class DependenciesTest < ActiveSupport::TestCase
ActiveSupport::Dependencies.clear
- assert ! defined?(ClassFolder::NestedClass)
- assert ! defined?(ClassFolder::SiblingClass)
+ assert_not defined?(ClassFolder::NestedClass)
+ assert_not defined?(ClassFolder::SiblingClass)
end
+ ensure
+ remove_constants(:ClassFolder)
end
def test_autoload_doesnt_shadow_no_method_error_with_relative_constant
@@ -888,9 +904,8 @@ class DependenciesTest < ActiveSupport::TestCase
assert !defined?(::RaisesNoMethodError), "::RaisesNoMethodError is defined but it should have failed!"
end
end
-
ensure
- Object.class_eval { remove_const :RaisesNoMethodError if const_defined?(:RaisesNoMethodError) }
+ remove_constants(:RaisesNoMethodError)
end
def test_autoload_doesnt_shadow_no_method_error_with_absolute_constant
@@ -901,9 +916,8 @@ class DependenciesTest < ActiveSupport::TestCase
assert !defined?(::RaisesNoMethodError), "::RaisesNoMethodError is defined but it should have failed!"
end
end
-
ensure
- Object.class_eval { remove_const :RaisesNoMethodError if const_defined?(:RaisesNoMethodError) }
+ remove_constants(:RaisesNoMethodError)
end
def test_autoload_doesnt_shadow_error_when_mechanism_not_set_to_load
@@ -919,7 +933,6 @@ class DependenciesTest < ActiveSupport::TestCase
def test_autoload_doesnt_shadow_name_error
with_autoloading_fixtures do
- Object.send(:remove_const, :RaisesNameError) if defined?(::RaisesNameError)
2.times do
e = assert_raise NameError do
::RaisesNameError::FooBarBaz.object_id
@@ -934,19 +947,20 @@ class DependenciesTest < ActiveSupport::TestCase
assert !defined?(::RaisesNameError), "::RaisesNameError is defined but it should have failed!"
end
end
-
ensure
- Object.class_eval { remove_const :RaisesNoMethodError if const_defined?(:RaisesNoMethodError) }
+ remove_constants(:RaisesNameError)
end
def test_remove_constant_handles_double_colon_at_start
Object.const_set 'DeleteMe', Module.new
DeleteMe.const_set 'OrMe', Module.new
ActiveSupport::Dependencies.remove_constant "::DeleteMe::OrMe"
- assert ! defined?(DeleteMe::OrMe)
+ assert_not defined?(DeleteMe::OrMe)
assert defined?(DeleteMe)
ActiveSupport::Dependencies.remove_constant "::DeleteMe"
- assert ! defined?(DeleteMe)
+ assert_not defined?(DeleteMe)
+ ensure
+ remove_constants(:DeleteMe)
end
def test_remove_constant_does_not_trigger_loading_autoloads
@@ -956,7 +970,9 @@ class DependenciesTest < ActiveSupport::TestCase
end
assert_nil ActiveSupport::Dependencies.remove_constant(constant), "Kernel#autoload has been triggered by remove_constant"
- assert !defined?(ShouldNotBeAutoloaded)
+ assert_not defined?(ShouldNotBeAutoloaded)
+ ensure
+ remove_constants(constant)
end
def test_remove_constant_does_not_autoload_already_removed_parents_as_a_side_effect
@@ -965,11 +981,14 @@ class DependenciesTest < ActiveSupport::TestCase
_ = ::A::B # assignment to silence parse-time warning "possibly useless use of :: in void context"
ActiveSupport::Dependencies.remove_constant('A')
ActiveSupport::Dependencies.remove_constant('A::B')
- assert !defined?(A)
+ assert_not defined?(A)
end
+ ensure
+ remove_constants(:A)
end
def test_load_once_constants_should_not_be_unloaded
+ old_path = ActiveSupport::Dependencies.autoload_once_paths
with_autoloading_fixtures do
ActiveSupport::Dependencies.autoload_once_paths = ActiveSupport::Dependencies.autoload_paths
_ = ::A # assignment to silence parse-time warning "possibly useless use of :: in void context"
@@ -978,8 +997,8 @@ class DependenciesTest < ActiveSupport::TestCase
assert defined?(A)
end
ensure
- ActiveSupport::Dependencies.autoload_once_paths = []
- Object.class_eval { remove_const :A if const_defined?(:A) }
+ ActiveSupport::Dependencies.autoload_once_paths = old_path
+ remove_constants(:A)
end
def test_access_unloaded_constants_for_reload
@@ -991,23 +1010,27 @@ class DependenciesTest < ActiveSupport::TestCase
A::B # Make sure no circular dependency error
end
+ ensure
+ remove_constants(:A)
end
def test_autoload_once_paths_should_behave_when_recursively_loading
+ old_path = ActiveSupport::Dependencies.autoload_once_paths
with_loading 'dependencies', 'autoloading_fixtures' do
ActiveSupport::Dependencies.autoload_once_paths = [ActiveSupport::Dependencies.autoload_paths.last]
- assert !defined?(CrossSiteDependency)
+ assert_not defined?(CrossSiteDependency)
assert_nothing_raised { CrossSiteDepender.nil? }
assert defined?(CrossSiteDependency)
- assert !ActiveSupport::Dependencies.autoloaded?(CrossSiteDependency),
+ assert_not ActiveSupport::Dependencies.autoloaded?(CrossSiteDependency),
"CrossSiteDependency shouldn't be marked as autoloaded!"
ActiveSupport::Dependencies.clear
assert defined?(CrossSiteDependency),
"CrossSiteDependency shouldn't have been unloaded!"
end
ensure
- ActiveSupport::Dependencies.autoload_once_paths = []
+ ActiveSupport::Dependencies.autoload_once_paths = old_path
+ remove_constants(:CrossSiteDependency)
end
def test_hook_called_multiple_times
diff --git a/guides/source/4_1_release_notes.md b/guides/source/4_1_release_notes.md
index 52a5acb75e..c7877a9cb5 100644
--- a/guides/source/4_1_release_notes.md
+++ b/guides/source/4_1_release_notes.md
@@ -136,7 +136,7 @@ end
### Action Mailer Previews
-Action Mailer previews provide a way to visually see how emails look by visiting
+Action Mailer previews provide a way to see how emails look by visiting
a special URL that renders them.
You implement a preview class whose methods return the mail object you'd like
diff --git a/guides/source/4_2_release_notes.md b/guides/source/4_2_release_notes.md
index d9f49aac55..8553cffa9d 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.
@@ -300,6 +300,9 @@ Please refer to the [Changelog][railties] for detailed changes.
### Removals
+* The `--skip-action-view` option has been removed from the
+ app generator. ([Pull Request](https://github.com/rails/rails/pull/17042))
+
* The `rails application` command has been removed without replacement.
([Pull Request](https://github.com/rails/rails/pull/11616))
@@ -358,9 +361,9 @@ Please refer to the [Changelog][railties] for detailed changes.
([Pull Request](https://github.com/rails/rails/pull/16129))
-* Introduced a `--skip-gems` option in the app generator to skip gems such as
- `turbolinks` and `coffee-rails` that do not have their own specific flags.
- ([Commit](https://github.com/rails/rails/commit/10565895805887d4faf004a6f71219da177f78b7))
+* Introduce a `--skip-turbolinks` option in the app generator to not generate
+ any turbolinks integration.
+ ([Commit](https://github.com/rails/rails/commit/bf17c8a531bc8059d50ad731398002a3e7162a7d))
* Introduced a `bin/setup` script to enable automated setup code when
bootstrapping an application.
@@ -471,7 +474,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 +482,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 +540,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
@@ -575,6 +578,10 @@ Please refer to the [Changelog][active-record] for detailed changes.
### Deprecations
+* Deprecated `sanitize_sql_hash_for_conditions` without replacement. Using a
+ `Relation` for performing queries and updates is the prefered API.
+ ([Commit](https://github.com/rails/rails/commit/d5902c9e))
+
* Deprecated swallowing of errors inside `after_commit` and `after_rollback`.
([Pull Request](https://github.com/rails/rails/pull/16537))
@@ -596,7 +603,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 +655,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),
@@ -753,15 +760,15 @@ Please refer to the [Changelog][active-support] for detailed changes.
### Notable changes
-* `Object#try` and `Object#try!` can now be used without an explicit receiver.
- ([Commit](https://github.com/rails/rails/commit/5e51bdda59c9ba8e5faf86294e3e431bd45f1830),
- [Pull Request](https://github.com/rails/rails/pull/17361))
-
* Introduced new configuration option `active_support.test_order` for
specifying the order test cases are executed. This option currently defaults
to `:sorted` but will be changed to `:random` in Rails 5.0.
([Commit](https://github.com/rails/rails/commit/53e877f7d9291b2bf0b8c425f9e32ef35829f35b))
+* `Object#try` and `Object#try!` can now be used without an explicit receiver.
+ ([Commit](https://github.com/rails/rails/commit/5e51bdda59c9ba8e5faf86294e3e431bd45f1830),
+ [Pull Request](https://github.com/rails/rails/pull/17361))
+
* The `travel_to` test helper now truncates the `usec` component to 0.
([Commit](https://github.com/rails/rails/commit/9f6e82ee4783e491c20f5244a613fdeb4024beb5))
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_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/command_line.md b/guides/source/command_line.md
index b9014724bd..e72bc81766 100644
--- a/guides/source/command_line.md
+++ b/guides/source/command_line.md
@@ -61,7 +61,7 @@ With no further work, `rails server` will run our new shiny Rails app:
$ cd commandsapp
$ bin/rails server
=> Booting WEBrick
-=> Rails 4.2.0 application starting in development on http://0.0.0.0:3000
+=> Rails 4.2.0 application starting in development on http://localhost:3000
=> Call with -d to detach
=> Ctrl-C to shutdown server
[2013-08-07 02:00:01] INFO WEBrick 1.3.1
@@ -79,7 +79,7 @@ The server can be run on a different port using the `-p` option. The default dev
$ bin/rails server -e production -p 4000
```
-The `-b` option binds Rails to the specified IP, by default it is 0.0.0.0. You can run a server as a daemon by passing a `-d` option.
+The `-b` option binds Rails to the specified IP, by default it is localhost. You can run a server as a daemon by passing a `-d` option.
### `rails generate`
@@ -368,8 +368,7 @@ Rake is Ruby Make, a standalone Ruby utility that replaces the Unix utility 'mak
You can get a list of Rake tasks available to you, which will often depend on your current directory, by typing `rake --tasks`. Each task has a description, and should help you find the thing you need.
-To get the full backtrace for running rake task you can pass the option
-```--trace``` to command line, for example ```rake db:create --trace```.
+To get the full backtrace for running rake task you can pass the option ```--trace``` to command line, for example ```rake db:create --trace```.
```bash
$ bin/rake --tasks
@@ -394,16 +393,11 @@ INFO: You can also use ```rake -T``` to get the list of tasks.
```bash
$ bin/rake about
About your application's environment
+Rails version 4.2.0
Ruby version 1.9.3 (x86_64-linux)
RubyGems version 1.3.6
Rack version 1.3
-Rails version 4.2.0
JavaScript Runtime Node.js (V8)
-Active Record version 4.2.0
-Action Pack version 4.2.0
-Action View version 4.2.0
-Action Mailer version 4.2.0
-Active Support version 4.2.0
Middleware Rack::Sendfile, ActionDispatch::Static, Rack::Lock, #<ActiveSupport::Cache::Strategy::LocalCache::Middleware:0x007ffd131a7c88>, Rack::Runtime, Rack::MethodOverride, ActionDispatch::RequestId, Rails::Rack::Logger, ActionDispatch::ShowExceptions, ActionDispatch::DebugExceptions, ActionDispatch::RemoteIp, ActionDispatch::Reloader, ActionDispatch::Callbacks, ActiveRecord::Migration::CheckPending, ActiveRecord::ConnectionAdapters::ConnectionManagement, ActiveRecord::QueryCache, ActionDispatch::Cookies, ActionDispatch::Session::CookieStore, ActionDispatch::Flash, ActionDispatch::ParamsParser, Rack::Head, Rack::ConditionalGet, Rack::ETag
Application root /home/foobar/commandsapp
Environment development
@@ -413,10 +407,7 @@ Database schema version 20110805173523
### `assets`
-You can precompile the assets in `app/assets` using `rake assets:precompile`,
-and remove older compiled assets using `rake assets:clean`. The `assets:clean`
-task allows for rolling deploys that may still be linking to an old asset while
-the new assets are being built.
+You can precompile the assets in `app/assets` using `rake assets:precompile`, and remove older compiled assets using `rake assets:clean`. The `assets:clean` task allows for rolling deploys that may still be linking to an old asset while the new assets are being built.
If you want to clear `public/assets` completely, you can use `rake assets:clobber`.
@@ -503,7 +494,7 @@ Rails comes with a test suite called Minitest. Rails owes its stability to the u
### `tmp`
-The `Rails.root/tmp` directory is, like the *nix /tmp directory, the holding place for temporary files like sessions (if you're using a file store for files), process id files, and cached actions.
+The `Rails.root/tmp` directory is, like the *nix /tmp directory, the holding place for temporary files like sessions (if you're using a file store for sessions), process id files, and cached actions.
The `tmp:` namespaced tasks will help you clear and create the `Rails.root/tmp` directory:
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/testing.md b/guides/source/testing.md
index 8ad1eed72c..ea24e8b462 100644
--- a/guides/source/testing.md
+++ b/guides/source/testing.md
@@ -728,7 +728,7 @@ class UserFlowsTest < ActionDispatch::IntegrationTest
https!(false)
get "/articles/all"
assert_response :success
- assert assigns(:products)
+ assert assigns(:articles)
end
end
```
@@ -1045,6 +1045,68 @@ end
Moreover, since the test class extends from `ActionView::TestCase`, you have
access to Rails' helper methods such as `link_to` or `pluralize`.
+Testing Jobs
+------------
+
+Since your custom jobs can be queued at different levels inside your application,
+you'll need to test both jobs themselves (their behavior when they get enqueued)
+and that other entities correctly enqueue them.
+
+### A Basic Test Case
+
+By default, when you generate a job, an associated test will be generated as well
+under the `test/jobs` directory. Here's an example test with a billing job:
+
+```ruby
+require 'test_helper'
+
+class BillingJobTest < ActiveJob::TestCase
+ test 'that account is charged' do
+ BillingJob.perform_now(account, product)
+ assert account.reload.charged_for?(product)
+ end
+end
+```
+
+This test is pretty simple and only asserts that the job get the work done
+as expected.
+
+By default, `ActiveJob::TestCase` will set the queue adapter to `:test` so that
+your jobs are performed inline. It will also ensure that all previously performed
+and enqueued jobs are cleared before any test run so you can safely assume that
+no jobs have already been executed in the scope of each test.
+
+### Custom Assertions And Testing Jobs Inside Other Components
+
+Active Job ships with a bunch of custom assertions that can be used to lessen
+the verbosity of tests:
+
+| Assertion | Purpose |
+| -------------------------------------- | ------- |
+| `assert_enqueued_jobs(number)` | Asserts that the number of enqueued jobs matches the given number. |
+| `assert_performed_jobs(number)` | Asserts that the number of performed jobs matches the given number. |
+| `assert_no_enqueued_jobs { ... }` | Asserts that no jobs have been enqueued. |
+| `assert_no_performed_jobs { ... }` | Asserts that no jobs have been performed. |
+| `assert_enqueued_with([args]) { ... }` | Asserts that the job passed in the block has been enqueued with the given arguments. |
+| `assert_performed_with([args]) { ... }`| Asserts that the job passed in the block has been performed with the given arguments. |
+
+It's a good practice to ensure that your jobs correctly get enqueued or performed
+wherever you invoke them (e.g. inside your controllers). This is precisely where
+the custom assertions provided by Active Job are pretty useful. For instance,
+within a model:
+
+```ruby
+require 'test_helper'
+
+class ProductTest < ActiveSupport::TestCase
+ test 'billing job scheduling' do
+ assert_enqueued_with(job: BillingJob) do
+ product.charge(account)
+ end
+ end
+end
+```
+
Other Testing Approaches
------------------------
diff --git a/guides/source/upgrading_ruby_on_rails.md b/guides/source/upgrading_ruby_on_rails.md
index aac2aef615..25759a0c77 100644
--- a/guides/source/upgrading_ruby_on_rails.md
+++ b/guides/source/upgrading_ruby_on_rails.md
@@ -181,7 +181,7 @@ end
There's a new choice for sanitizing HTML fragments in your applications. The
venerable html-scanner approach is now officially being deprecated in favor of
-[`Rails Html Sanitizer`](https://github.com/rails/rails-html-sanitizer).
+[`Rails HTML Sanitizer`](https://github.com/rails/rails-html-sanitizer).
This means the methods `sanitize`, `sanitize_css`, `strip_tags` and
`strip_links` are backed by a new implementation.
@@ -207,7 +207,7 @@ gem 'rails-deprecated_sanitizer'
```
### Rails DOM Testing
-The [`TagAssertions` module](http://api.rubyonrails.org/classes/ActionDispatch/Assertions/TagAssertions.html) (containing methods such as `assert_tag`), [has been deprecated](https://github.com/rails/rails/blob/6061472b8c310158a2a2e8e9a6b81a1aef6b60fe/actionpack/lib/action_dispatch/testing/assertions/dom.rb) in favor of the `assert_select` methods from the `SelectorAssertions` module, which has been extracted into the [rails-dom-testing gem](https://github.com/rails/rails-dom-testing).
+The [`TagAssertions` module](http://api.rubyonrails.org/classes/ActionDispatch/Assertions/TagAssertions.html) (containing methods such as `assert_tag`), [has been deprecated](https://github.com/rails/rails/blob/6061472b8c310158a2a2e8e9a6b81a1aef6b60fe/actionpack/lib/action_dispatch/testing/assertions/dom.rb) in favor of the `assert_select` methods from the `SelectorAssertions` module, which has been extracted into the [rails-dom-testing gem](https://github.com/rails/rails-dom-testing).
### Masked Authenticity Tokens
diff --git a/railties/CHANGELOG.md b/railties/CHANGELOG.md
index 7b50ffbd76..ca2bd62b43 100644
--- a/railties/CHANGELOG.md
+++ b/railties/CHANGELOG.md
@@ -95,7 +95,7 @@
*Rafael Mendonça França*
-* Add a generic --skip-turbolinks options to generator.
+* Add `--skip-turbolinks` option to the app generator.
*Rafael Mendonça França*
diff --git a/railties/lib/rails/application.rb b/railties/lib/rails/application.rb
index 78b8a90432..ae60337af2 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/code_statistics.rb b/railties/lib/rails/code_statistics.rb
index 0ae6d2a455..27779857b7 100644
--- a/railties/lib/rails/code_statistics.rb
+++ b/railties/lib/rails/code_statistics.rb
@@ -6,6 +6,7 @@ class CodeStatistics #:nodoc:
'Helper tests',
'Model tests',
'Mailer tests',
+ 'Job tests',
'Integration tests',
'Functional tests (old)',
'Unit tests (old)']
diff --git a/railties/lib/rails/commands/destroy.rb b/railties/lib/rails/commands/destroy.rb
index 5479da86a0..ce26cc3fde 100644
--- a/railties/lib/rails/commands/destroy.rb
+++ b/railties/lib/rails/commands/destroy.rb
@@ -1,5 +1,7 @@
require 'rails/generators'
+#if no argument/-h/--help is passed to rails destroy command, then
+#it generates the help associated.
if [nil, "-h", "--help"].include?(ARGV.first)
Rails::Generators.help 'destroy'
exit
diff --git a/railties/lib/rails/commands/generate.rb b/railties/lib/rails/commands/generate.rb
index 351c59c645..926c36b967 100644
--- a/railties/lib/rails/commands/generate.rb
+++ b/railties/lib/rails/commands/generate.rb
@@ -1,5 +1,7 @@
require 'rails/generators'
+#if no argument/-h/--help is passed to rails generate command, then
+#it generates the help associated.
if [nil, "-h", "--help"].include?(ARGV.first)
Rails::Generators.help 'generate'
exit
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/lib/rails/info.rb b/railties/lib/rails/info.rb
index 357aebf584..94ede76932 100644
--- a/railties/lib/rails/info.rb
+++ b/railties/lib/rails/info.rb
@@ -1,6 +1,9 @@
require "cgi"
module Rails
+ # This module helps build the runtime properties used to display in the
+ # Rails::InfoController responses. Including the active Rails version, Ruby
+ # version, Rack version, and so on.
module Info
mattr_accessor :properties
class << (@@properties = [])
diff --git a/railties/lib/rails/source_annotation_extractor.rb b/railties/lib/rails/source_annotation_extractor.rb
index 201532d299..9b058a1848 100644
--- a/railties/lib/rails/source_annotation_extractor.rb
+++ b/railties/lib/rails/source_annotation_extractor.rb
@@ -80,9 +80,8 @@ class SourceAnnotationExtractor
# Returns a hash that maps filenames under +dir+ (recursively) to arrays
# with their annotations. Only files with annotations are included. Files
- # with extension +.builder+, +.rb+, +.erb+, +.haml+, +.slim+, +.css+,
- # +.scss+, +.js+, +.coffee+, +.rake+, +.sass+ and +.less+
- # are taken into account.
+ # with extension +.builder+, +.rb+, +.rake+, +.yml+, +.yaml+, +.ruby+,
+ # +.css+, +.js+ and +.erb+ are taken into account.
def find_in(dir)
results = {}
diff --git a/railties/lib/rails/tasks/statistics.rake b/railties/lib/rails/tasks/statistics.rake
index b94cd244be..4f09ded31d 100644
--- a/railties/lib/rails/tasks/statistics.rake
+++ b/railties/lib/rails/tasks/statistics.rake
@@ -14,10 +14,11 @@ STATS_DIRECTORIES = [
%w(Helper\ tests test/helpers),
%w(Model\ tests test/models),
%w(Mailer\ tests test/mailers),
+ %w(Job\ tests test/jobs),
%w(Integration\ tests test/integration),
%w(Functional\ tests\ (old) test/functional),
%w(Unit\ tests \ (old) test/unit)
-].collect do |name, dir|
+].collect do |name, dir|
[ name, "#{File.dirname(Rake.application.rakefile_location)}/#{dir}" ]
end.select { |name, dir| File.directory?(dir) }
diff --git a/railties/test/application/configuration_test.rb b/railties/test/application/configuration_test.rb
index 98355e273a..55a3456cfc 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