aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Gemfile1
-rw-r--r--RAILS_VERSION2
-rw-r--r--actionmailer/README.rdoc32
-rw-r--r--actionmailer/lib/action_mailer/base.rb7
-rw-r--r--actionmailer/lib/action_mailer/delivery_job.rb2
-rw-r--r--actionmailer/lib/action_mailer/gem_version.rb2
-rw-r--r--actionmailer/lib/action_mailer/message_delivery.rb17
-rw-r--r--actionpack/CHANGELOG.md10
-rw-r--r--actionpack/lib/abstract_controller/helpers.rb12
-rw-r--r--actionpack/lib/action_controller/metal/exceptions.rb2
-rw-r--r--actionpack/lib/action_controller/metal/live.rb2
-rw-r--r--actionpack/lib/action_controller/metal/request_forgery_protection.rb4
-rw-r--r--actionpack/lib/action_controller/metal/strong_parameters.rb11
-rw-r--r--actionpack/lib/action_dispatch/http/parameters.rb2
-rw-r--r--actionpack/lib/action_dispatch/http/request.rb2
-rw-r--r--actionpack/lib/action_dispatch/http/response.rb8
-rw-r--r--actionpack/lib/action_dispatch/middleware/debug_exceptions.rb46
-rw-r--r--actionpack/lib/action_dispatch/middleware/exception_wrapper.rb22
-rw-r--r--actionpack/lib/action_dispatch/middleware/static.rb14
-rw-r--r--actionpack/lib/action_dispatch/middleware/templates/rescues/_source.erb2
-rw-r--r--actionpack/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb2
-rw-r--r--actionpack/lib/action_dispatch/routing/inspector.rb2
-rw-r--r--actionpack/lib/action_dispatch/routing/mapper.rb13
-rw-r--r--actionpack/lib/action_dispatch/routing/route_set.rb36
-rw-r--r--actionpack/lib/action_dispatch/testing/assertions/tag.rb2
-rw-r--r--actionpack/lib/action_pack/gem_version.rb2
-rw-r--r--actionpack/test/controller/helper_test.rb22
-rw-r--r--actionpack/test/controller/mime/respond_to_test.rb4
-rw-r--r--actionpack/test/dispatch/debug_exceptions_test.rb42
-rw-r--r--actionpack/test/dispatch/routing/route_set_test.rb80
-rw-r--r--actionpack/test/dispatch/static_test.rb22
-rw-r--r--actionpack/test/fixtures/helpers_typo/admin/users_helper.rb5
-rw-r--r--actionview/CHANGELOG.md6
-rw-r--r--actionview/lib/action_view/gem_version.rb2
-rw-r--r--actionview/lib/action_view/helpers/form_helper.rb4
-rw-r--r--actionview/lib/action_view/helpers/form_tag_helper.rb12
-rw-r--r--actionview/lib/action_view/helpers/number_helper.rb10
-rw-r--r--actionview/lib/action_view/helpers/sanitize_helper.rb4
-rw-r--r--actionview/lib/action_view/helpers/tag_helper.rb2
-rw-r--r--actionview/lib/action_view/helpers/tags/base.rb2
-rw-r--r--actionview/lib/action_view/renderer/template_renderer.rb2
-rw-r--r--actionview/lib/action_view/template.rb8
-rw-r--r--actionview/lib/action_view/template/handlers/raw.rb2
-rw-r--r--actionview/lib/action_view/template/resolver.rb8
-rw-r--r--actionview/lib/action_view/view_paths.rb6
-rw-r--r--actionview/test/template/form_helper_test.rb14
-rw-r--r--actionview/test/template/form_tag_helper_test.rb6
-rw-r--r--activejob/lib/active_job/callbacks.rb2
-rw-r--r--activejob/lib/active_job/core.rb9
-rw-r--r--activejob/lib/active_job/enqueuing.rb4
-rw-r--r--activejob/lib/active_job/execution.rb1
-rw-r--r--activejob/lib/active_job/gem_version.rb2
-rw-r--r--activejob/lib/active_job/logging.rb2
-rw-r--r--activejob/lib/active_job/queue_adapter.rb3
-rw-r--r--activejob/lib/active_job/queue_adapters.rb2
-rw-r--r--activejob/lib/active_job/queue_adapters/delayed_job_adapter.rb4
-rw-r--r--activejob/lib/active_job/queue_adapters/queue_classic_adapter.rb2
-rw-r--r--activejob/lib/active_job/queue_name.rb6
-rw-r--r--activejob/lib/active_job/test_helper.rb4
-rw-r--r--activejob/test/cases/queue_naming_test.rb19
-rw-r--r--activejob/test/jobs/callback_job.rb29
-rw-r--r--activemodel/lib/active_model/dirty.rb12
-rw-r--r--activemodel/lib/active_model/gem_version.rb2
-rw-r--r--activemodel/lib/active_model/validations.rb2
-rw-r--r--activemodel/lib/active_model/validations/callbacks.rb2
-rw-r--r--activemodel/lib/active_model/validations/format.rb2
-rw-r--r--activemodel/test/cases/validations/validates_test.rb1
-rw-r--r--activerecord/CHANGELOG.md39
-rw-r--r--activerecord/activerecord.gemspec2
-rw-r--r--activerecord/lib/active_record/associations/has_many_through_association.rb17
-rw-r--r--activerecord/lib/active_record/associations/preloader/association.rb5
-rw-r--r--activerecord/lib/active_record/associations/preloader/through_association.rb1
-rw-r--r--activerecord/lib/active_record/attribute_methods.rb11
-rw-r--r--activerecord/lib/active_record/attribute_methods/serialization.rb8
-rw-r--r--activerecord/lib/active_record/attributes.rb23
-rw-r--r--activerecord/lib/active_record/callbacks.rb10
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb14
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/quoting.rb2
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb12
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/schema_dumper.rb2
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb2
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract_adapter.rb11
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb37
-rw-r--r--activerecord/lib/active_record/connection_adapters/column.rb20
-rw-r--r--activerecord/lib/active_record/connection_adapters/connection_specification.rb9
-rw-r--r--activerecord/lib/active_record/connection_adapters/mysql_adapter.rb2
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/database_statements.rb2
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/oid/cidr.rb6
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/oid/range.rb11
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb2
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/quoting.rb2
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb17
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb16
-rw-r--r--activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb2
-rw-r--r--activerecord/lib/active_record/connection_handling.rb2
-rw-r--r--activerecord/lib/active_record/core.rb29
-rw-r--r--activerecord/lib/active_record/fixtures.rb2
-rw-r--r--activerecord/lib/active_record/gem_version.rb2
-rw-r--r--activerecord/lib/active_record/inheritance.rb4
-rw-r--r--activerecord/lib/active_record/migration.rb8
-rw-r--r--activerecord/lib/active_record/model_schema.rb10
-rw-r--r--activerecord/lib/active_record/railties/databases.rake3
-rw-r--r--activerecord/lib/active_record/reflection.rb30
-rw-r--r--activerecord/lib/active_record/relation.rb19
-rw-r--r--activerecord/lib/active_record/relation/calculations.rb1
-rw-r--r--activerecord/lib/active_record/relation/finder_methods.rb26
-rw-r--r--activerecord/lib/active_record/relation/merger.rb28
-rw-r--r--activerecord/lib/active_record/relation/predicate_builder.rb2
-rw-r--r--activerecord/lib/active_record/relation/predicate_builder/array_handler.rb13
-rw-r--r--activerecord/lib/active_record/relation/predicate_builder/relation_handler.rb2
-rw-r--r--activerecord/lib/active_record/relation/query_methods.rb46
-rw-r--r--activerecord/lib/active_record/sanitization.rb5
-rw-r--r--activerecord/lib/active_record/schema_dumper.rb2
-rw-r--r--activerecord/lib/active_record/scoping/named.rb4
-rw-r--r--activerecord/lib/active_record/tasks/database_tasks.rb28
-rw-r--r--activerecord/lib/active_record/tasks/mysql_database_tasks.rb1
-rw-r--r--activerecord/lib/active_record/transactions.rb4
-rw-r--r--activerecord/lib/active_record/type.rb1
-rw-r--r--activerecord/lib/active_record/type/big_integer.rb13
-rw-r--r--activerecord/lib/active_record/type/boolean.rb10
-rw-r--r--activerecord/lib/active_record/type/decimal_without_scale.rb4
-rw-r--r--activerecord/lib/active_record/type/integer.rb25
-rw-r--r--activerecord/test/cases/adapters/postgresql/json_test.rb8
-rw-r--r--activerecord/test/cases/adapters/postgresql/schema_test.rb8
-rw-r--r--activerecord/test/cases/adapters/postgresql/uuid_test.rb20
-rw-r--r--activerecord/test/cases/attributes_test.rb24
-rw-r--r--activerecord/test/cases/base_test.rb10
-rw-r--r--activerecord/test/cases/calculations_test.rb1
-rw-r--r--activerecord/test/cases/connection_adapters/merge_and_resolve_default_url_config_test.rb89
-rw-r--r--activerecord/test/cases/connection_adapters/mysql_type_lookup_test.rb4
-rw-r--r--activerecord/test/cases/finder_test.rb37
-rw-r--r--activerecord/test/cases/helper.rb6
-rw-r--r--activerecord/test/cases/migration/references_index_test.rb4
-rw-r--r--activerecord/test/cases/migration/references_statements_test.rb2
-rw-r--r--activerecord/test/cases/migration_test.rb14
-rw-r--r--activerecord/test/cases/relation/where_chain_test.rb28
-rw-r--r--activerecord/test/cases/relation/where_test.rb1
-rw-r--r--activerecord/test/cases/sanitize_test.rb4
-rw-r--r--activerecord/test/cases/schema_dumper_test.rb7
-rw-r--r--activerecord/test/cases/scoping/named_scoping_test.rb7
-rw-r--r--activerecord/test/cases/serialization_test.rb9
-rw-r--r--activerecord/test/cases/type/integer_test.rb106
-rw-r--r--activerecord/test/cases/types_test.rb47
-rw-r--r--activerecord/test/models/author.rb1
-rw-r--r--activerecord/test/models/post.rb4
-rw-r--r--activerecord/test/schema/postgresql_specific_schema.rb15
-rw-r--r--activerecord/test/schema/schema.rb7
-rw-r--r--activesupport/CHANGELOG.md13
-rw-r--r--activesupport/lib/active_support/callbacks.rb4
-rw-r--r--activesupport/lib/active_support/core_ext/array/access.rb6
-rw-r--r--activesupport/lib/active_support/core_ext/hash/slice.rb10
-rw-r--r--activesupport/lib/active_support/core_ext/kernel/reporting.rb6
-rw-r--r--activesupport/lib/active_support/core_ext/object/try.rb45
-rw-r--r--activesupport/lib/active_support/core_ext/string/filters.rb16
-rw-r--r--activesupport/lib/active_support/core_ext/string/output_safety.rb2
-rw-r--r--activesupport/lib/active_support/dependencies.rb10
-rw-r--r--activesupport/lib/active_support/dependencies/autoload.rb2
-rw-r--r--activesupport/lib/active_support/duration.rb1
-rw-r--r--activesupport/lib/active_support/gem_version.rb2
-rw-r--r--activesupport/lib/active_support/inflector/inflections.rb2
-rw-r--r--activesupport/lib/active_support/inflector/methods.rb4
-rw-r--r--activesupport/lib/active_support/json/encoding.rb2
-rw-r--r--activesupport/lib/active_support/message_verifier.rb14
-rw-r--r--activesupport/lib/active_support/number_helper.rb10
-rw-r--r--activesupport/lib/active_support/number_helper/number_to_currency_converter.rb2
-rw-r--r--activesupport/lib/active_support/number_helper/number_to_percentage_converter.rb2
-rw-r--r--activesupport/lib/active_support/security_utils.rb20
-rw-r--r--activesupport/lib/active_support/test_case.rb2
-rw-r--r--activesupport/lib/active_support/time_with_zone.rb16
-rw-r--r--activesupport/test/autoloading_fixtures/typo.rb2
-rw-r--r--activesupport/test/core_ext/duration_test.rb1
-rw-r--r--activesupport/test/core_ext/object/try_test.rb12
-rw-r--r--activesupport/test/core_ext/string_ext_test.rb18
-rw-r--r--activesupport/test/core_ext/time_with_zone_test.rb5
-rw-r--r--activesupport/test/dependencies_test.rb25
-rw-r--r--activesupport/test/dependencies_test_helpers.rb1
-rw-r--r--activesupport/test/json/encoding_test.rb2
-rw-r--r--activesupport/test/security_utils_test.rb9
-rw-r--r--guides/source/4_2_release_notes.md35
-rw-r--r--guides/source/_welcome.html.erb2
-rw-r--r--guides/source/action_controller_overview.md12
-rw-r--r--guides/source/active_job_basics.md59
-rw-r--r--guides/source/active_record_basics.md2
-rw-r--r--guides/source/active_record_migrations.md2
-rw-r--r--guides/source/active_record_validations.md3
-rw-r--r--guides/source/active_support_core_extensions.md16
-rw-r--r--guides/source/active_support_instrumentation.md12
-rw-r--r--guides/source/asset_pipeline.md4
-rw-r--r--guides/source/command_line.md7
-rw-r--r--guides/source/configuring.md2
-rw-r--r--guides/source/form_helpers.md2
-rw-r--r--guides/source/getting_started.md8
-rw-r--r--guides/source/ruby_on_rails_guides_guidelines.md1
-rw-r--r--guides/source/testing.md6
-rw-r--r--guides/source/upgrading_ruby_on_rails.md17
-rw-r--r--rails.gemspec2
-rw-r--r--railties/CHANGELOG.md8
-rw-r--r--railties/lib/rails/application.rb13
-rw-r--r--railties/lib/rails/code_statistics.rb1
-rw-r--r--railties/lib/rails/engine.rb9
-rw-r--r--railties/lib/rails/gem_version.rb2
-rw-r--r--railties/lib/rails/generators/app_base.rb15
-rw-r--r--railties/lib/rails/generators/rails/app/templates/Gemfile4
-rw-r--r--railties/lib/rails/rack/log_tailer.rb2
-rw-r--r--railties/lib/rails/tasks/statistics.rake3
-rw-r--r--railties/lib/rails/templates/rails/mailers/email.html.erb5
-rw-r--r--railties/test/application/configuration_test.rb14
-rw-r--r--railties/test/application/middleware/exceptions_test.rb15
-rw-r--r--railties/test/application/rake/dbs_test.rb10
-rw-r--r--railties/test/generators/app_generator_test.rb7
-rw-r--r--railties/test/isolation/abstract_unit.rb9
-rw-r--r--tools/README.md4
-rw-r--r--version.rb2
213 files changed, 1674 insertions, 609 deletions
diff --git a/Gemfile b/Gemfile
index 1bc25a2842..931c8e85bc 100644
--- a/Gemfile
+++ b/Gemfile
@@ -14,6 +14,7 @@ gem 'rack-cache', '~> 1.2'
gem 'jquery-rails', '~> 4.0.0.beta2'
gem 'coffee-rails', '~> 4.1.0'
gem 'turbolinks'
+gem 'arel', github: 'rails/arel'
# require: false so bcrypt is loaded only when has_secure_password is used.
# This is to avoid ActiveModel (and by extension the entire framework)
diff --git a/RAILS_VERSION b/RAILS_VERSION
index a771777d25..b86dc8c0c6 100644
--- a/RAILS_VERSION
+++ b/RAILS_VERSION
@@ -1 +1 @@
-4.2.0.beta2
+4.2.0.beta4
diff --git a/actionmailer/README.rdoc b/actionmailer/README.rdoc
index 3b8e3ed749..a4e660d621 100644
--- a/actionmailer/README.rdoc
+++ b/actionmailer/README.rdoc
@@ -61,7 +61,7 @@ generated would look like this:
Thank you for signing up!
-In order to send mails, you simply call the method and then call +deliver+ on the return value.
+In order to send mails, you simply call the method and then call +deliver_now+ on the return value.
Calling the method returns a Mail Message object:
@@ -74,9 +74,17 @@ Or you can just chain the methods together like:
== Setting defaults
-It is possible to set default values that will be used in every method in your Action Mailer class. To implement this functionality, you just call the public class method <tt>default</tt> which you get for free from <tt>ActionMailer::Base</tt>. This method accepts a Hash as the parameter. You can use any of the headers email messages have, like <tt>:from</tt> as the key. You can also pass in a string as the key, like "Content-Type", but Action Mailer does this out of the box for you, so you won't need to worry about that. Finally, it is also possible to pass in a Proc that will get evaluated when it is needed.
+It is possible to set default values that will be used in every method in your
+Action Mailer class. To implement this functionality, you just call the public
+class method +default+ which you get for free from <tt>ActionMailer::Base</tt>.
+This method accepts a Hash as the parameter. You can use any of the headers,
+email messages have, like +:from+ as the key. You can also pass in a string as
+the key, like "Content-Type", but Action Mailer does this out of the box for you,
+so you won't need to worry about that. Finally, it is also possible to pass in a
+Proc that will get evaluated when it is needed.
-Note that every value you set with this method will get overwritten if you use the same key in your mailer method.
+Note that every value you set with this method will get overwritten if you use the
+same key in your mailer method.
Example:
@@ -87,10 +95,11 @@ Example:
== Receiving emails
-To receive emails, you need to implement a public instance method called <tt>receive</tt> that takes an
-email object as its single parameter. The Action Mailer framework has a corresponding class method,
-which is also called <tt>receive</tt>, that accepts a raw, unprocessed email as a string, which it then turns
-into the email object and calls the receive instance method.
+To receive emails, you need to implement a public instance method called
++receive+ that takes an email object as its single parameter. The Action Mailer
+framework has a corresponding class method, which is also called +receive+, that
+accepts a raw, unprocessed email as a string, which it then turns into the email
+object and calls the receive instance method.
Example:
@@ -111,13 +120,14 @@ Example:
end
end
-This Mailman can be the target for Postfix or other MTAs. In Rails, you would use the runner in the
-trivial case like this:
+This Mailman can be the target for Postfix or other MTAs. In Rails, you would use
+the runner in the trivial case like this:
rails runner 'Mailman.receive(STDIN.read)'
-However, invoking Rails in the runner for each mail to be received is very resource intensive. A single
-instance of Rails should be run within a daemon, if it is going to process more than just a limited amount of email.
+However, invoking Rails in the runner for each mail to be received is very
+resource intensive. A single instance of Rails should be run within a daemon, if
+it is going to process more than just a limited amount of email.
== Configuration
diff --git a/actionmailer/lib/action_mailer/base.rb b/actionmailer/lib/action_mailer/base.rb
index 798241aaf8..a70bf1544a 100644
--- a/actionmailer/lib/action_mailer/base.rb
+++ b/actionmailer/lib/action_mailer/base.rb
@@ -84,7 +84,8 @@ module ActionMailer
# name as the method in your mailer model. For example, in the mailer defined above, the template at
# <tt>app/views/notifier/welcome.text.erb</tt> would be used to generate the email.
#
- # Variables defined in the model are accessible as instance variables in the view.
+ # Variables defined in the methods of your mailer model are accessible as instance variables in their
+ # corresponding view.
#
# Emails by default are sent in plain text, so a sample view for our model example might look like this:
#
@@ -702,8 +703,8 @@ module ActionMailer
# The main method that creates the message and renders the email templates. There are
# two ways to call this method, with a block, or without a block.
#
- # Both methods accept a headers hash. This hash allows you to specify the most used headers
- # in an email message, these are:
+ # It accepts a headers hash. This hash allows you to specify
+ # the most used headers in an email message, these are:
#
# * +:subject+ - The subject of the message, if this is omitted, Action Mailer will
# ask the Rails I18n class for a translated +:subject+ in the scope of
diff --git a/actionmailer/lib/action_mailer/delivery_job.rb b/actionmailer/lib/action_mailer/delivery_job.rb
index 622f202695..95231411fb 100644
--- a/actionmailer/lib/action_mailer/delivery_job.rb
+++ b/actionmailer/lib/action_mailer/delivery_job.rb
@@ -1,6 +1,8 @@
require 'active_job'
module ActionMailer
+ # The <tt>ActionMailer::DeliveryJob</tt> class is used when you
+ # want to send emails outside of the request-response cycle.
class DeliveryJob < ActiveJob::Base #:nodoc:
queue_as :mailers
diff --git a/actionmailer/lib/action_mailer/gem_version.rb b/actionmailer/lib/action_mailer/gem_version.rb
index 0c5c55be84..e568b8f6f2 100644
--- a/actionmailer/lib/action_mailer/gem_version.rb
+++ b/actionmailer/lib/action_mailer/gem_version.rb
@@ -8,7 +8,7 @@ module ActionMailer
MAJOR = 4
MINOR = 2
TINY = 0
- PRE = "beta2"
+ PRE = "beta4"
STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".")
end
diff --git a/actionmailer/lib/action_mailer/message_delivery.rb b/actionmailer/lib/action_mailer/message_delivery.rb
index c18e914f37..b5dc2d7497 100644
--- a/actionmailer/lib/action_mailer/message_delivery.rb
+++ b/actionmailer/lib/action_mailer/message_delivery.rb
@@ -1,4 +1,5 @@
require 'delegate'
+require 'active_support/core_ext/string/filters'
module ActionMailer
@@ -85,14 +86,22 @@ module ActionMailer
end
def deliver! #:nodoc:
- ActiveSupport::Deprecation.warn "#deliver! is deprecated and will be removed in Rails 5. " \
- "Use #deliver_now! to deliver immediately or #deliver_later! to deliver through Active Job."
+ ActiveSupport::Deprecation.warn(<<-MSG.squish)
+ `#deliver!` is deprecated and will be removed in Rails 5. Use
+ `#deliver_now!` to deliver immediately or `#deliver_later!` to
+ deliver through Active Job.
+ MSG
+
deliver_now!
end
def deliver #:nodoc:
- ActiveSupport::Deprecation.warn "#deliver is deprecated and will be removed in Rails 5. " \
- "Use #deliver_now to deliver immediately or #deliver_later to deliver through Active Job."
+ ActiveSupport::Deprecation.warn(<<-MSG.squish)
+ `#deliver` is deprecated and will be removed in Rails 5. Use
+ `#deliver_now` to deliver immediately or `#deliver_later` to
+ deliver through Active Job.
+ MSG
+
deliver_now
end
diff --git a/actionpack/CHANGELOG.md b/actionpack/CHANGELOG.md
index 4626c2650a..158b22c0cc 100644
--- a/actionpack/CHANGELOG.md
+++ b/actionpack/CHANGELOG.md
@@ -1,3 +1,13 @@
+* Deprecate the `only_path` option on `*_path` helpers.
+
+ In cases where this option is set to `true`, the option is redundant and can
+ be safely removed; otherwise, the corresponding `*_url` helper should be
+ used instead.
+
+ Fixes #17294.
+
+ *Dan Olson*, *Godfrey Chan*
+
* Improve Journey compliance to RFC 3986.
The scanner in Journey failed to recognize routes that use literals
diff --git a/actionpack/lib/abstract_controller/helpers.rb b/actionpack/lib/abstract_controller/helpers.rb
index 95c67d482b..df7382f02d 100644
--- a/actionpack/lib/abstract_controller/helpers.rb
+++ b/actionpack/lib/abstract_controller/helpers.rb
@@ -150,7 +150,17 @@ module AbstractController
rescue LoadError => e
raise AbstractController::Helpers::MissingHelperError.new(e, file_name)
end
- file_name.camelize.constantize
+
+ mod_name = file_name.camelize
+ begin
+ mod_name.constantize
+ rescue LoadError
+ # dependencies.rb gives a similar error message but its wording is
+ # not as clear because it mentions autoloading. To the user all it
+ # matters is that a helper module couldn't be loaded, autoloading
+ # is an internal mechanism that should not leak.
+ raise NameError, "Couldn't find #{mod_name}, expected it to be defined in helpers/#{file_name}.rb"
+ end
when Module
arg
else
diff --git a/actionpack/lib/action_controller/metal/exceptions.rb b/actionpack/lib/action_controller/metal/exceptions.rb
index 3844dbf2a6..18e003741d 100644
--- a/actionpack/lib/action_controller/metal/exceptions.rb
+++ b/actionpack/lib/action_controller/metal/exceptions.rb
@@ -25,7 +25,7 @@ module ActionController
end
end
- class ActionController::UrlGenerationError < RoutingError #:nodoc:
+ class ActionController::UrlGenerationError < ActionControllerError #:nodoc:
end
class MethodNotAllowed < ActionControllerError #:nodoc:
diff --git a/actionpack/lib/action_controller/metal/live.rb b/actionpack/lib/action_controller/metal/live.rb
index c9ef3a3dad..1e13b3761f 100644
--- a/actionpack/lib/action_controller/metal/live.rb
+++ b/actionpack/lib/action_controller/metal/live.rb
@@ -102,7 +102,7 @@ module ActionController
end
end
- message = json.gsub("\n", "\ndata: ")
+ message = json.gsub(/\n/, "\ndata: ")
@stream.write "data: #{message}\n\n"
end
end
diff --git a/actionpack/lib/action_controller/metal/request_forgery_protection.rb b/actionpack/lib/action_controller/metal/request_forgery_protection.rb
index a4f376816f..fd20682f8f 100644
--- a/actionpack/lib/action_controller/metal/request_forgery_protection.rb
+++ b/actionpack/lib/action_controller/metal/request_forgery_protection.rb
@@ -1,5 +1,6 @@
require 'rack/session/abstract/id'
require 'action_controller/metal/exceptions'
+require 'active_support/security_utils'
module ActionController #:nodoc:
class InvalidAuthenticityToken < ActionControllerError #:nodoc:
@@ -305,8 +306,7 @@ module ActionController #:nodoc:
end
def compare_with_real_token(token, session)
- # Borrow a constant-time comparison from Rack
- Rack::Utils.secure_compare(token, real_csrf_token(session))
+ ActiveSupport::SecurityUtils.secure_compare(token, real_csrf_token(session))
end
def real_csrf_token(session)
diff --git a/actionpack/lib/action_controller/metal/strong_parameters.rb b/actionpack/lib/action_controller/metal/strong_parameters.rb
index 7038f0997f..a5ee1e2159 100644
--- a/actionpack/lib/action_controller/metal/strong_parameters.rb
+++ b/actionpack/lib/action_controller/metal/strong_parameters.rb
@@ -1,5 +1,6 @@
require 'active_support/core_ext/hash/indifferent_access'
require 'active_support/core_ext/array/wrap'
+require 'active_support/core_ext/string/filters'
require 'active_support/deprecation'
require 'active_support/rescuable'
require 'action_dispatch/http/upload'
@@ -114,10 +115,12 @@ module ActionController
def self.const_missing(const_name)
super unless const_name == :NEVER_UNPERMITTED_PARAMS
- ActiveSupport::Deprecation.warn "`ActionController::Parameters::NEVER_UNPERMITTED_PARAMS`"\
- " has been deprecated. Use "\
- "`ActionController::Parameters.always_permitted_parameters` instead."
- self.always_permitted_parameters
+ ActiveSupport::Deprecation.warn(<<-MSG.squish)
+ `ActionController::Parameters::NEVER_UNPERMITTED_PARAMS` has been deprecated.
+ Use `ActionController::Parameters.always_permitted_parameters` instead.
+ MSG
+
+ always_permitted_parameters
end
# Returns a new instance of <tt>ActionController::Parameters</tt>.
diff --git a/actionpack/lib/action_dispatch/http/parameters.rb b/actionpack/lib/action_dispatch/http/parameters.rb
index 20ae48d458..a5cd26a3c1 100644
--- a/actionpack/lib/action_dispatch/http/parameters.rb
+++ b/actionpack/lib/action_dispatch/http/parameters.rb
@@ -27,7 +27,7 @@ module ActionDispatch
def symbolized_path_parameters
ActiveSupport::Deprecation.warn(
- "`symbolized_path_parameters` is deprecated. Please use `path_parameters`"
+ '`symbolized_path_parameters` is deprecated. Please use `path_parameters`.'
)
path_parameters
end
diff --git a/actionpack/lib/action_dispatch/http/request.rb b/actionpack/lib/action_dispatch/http/request.rb
index a8785ee6bf..2a7bb374a5 100644
--- a/actionpack/lib/action_dispatch/http/request.rb
+++ b/actionpack/lib/action_dispatch/http/request.rb
@@ -328,7 +328,7 @@ module ActionDispatch
# Extracted into ActionDispatch::Request::Utils.deep_munge, but kept here for backwards compatibility.
def deep_munge(hash)
ActiveSupport::Deprecation.warn(
- "This method has been extracted into ActionDispatch::Request::Utils.deep_munge. Please start using that instead."
+ 'This method has been extracted into `ActionDispatch::Request::Utils.deep_munge`. Please start using that instead.'
)
Utils.deep_munge(hash)
diff --git a/actionpack/lib/action_dispatch/http/response.rb b/actionpack/lib/action_dispatch/http/response.rb
index 99d46af953..33de2f8b5f 100644
--- a/actionpack/lib/action_dispatch/http/response.rb
+++ b/actionpack/lib/action_dispatch/http/response.rb
@@ -1,4 +1,5 @@
require 'active_support/core_ext/module/attribute_accessors'
+require 'active_support/core_ext/string/filters'
require 'active_support/deprecation'
require 'action_dispatch/http/filter_redirect'
require 'monitor'
@@ -288,7 +289,12 @@ module ActionDispatch # :nodoc:
# as arrays work, and "flattening" responses, cascading to the rack body!
# Not sensible behavior.
def to_ary
- ActiveSupport::Deprecation.warn 'ActionDispatch::Response#to_ary no longer performs implicit conversion to an Array. Please use response.to_a instead, or a splat like `status, headers, body = *response`'
+ ActiveSupport::Deprecation.warn(<<-MSG.squish)
+ `ActionDispatch::Response#to_ary` no longer performs implicit conversion
+ to an array. Please use `response.to_a` instead, or a splat like `status,
+ headers, body = *response`.
+ MSG
+
to_a
end
diff --git a/actionpack/lib/action_dispatch/middleware/debug_exceptions.rb b/actionpack/lib/action_dispatch/middleware/debug_exceptions.rb
index 274f6f2f22..798c087d64 100644
--- a/actionpack/lib/action_dispatch/middleware/debug_exceptions.rb
+++ b/actionpack/lib/action_dispatch/middleware/debug_exceptions.rb
@@ -35,10 +35,23 @@ module ActionDispatch
if env['action_dispatch.show_detailed_exceptions']
request = Request.new(env)
+ traces = wrapper.traces
+
+ trace_to_show = 'Application Trace'
+ if traces[trace_to_show].empty?
+ trace_to_show = 'Full Trace'
+ end
+
+ if source_to_show = traces[trace_to_show].first
+ source_to_show_id = source_to_show[:id]
+ end
+
template = ActionView::Base.new([RESCUES_TEMPLATE_PATH],
request: request,
exception: wrapper.exception,
- traces: traces_from_wrapper(wrapper),
+ traces: traces,
+ show_source_idx: source_to_show_id,
+ trace_to_show: trace_to_show,
routes_inspector: routes_inspector(exception),
source_extract: wrapper.source_extract,
line_number: wrapper.line_number,
@@ -93,36 +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
-
- if application_trace && framework_trace
- id_counter = 0
-
- application_trace = application_trace.map do |trace|
- prev = id_counter
- id_counter += 1
- { id: prev, trace: trace }
- end
-
- framework_trace = framework_trace.map do |trace|
- prev = id_counter
- id_counter += 1
- { id: prev, trace: trace }
- end
-
- full_trace = application_trace + framework_trace
- end
-
- {
- "Application Trace" => application_trace,
- "Framework Trace" => framework_trace,
- "Full Trace" => full_trace
- }
- 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/middleware/static.rb b/actionpack/lib/action_dispatch/middleware/static.rb
index e66c21ef85..002bf8b11a 100644
--- a/actionpack/lib/action_dispatch/middleware/static.rb
+++ b/actionpack/lib/action_dispatch/middleware/static.rb
@@ -24,9 +24,19 @@ module ActionDispatch
path = URI.parser.unescape(path)
return false unless path.valid_encoding?
- paths = [path, "#{path}#{ext}", "#{path}/index#{ext}"]
+ paths = [path, "#{path}#{ext}", "#{path}/index#{ext}"].map { |v|
+ Rack::Utils.clean_path_info v
+ }
- if match = paths.detect {|p| File.file?(File.join(@root, p)) }
+ if match = paths.detect { |p|
+ path = File.join(@root, p)
+ begin
+ File.file?(path) && File.readable?(path)
+ rescue SystemCallError
+ false
+ end
+
+ }
return ::Rack::Utils.escape(match)
end
end
diff --git a/actionpack/lib/action_dispatch/middleware/templates/rescues/_source.erb b/actionpack/lib/action_dispatch/middleware/templates/rescues/_source.erb
index ba29e26930..eabac3a9d2 100644
--- a/actionpack/lib/action_dispatch/middleware/templates/rescues/_source.erb
+++ b/actionpack/lib/action_dispatch/middleware/templates/rescues/_source.erb
@@ -1,7 +1,7 @@
<% if @source_extract %>
<% @source_extract.each_with_index do |extract_source, index| %>
<% if extract_source[:code] %>
- <div class="source <%="hidden" if index != 0%>" id="frame-source-<%=index%>">
+ <div class="source <%="hidden" if @show_source_idx != index%>" id="frame-source-<%=index%>">
<div class="info">
Extracted source (around line <strong>#<%= extract_source[:line_number] %></strong>):
</div>
diff --git a/actionpack/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb b/actionpack/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb
index f62caf51d7..ab57b11c7d 100644
--- a/actionpack/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb
+++ b/actionpack/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb
@@ -12,7 +12,7 @@
<% end %>
<% @traces.each do |name, trace| %>
- <div id="<%= name.gsub(/\s/, '-') %>" style="display: <%= (name == "Application Trace") ? 'block' : 'none' %>;">
+ <div id="<%= name.gsub(/\s/, '-') %>" style="display: <%= (name == @trace_to_show) ? 'block' : 'none' %>;">
<pre><code><% trace.each do |frame| %><a class="trace-frames" data-frame-id="<%= frame[:id] %>" href="#"><%= frame[:trace] %></a><br><% end %></code></pre>
</div>
<% end %>
diff --git a/actionpack/lib/action_dispatch/routing/inspector.rb b/actionpack/lib/action_dispatch/routing/inspector.rb
index ea3b2f419d..cfe2237512 100644
--- a/actionpack/lib/action_dispatch/routing/inspector.rb
+++ b/actionpack/lib/action_dispatch/routing/inspector.rb
@@ -48,7 +48,7 @@ module ActionDispatch
def reqs
@reqs ||= begin
reqs = endpoint
- reqs += " #{constraints.to_s}" unless constraints.empty?
+ reqs += " #{constraints}" unless constraints.empty?
reqs
end
end
diff --git a/actionpack/lib/action_dispatch/routing/mapper.rb b/actionpack/lib/action_dispatch/routing/mapper.rb
index a121fef663..ac03ecb2c8 100644
--- a/actionpack/lib/action_dispatch/routing/mapper.rb
+++ b/actionpack/lib/action_dispatch/routing/mapper.rb
@@ -4,6 +4,7 @@ require 'active_support/core_ext/hash/slice'
require 'active_support/core_ext/enumerable'
require 'active_support/core_ext/array/extract_options'
require 'active_support/core_ext/module/remove_method'
+require 'active_support/core_ext/string/filters'
require 'active_support/inflector'
require 'action_dispatch/routing/redirection'
require 'action_dispatch/routing/endpoint'
@@ -282,11 +283,19 @@ module ActionDispatch
def split_to(to)
case to
when Symbol
- ActiveSupport::Deprecation.warn "defining a route where `to` is a symbol is deprecated. Please change \"to: :#{to}\" to \"action: :#{to}\""
+ ActiveSupport::Deprecation.warn(<<-MSG.squish)
+ Defining a route where `to` is a symbol is deprecated.
+ Please change `to: :#{to}` to `action: :#{to}`.
+ MSG
+
[nil, to.to_s]
when /#/ then to.split('#')
when String
- ActiveSupport::Deprecation.warn "defining a route where `to` is a controller without an action is deprecated. Please change \"to: :#{to}\" to \"controller: :#{to}\""
+ ActiveSupport::Deprecation.warn(<<-MSG.squish)
+ Defining a route where `to` is a controller without an action is deprecated.
+ Please change `to: :#{to}` to `controller: :#{to}`.
+ MSG
+
[to, nil]
else
[]
diff --git a/actionpack/lib/action_dispatch/routing/route_set.rb b/actionpack/lib/action_dispatch/routing/route_set.rb
index f51bee3b31..a641ea3ea9 100644
--- a/actionpack/lib/action_dispatch/routing/route_set.rb
+++ b/actionpack/lib/action_dispatch/routing/route_set.rb
@@ -6,6 +6,7 @@ require 'active_support/core_ext/object/to_query'
require 'active_support/core_ext/hash/slice'
require 'active_support/core_ext/module/remove_method'
require 'active_support/core_ext/array/extract_options'
+require 'active_support/core_ext/string/filters'
require 'action_controller/metal/exceptions'
require 'action_dispatch/http/request'
require 'action_dispatch/routing/endpoint'
@@ -102,7 +103,10 @@ module ActionDispatch
end
def helpers
- ActiveSupport::Deprecation.warn("`named_routes.helpers` is deprecated, please use `route_defined?(route_name)` to see if a named route was defined.")
+ ActiveSupport::Deprecation.warn(<<-MSG.squish)
+ `named_routes.helpers` is deprecated, please use `route_defined?(route_name)`
+ to see if a named route was defined.
+ MSG
@path_helpers + @url_helpers
end
@@ -134,8 +138,8 @@ module ActionDispatch
@url_helpers_module.send :undef_method, url_name
end
routes[key] = route
- define_url_helper @path_helpers_module, route, path_name, route.defaults, name, PATH
- define_url_helper @url_helpers_module, route, url_name, route.defaults, name, FULL
+ define_url_helper @path_helpers_module, route, path_name, route.defaults, name, LEGACY
+ define_url_helper @url_helpers_module, route, url_name, route.defaults, name, UNKNOWN
@path_helpers << path_name
@url_helpers << url_name
@@ -322,6 +326,32 @@ module ActionDispatch
PATH = ->(options) { ActionDispatch::Http::URL.path_for(options) }
FULL = ->(options) { ActionDispatch::Http::URL.full_url_for(options) }
UNKNOWN = ->(options) { ActionDispatch::Http::URL.url_for(options) }
+ LEGACY = ->(options) {
+ if options.key?(:only_path)
+ if options[:only_path]
+ ActiveSupport::Deprecation.warn(<<-MSG.squish)
+ You are calling a `*_path` helper with the `only_path` option
+ explicitly set to `true`. This option will stop working on
+ path helpers in Rails 5. Simply remove the `only_path: true`
+ argument from your call as it is redundant when applied to a
+ path helper.
+ MSG
+
+ PATH.call(options)
+ else
+ ActiveSupport::Deprecation.warn(<<-MSG.squish)
+ You are calling a `*_path` helper with the `only_path` option
+ explicitly set to `false`. This option will stop working on
+ path helpers in Rails 5. Use the corresponding `*_url` helper
+ instead.
+ MSG
+
+ FULL.call(options)
+ end
+ else
+ PATH.call(options)
+ end
+ }
# :startdoc:
attr_accessor :formatter, :set, :named_routes, :default_scope, :router
diff --git a/actionpack/lib/action_dispatch/testing/assertions/tag.rb b/actionpack/lib/action_dispatch/testing/assertions/tag.rb
index 5c2905d1ac..da98b1d6ce 100644
--- a/actionpack/lib/action_dispatch/testing/assertions/tag.rb
+++ b/actionpack/lib/action_dispatch/testing/assertions/tag.rb
@@ -1,3 +1,3 @@
require 'active_support/deprecation'
-ActiveSupport::Deprecation.warn("ActionDispatch::Assertions::TagAssertions has been extracted to the rails-dom-testing gem.")
+ActiveSupport::Deprecation.warn('`ActionDispatch::Assertions::TagAssertions` has been extracted to the rails-dom-testing gem.')
diff --git a/actionpack/lib/action_pack/gem_version.rb b/actionpack/lib/action_pack/gem_version.rb
index 6834845d4f..9b3ea30f69 100644
--- a/actionpack/lib/action_pack/gem_version.rb
+++ b/actionpack/lib/action_pack/gem_version.rb
@@ -8,7 +8,7 @@ module ActionPack
MAJOR = 4
MINOR = 2
TINY = 0
- PRE = "beta2"
+ PRE = "beta4"
STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".")
end
diff --git a/actionpack/test/controller/helper_test.rb b/actionpack/test/controller/helper_test.rb
index 20f99f19ee..936b8c2450 100644
--- a/actionpack/test/controller/helper_test.rb
+++ b/actionpack/test/controller/helper_test.rb
@@ -60,6 +60,12 @@ class HelpersPathsController < ActionController::Base
end
end
+class HelpersTypoController < ActionController::Base
+ path = File.expand_path('../../fixtures/helpers_typo', __FILE__)
+ $:.unshift(path)
+ self.helpers_path = path
+end
+
module LocalAbcHelper
def a() end
def b() end
@@ -82,6 +88,22 @@ class HelperPathsTest < ActiveSupport::TestCase
end
end
+class HelpersTypoControllerTest < ActiveSupport::TestCase
+ def setup
+ @autoload_paths = ActiveSupport::Dependencies.autoload_paths
+ ActiveSupport::Dependencies.autoload_paths = Array(HelpersTypoController.helpers_path)
+ end
+
+ def test_helper_typo_error_message
+ e = assert_raise(NameError) { HelpersTypoController.helper 'admin/users' }
+ assert_equal "Couldn't find Admin::UsersHelper, expected it to be defined in helpers/admin/users_helper.rb", e.message
+ end
+
+ def teardown
+ ActiveSupport::Dependencies.autoload_paths = @autoload_paths
+ end
+end
+
class HelperTest < ActiveSupport::TestCase
class TestController < ActionController::Base
attr_accessor :delegate_attr
diff --git a/actionpack/test/controller/mime/respond_to_test.rb b/actionpack/test/controller/mime/respond_to_test.rb
index 1bc7ad3015..66d2fd7716 100644
--- a/actionpack/test/controller/mime/respond_to_test.rb
+++ b/actionpack/test/controller/mime/respond_to_test.rb
@@ -579,10 +579,10 @@ class RespondToControllerTest < ActionController::TestCase
end
get :using_defaults
- assert_equal "using_defaults - #{[:html].to_s}", @response.body
+ assert_equal "using_defaults - #{[:html]}", @response.body
get :using_defaults, :format => "xml"
- assert_equal "using_defaults - #{[:xml].to_s}", @response.body
+ assert_equal "using_defaults - #{[:xml]}", @response.body
end
def test_format_with_custom_response_type
diff --git a/actionpack/test/dispatch/debug_exceptions_test.rb b/actionpack/test/dispatch/debug_exceptions_test.rb
index 0add9fa3b0..f8851f0152 100644
--- a/actionpack/test/dispatch/debug_exceptions_test.rb
+++ b/actionpack/test/dispatch/debug_exceptions_test.rb
@@ -19,6 +19,10 @@ class DebugExceptionsTest < ActionDispatch::IntegrationTest
@closed = true
end
+ def method_that_raises
+ raise StandardError.new 'error in framework'
+ end
+
def call(env)
env['action_dispatch.show_detailed_exceptions'] = @detailed
req = ActionDispatch::Request.new(env)
@@ -57,7 +61,8 @@ class DebugExceptionsTest < ActionDispatch::IntegrationTest
{})
raise ActionView::Template::Error.new(template, e)
end
-
+ when "/framework_raises"
+ method_that_raises
else
raise "puke!"
end
@@ -280,4 +285,39 @@ class DebugExceptionsTest < ActionDispatch::IntegrationTest
assert_select 'pre code', /\(eval\):1: syntax error, unexpected/
end
end
+
+ test 'debug exceptions app shows user code that caused the error in source view' do
+ @app = DevelopmentApp
+ Rails.stubs(:root).returns(Pathname.new('.'))
+ cleaner = ActiveSupport::BacktraceCleaner.new.tap do |bc|
+ bc.add_silencer { |line| line =~ /method_that_raises/ }
+ bc.add_silencer { |line| line !~ %r{test/dispatch/debug_exceptions_test.rb} }
+ end
+
+ get '/framework_raises', {}, {'action_dispatch.backtrace_cleaner' => cleaner}
+
+ # Assert correct error
+ assert_response 500
+ assert_select 'h2', /error in framework/
+
+ # assert source view line is the call to method_that_raises
+ assert_select 'div.source:not(.hidden)' do
+ assert_select 'pre .line.active', /method_that_raises/
+ end
+
+ # assert first source view (hidden) that throws the error
+ assert_select 'div.source:first' do
+ assert_select 'pre .line.active', /raise StandardError\.new/
+ end
+
+ # assert application trace refers to line that calls method_that_raises is first
+ assert_select '#Application-Trace' do
+ assert_select 'pre code a:first', %r{test/dispatch/debug_exceptions_test\.rb:\d+:in `call}
+ end
+
+ # assert framework trace that that threw the error is first
+ assert_select '#Framework-Trace' do
+ assert_select 'pre code a:first', /method_that_raises/
+ end
+ end
end
diff --git a/actionpack/test/dispatch/routing/route_set_test.rb b/actionpack/test/dispatch/routing/route_set_test.rb
index c465d56bde..a7acc0de41 100644
--- a/actionpack/test/dispatch/routing/route_set_test.rb
+++ b/actionpack/test/dispatch/routing/route_set_test.rb
@@ -69,6 +69,86 @@ module ActionDispatch
end
end
+ test "only_path: true with *_url and no :host option" do
+ draw do
+ get 'foo', to: SimpleApp.new('foo#index')
+ end
+
+ assert_equal '/foo', url_helpers.foo_url(only_path: true)
+ end
+
+ test "only_path: false with *_url and no :host option" do
+ draw do
+ get 'foo', to: SimpleApp.new('foo#index')
+ end
+
+ assert_raises ArgumentError do
+ assert_equal 'http://example.com/foo', url_helpers.foo_url(only_path: false)
+ end
+ end
+
+ test "only_path: false with *_url and local :host option" do
+ draw do
+ get 'foo', to: SimpleApp.new('foo#index')
+ end
+
+ assert_equal 'http://example.com/foo', url_helpers.foo_url(only_path: false, host: 'example.com')
+ end
+
+ test "only_path: false with *_url and global :host option" do
+ @set.default_url_options = { host: 'example.com' }
+
+ draw do
+ get 'foo', to: SimpleApp.new('foo#index')
+ end
+
+ assert_equal 'http://example.com/foo', url_helpers.foo_url(only_path: false)
+ end
+
+ test "only_path: true with *_path" do
+ draw do
+ get 'foo', to: SimpleApp.new('foo#index')
+ end
+
+ assert_deprecated do
+ assert_equal '/foo', url_helpers.foo_path(only_path: true)
+ end
+ end
+
+ test "only_path: false with *_path with global :host option" do
+ @set.default_url_options = { host: 'example.com' }
+
+ draw do
+ get 'foo', to: SimpleApp.new('foo#index')
+ end
+
+ assert_deprecated do
+ assert_equal 'http://example.com/foo', url_helpers.foo_path(only_path: false)
+ end
+ end
+
+ test "only_path: false with *_path with local :host option" do
+ draw do
+ get 'foo', to: SimpleApp.new('foo#index')
+ end
+
+ assert_deprecated do
+ assert_equal 'http://example.com/foo', url_helpers.foo_path(only_path: false, host: 'example.com')
+ end
+ end
+
+ test "only_path: false with *_path with no :host option" do
+ draw do
+ get 'foo', to: SimpleApp.new('foo#index')
+ end
+
+ assert_deprecated do
+ assert_raises ArgumentError do
+ assert_equal 'http://example.com/foo', url_helpers.foo_path(only_path: false)
+ end
+ end
+ end
+
test "explicit keys win over implicit keys" do
draw do
resources :foo do
diff --git a/actionpack/test/dispatch/static_test.rb b/actionpack/test/dispatch/static_test.rb
index 6f7373201c..7f1207eaed 100644
--- a/actionpack/test/dispatch/static_test.rb
+++ b/actionpack/test/dispatch/static_test.rb
@@ -200,7 +200,8 @@ class StaticTest < ActiveSupport::TestCase
}
def setup
- @app = ActionDispatch::Static.new(DummyApp, "#{FIXTURE_LOAD_PATH}/public", "public, max-age=60")
+ @root = "#{FIXTURE_LOAD_PATH}/public"
+ @app = ActionDispatch::Static.new(DummyApp, @root, "public, max-age=60")
end
def public_path
@@ -208,11 +209,28 @@ class StaticTest < ActiveSupport::TestCase
end
include StaticTests
+
+ def test_custom_handler_called_when_file_is_outside_root
+ filename = 'shared.html.erb'
+ assert File.exist?(File.join(@root, '..', filename))
+ env = {
+ "REQUEST_METHOD"=>"GET",
+ "REQUEST_PATH"=>"/..%2F#{filename}",
+ "PATH_INFO"=>"/..%2F#{filename}",
+ "REQUEST_URI"=>"/..%2F#{filename}",
+ "HTTP_VERSION"=>"HTTP/1.1",
+ "SERVER_NAME"=>"localhost",
+ "SERVER_PORT"=>"8080",
+ "QUERY_STRING"=>""
+ }
+ assert_equal(DummyApp.call(nil), @app.call(env))
+ end
end
class StaticEncodingTest < StaticTest
def setup
- @app = ActionDispatch::Static.new(DummyApp, "#{FIXTURE_LOAD_PATH}/公共", "public, max-age=60")
+ @root = "#{FIXTURE_LOAD_PATH}/公共"
+ @app = ActionDispatch::Static.new(DummyApp, @root, "public, max-age=60")
end
def public_path
diff --git a/actionpack/test/fixtures/helpers_typo/admin/users_helper.rb b/actionpack/test/fixtures/helpers_typo/admin/users_helper.rb
new file mode 100644
index 0000000000..7d2326e04d
--- /dev/null
+++ b/actionpack/test/fixtures/helpers_typo/admin/users_helper.rb
@@ -0,0 +1,5 @@
+module Admin
+ module UsersHelpeR
+ end
+end
+
diff --git a/actionview/CHANGELOG.md b/actionview/CHANGELOG.md
index 8ac74dc938..e388e6ecd3 100644
--- a/actionview/CHANGELOG.md
+++ b/actionview/CHANGELOG.md
@@ -1,3 +1,9 @@
+* Update `select_tag` to work correctly with `:include_blank` option passing a string.
+
+ Fixes #16483.
+
+ *Frank Groeneveld*
+
* Changed the meaning of `render "foo/bar"`.
Previously, calling `render "foo/bar"` in a controller action is equivalent
diff --git a/actionview/lib/action_view/gem_version.rb b/actionview/lib/action_view/gem_version.rb
index 076b8ec30b..752eafee3c 100644
--- a/actionview/lib/action_view/gem_version.rb
+++ b/actionview/lib/action_view/gem_version.rb
@@ -8,7 +8,7 @@ module ActionView
MAJOR = 4
MINOR = 2
TINY = 0
- PRE = "beta2"
+ PRE = "beta4"
STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".")
end
diff --git a/actionview/lib/action_view/helpers/form_helper.rb b/actionview/lib/action_view/helpers/form_helper.rb
index 038f9e384b..03f80ff360 100644
--- a/actionview/lib/action_view/helpers/form_helper.rb
+++ b/actionview/lib/action_view/helpers/form_helper.rb
@@ -1231,8 +1231,8 @@ module ActionView
# end
#
# The above code creates a new method +div_radio_button+ which wraps a div
- # around the a new radio button. Note that when options are passed in, you
- # must called +objectify_options+ in order for the model object to get
+ # around the new radio button. Note that when options are passed in, you
+ # must call +objectify_options+ in order for the model object to get
# correctly passed to the method. If +objectify_options+ is not called,
# then the newly created helper will not be linked back to the model.
#
diff --git a/actionview/lib/action_view/helpers/form_tag_helper.rb b/actionview/lib/action_view/helpers/form_tag_helper.rb
index 69893b8abd..c0218fd55d 100644
--- a/actionview/lib/action_view/helpers/form_tag_helper.rb
+++ b/actionview/lib/action_view/helpers/form_tag_helper.rb
@@ -133,12 +133,18 @@ module ActionView
option_tags ||= ""
html_name = (options[:multiple] == true && !name.to_s.ends_with?("[]")) ? "#{name}[]" : name
- if options.delete(:include_blank)
- option_tags = content_tag(:option, '', :value => '').safe_concat(option_tags)
+ if options.include?(:include_blank)
+ include_blank = options.delete(:include_blank)
+
+ if include_blank == true
+ include_blank = ''
+ end
+
+ option_tags = content_tag(:option, include_blank, value: '').safe_concat(option_tags)
end
if prompt = options.delete(:prompt)
- option_tags = content_tag(:option, prompt, :value => '').safe_concat(option_tags)
+ option_tags = content_tag(:option, prompt, value: '').safe_concat(option_tags)
end
content_tag :select, option_tags, { "name" => html_name, "id" => sanitize_to_id(name) }.update(options.stringify_keys)
diff --git a/actionview/lib/action_view/helpers/number_helper.rb b/actionview/lib/action_view/helpers/number_helper.rb
index 7220bded3c..f66dbfe7d3 100644
--- a/actionview/lib/action_view/helpers/number_helper.rb
+++ b/actionview/lib/action_view/helpers/number_helper.rb
@@ -306,12 +306,12 @@ module ActionView
# string containing an i18n scope where to find this hash. It
# might have the following keys:
# * *integers*: <tt>:unit</tt>, <tt>:ten</tt>,
- # *<tt>:hundred</tt>, <tt>:thousand</tt>, <tt>:million</tt>,
- # *<tt>:billion</tt>, <tt>:trillion</tt>,
- # *<tt>:quadrillion</tt>
+ # <tt>:hundred</tt>, <tt>:thousand</tt>, <tt>:million</tt>,
+ # <tt>:billion</tt>, <tt>:trillion</tt>,
+ # <tt>:quadrillion</tt>
# * *fractionals*: <tt>:deci</tt>, <tt>:centi</tt>,
- # *<tt>:mili</tt>, <tt>:micro</tt>, <tt>:nano</tt>,
- # *<tt>:pico</tt>, <tt>:femto</tt>
+ # <tt>:mili</tt>, <tt>:micro</tt>, <tt>:nano</tt>,
+ # <tt>:pico</tt>, <tt>:femto</tt>
# * <tt>:format</tt> - Sets the format of the output string
# (defaults to "%n %u"). The field types are:
# * %u - The quantifier (ex.: 'thousand')
diff --git a/actionview/lib/action_view/helpers/sanitize_helper.rb b/actionview/lib/action_view/helpers/sanitize_helper.rb
index 4f2db0a0c4..7cb55cc214 100644
--- a/actionview/lib/action_view/helpers/sanitize_helper.rb
+++ b/actionview/lib/action_view/helpers/sanitize_helper.rb
@@ -57,7 +57,7 @@ module ActionView
# Add table tags to the default allowed tags
#
# class Application < Rails::Application
- # config.action_view.sanitized_allowed_tags = 'table', 'tr', 'td'
+ # config.action_view.sanitized_allowed_tags = ['table', 'tr', 'td']
# end
#
# Remove tags to the default allowed tags
@@ -176,7 +176,7 @@ module ActionView
# Replaces the allowed tags for the +sanitize+ helper.
#
# class Application < Rails::Application
- # config.action_view.sanitized_allowed_tags = 'table', 'tr', 'td'
+ # config.action_view.sanitized_allowed_tags = ['table', 'tr', 'td']
# end
#
diff --git a/actionview/lib/action_view/helpers/tag_helper.rb b/actionview/lib/action_view/helpers/tag_helper.rb
index 385d57a7a5..b2038576a2 100644
--- a/actionview/lib/action_view/helpers/tag_helper.rb
+++ b/actionview/lib/action_view/helpers/tag_helper.rb
@@ -123,7 +123,7 @@ module ActionView
# cdata_section("hello]]>world")
# # => <![CDATA[hello]]]]><![CDATA[>world]]>
def cdata_section(content)
- splitted = content.to_s.gsub(']]>', ']]]]><![CDATA[>')
+ splitted = content.to_s.gsub(/\]\]\>/, ']]]]><![CDATA[>')
"<![CDATA[#{splitted}]]>".html_safe
end
diff --git a/actionview/lib/action_view/helpers/tags/base.rb b/actionview/lib/action_view/helpers/tags/base.rb
index 8607da301c..f8abb19698 100644
--- a/actionview/lib/action_view/helpers/tags/base.rb
+++ b/actionview/lib/action_view/helpers/tags/base.rb
@@ -25,7 +25,7 @@ module ActionView
private
def value(object)
- object.send @method_name if object
+ object.public_send @method_name if object
end
def value_before_type_cast(object)
diff --git a/actionview/lib/action_view/renderer/template_renderer.rb b/actionview/lib/action_view/renderer/template_renderer.rb
index f3a48ecfa0..cd21d7ab47 100644
--- a/actionview/lib/action_view/renderer/template_renderer.rb
+++ b/actionview/lib/action_view/renderer/template_renderer.rb
@@ -18,7 +18,7 @@ module ActionView
# Determine the template to be rendered using the given options.
def determine_template(options)
- keys = options.fetch(:locals, {}).keys
+ keys = options.has_key?(:locals) ? options[:locals].keys : []
if options.key?(:body)
Template::Text.new(options[:body])
diff --git a/actionview/lib/action_view/template.rb b/actionview/lib/action_view/template.rb
index 379f31bdaf..6b61378a1f 100644
--- a/actionview/lib/action_view/template.rb
+++ b/actionview/lib/action_view/template.rb
@@ -313,11 +313,15 @@ module ActionView
def locals_code #:nodoc:
# Double assign to suppress the dreaded 'assigned but unused variable' warning
- @locals.map { |key| "#{key} = #{key} = local_assigns[:#{key}];" }.join
+ @locals.each_with_object('') { |key, code| code << "#{key} = #{key} = local_assigns[:#{key}];" }
end
def method_name #:nodoc:
- @method_name ||= "_#{identifier_method_name}__#{@identifier.hash}_#{__id__}".tr('-', "_")
+ @method_name ||= begin
+ m = "_#{identifier_method_name}__#{@identifier.hash}_#{__id__}"
+ m.tr!('-', '_')
+ m
+ end
end
def identifier_method_name #:nodoc:
diff --git a/actionview/lib/action_view/template/handlers/raw.rb b/actionview/lib/action_view/template/handlers/raw.rb
index 0c0d1fffcb..397c86014a 100644
--- a/actionview/lib/action_view/template/handlers/raw.rb
+++ b/actionview/lib/action_view/template/handlers/raw.rb
@@ -2,7 +2,7 @@ module ActionView
module Template::Handlers
class Raw
def call(template)
- escaped = template.source.gsub(':', '\:')
+ escaped = template.source.gsub(/:/, '\:')
'%q:' + escaped + ':;'
end
diff --git a/actionview/lib/action_view/template/resolver.rb b/actionview/lib/action_view/template/resolver.rb
index d77421d5f5..b65507f4a2 100644
--- a/actionview/lib/action_view/template/resolver.rb
+++ b/actionview/lib/action_view/template/resolver.rb
@@ -1,6 +1,7 @@
require "pathname"
require "active_support/core_ext/class"
require "active_support/core_ext/module/attribute_accessors"
+require 'active_support/core_ext/string/filters'
require "action_view/template"
require "thread"
require "thread_safe"
@@ -251,9 +252,10 @@ module ActionView
extension = pieces.pop
unless extension
- message = "The file #{path} did not specify a template handler. The default is currently ERB, " \
- "but will change to RAW in the future."
- ActiveSupport::Deprecation.warn message
+ ActiveSupport::Deprecation.warn(<<-MSG.squish)
+ The file #{path} did not specify a template handler. The default is
+ currently ERB, but will change to RAW in the future.
+ MSG
end
handler = Template.handler_for_extension(extension)
diff --git a/actionview/lib/action_view/view_paths.rb b/actionview/lib/action_view/view_paths.rb
index 80a41f2418..2e203a7590 100644
--- a/actionview/lib/action_view/view_paths.rb
+++ b/actionview/lib/action_view/view_paths.rb
@@ -38,7 +38,11 @@ module ActionView
def handle_deprecated_parent_prefixes # TODO: remove in 4.3/5.0.
return unless respond_to?(:parent_prefixes)
- ActiveSupport::Deprecation.warn "Overriding ActionController::Base::parent_prefixes is deprecated, override .local_prefixes instead."
+ ActiveSupport::Deprecation.warn(<<-MSG.squish)
+ Overriding `ActionController::Base::parent_prefixes` is deprecated,
+ override `.local_prefixes` instead.
+ MSG
+
local_prefixes + parent_prefixes
end
end
diff --git a/actionview/test/template/form_helper_test.rb b/actionview/test/template/form_helper_test.rb
index f2238d1443..4bbbdf4fb1 100644
--- a/actionview/test/template/form_helper_test.rb
+++ b/actionview/test/template/form_helper_test.rb
@@ -1785,6 +1785,20 @@ class FormHelperTest < ActionView::TestCase
assert_dom_equal expected, output_buffer
end
+ def test_form_tags_do_not_call_private_properties_on_form_object
+ obj = Class.new do
+ private
+
+ def private_property
+ raise "This method should not be called."
+ end
+ end.new
+
+ form_for(obj, as: "other_name", url: '/', html: { id: "edit-other-name" }) do |f|
+ assert_raise(NoMethodError) { f.hidden_field(:private_property) }
+ end
+ end
+
def test_form_for_with_method_as_part_of_html_options
form_for(@post, url: '/', html: { id: 'create-post', method: :delete }) do |f|
concat f.text_field(:title)
diff --git a/actionview/test/template/form_tag_helper_test.rb b/actionview/test/template/form_tag_helper_test.rb
index 2d89332841..f8fd642809 100644
--- a/actionview/test/template/form_tag_helper_test.rb
+++ b/actionview/test/template/form_tag_helper_test.rb
@@ -232,6 +232,12 @@ class FormTagHelperTest < ActionView::TestCase
assert_dom_equal expected, actual
end
+ def test_select_tag_with_include_blank_string
+ actual = select_tag "places", "<option>Home</option><option>Work</option><option>Pub</option>".html_safe, include_blank: 'Choose'
+ expected = %(<select id="places" name="places"><option value="">Choose</option><option>Home</option><option>Work</option><option>Pub</option></select>)
+ assert_dom_equal expected, actual
+ end
+
def test_select_tag_with_prompt
actual = select_tag "places", "<option>Home</option><option>Work</option><option>Pub</option>".html_safe, :prompt => "string"
expected = %(<select id="places" name="places"><option value="">string</option><option>Home</option><option>Work</option><option>Pub</option></select>)
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 f55db5a588..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)
@@ -48,8 +50,8 @@ module ActiveJob
end
end
- # Creates a new job instance. Takes as arguments the arguments that
- # will be passed to the perform method.
+ # Creates a new job instance. Takes the arguments that will be
+ # passed to the perform method.
def initialize(*arguments)
@arguments = arguments
@job_id = SecureRandom.uuid
@@ -84,6 +86,3 @@ module ActiveJob
end
end
end
-
-
-
diff --git a/activejob/lib/active_job/enqueuing.rb b/activejob/lib/active_job/enqueuing.rb
index cca0a2a8d6..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
@@ -22,7 +23,7 @@ module ActiveJob
end
end
- # Reschedule the job to be re-executed. This is useful in combination
+ # Reschedules the job to be re-executed. This is useful in combination
# with the +rescue_from+ option. When you rescue an exception from your job
# you can ask Active Job to retry performing your job.
#
@@ -37,6 +38,7 @@ module ActiveJob
# rescue_from(ErrorLoadingSite) do
# retry_job queue: :low_priority
# end
+ #
# def perform(*args)
# # raise ErrorLoadingSite if cannot scrape
# end
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/gem_version.rb b/activejob/lib/active_job/gem_version.rb
index f80e6563b8..ac364f77d1 100644
--- a/activejob/lib/active_job/gem_version.rb
+++ b/activejob/lib/active_job/gem_version.rb
@@ -8,7 +8,7 @@ module ActiveJob
MAJOR = 4
MINOR = 2
TINY = 0
- PRE = "beta2"
+ PRE = "beta4"
STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".")
end
diff --git a/activejob/lib/active_job/logging.rb b/activejob/lib/active_job/logging.rb
index 6e703faaa7..21d2fda3ff 100644
--- a/activejob/lib/active_job/logging.rb
+++ b/activejob/lib/active_job/logging.rb
@@ -75,7 +75,7 @@ module ActiveJob
def perform(event)
info do
job = event.payload[:job]
- "Performed #{job.class.name} from #{queue_name(event)} in #{event.duration.round(2).to_s}ms"
+ "Performed #{job.class.name} from #{queue_name(event)} in #{event.duration.round(2)}ms"
end
end
diff --git a/activejob/lib/active_job/queue_adapter.rb b/activejob/lib/active_job/queue_adapter.rb
index 4bd28522ab..85d7c44bb8 100644
--- a/activejob/lib/active_job/queue_adapter.rb
+++ b/activejob/lib/active_job/queue_adapter.rb
@@ -2,9 +2,12 @@ require 'active_job/queue_adapters/inline_adapter'
require 'active_support/core_ext/string/inflections'
module ActiveJob
+ # The <tt>ActionJob::QueueAdapter</tt> module is used to load the
+ # correct adapter. The default queue adapter is the :inline queue.
module QueueAdapter #:nodoc:
extend ActiveSupport::Concern
+ # Includes the setter method for changing the active queue adapter.
module ClassMethods
mattr_reader(:queue_adapter) { ActiveJob::QueueAdapters::InlineAdapter }
diff --git a/activejob/lib/active_job/queue_adapters.rb b/activejob/lib/active_job/queue_adapters.rb
index efbcd3cb3a..f22b0502dc 100644
--- a/activejob/lib/active_job/queue_adapters.rb
+++ b/activejob/lib/active_job/queue_adapters.rb
@@ -13,7 +13,7 @@ module ActiveJob
# * {Sneakers}[https://github.com/jondot/sneakers]
# * {Sucker Punch}[https://github.com/brandonhilkert/sucker_punch]
#
- # #### Backends Features
+ # === Backends Features
#
# | | Async | Queues | Delayed | Priorities | Timeout | Retries |
# |-------------------|-------|--------|-----------|------------|---------|---------|
diff --git a/activejob/lib/active_job/queue_adapters/delayed_job_adapter.rb b/activejob/lib/active_job/queue_adapters/delayed_job_adapter.rb
index 4d27c4fff8..69d9e70de3 100644
--- a/activejob/lib/active_job/queue_adapters/delayed_job_adapter.rb
+++ b/activejob/lib/active_job/queue_adapters/delayed_job_adapter.rb
@@ -6,10 +6,10 @@ module ActiveJob
#
# Delayed::Job (or DJ) encapsulates the common pattern of asynchronously
# executing longer tasks in the background. Although DJ can have many
- # storage backends one of the most used is based on Active Record.
+ # storage backends, one of the most used is based on Active Record.
# Read more about Delayed Job {here}[https://github.com/collectiveidea/delayed_job].
#
- # To use Delayed Job set the queue_adapter config to +:delayed_job+.
+ # To use Delayed Job, set the queue_adapter config to +:delayed_job+.
#
# Rails.application.config.active_job.queue_adapter = :delayed_job
class DelayedJobAdapter
diff --git a/activejob/lib/active_job/queue_adapters/queue_classic_adapter.rb b/activejob/lib/active_job/queue_adapters/queue_classic_adapter.rb
index 1a46f20420..34c11a68b2 100644
--- a/activejob/lib/active_job/queue_adapters/queue_classic_adapter.rb
+++ b/activejob/lib/active_job/queue_adapters/queue_classic_adapter.rb
@@ -26,7 +26,7 @@ module ActiveJob
queue = build_queue(job.queue_name)
unless queue.respond_to?(:enqueue_at)
raise NotImplementedError, 'To be able to schedule jobs with queue_classic ' \
- 'the QC::Queue needs to respond to `enqueue_at(timestamp, method, *args)`. '
+ 'the QC::Queue needs to respond to `enqueue_at(timestamp, method, *args)`. ' \
'You can implement this yourself or you can use the queue_classic-later gem.'
end
queue.enqueue_at(timestamp, "#{JobWrapper.name}.perform", job.serialize)
diff --git a/activejob/lib/active_job/queue_name.rb b/activejob/lib/active_job/queue_name.rb
index d167617e4e..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" }
@@ -26,13 +27,16 @@ module ActiveJob
def queue_name_from_part(part_name) #:nodoc:
queue_name = part_name || default_queue_name
name_parts = [queue_name_prefix.presence, queue_name]
- name_parts.compact.join('_')
+ name_parts.compact.join(queue_name_delimiter)
end
end
included do
class_attribute :queue_name, instance_accessor: false
+ class_attribute :queue_name_delimiter, instance_accessor: false
+
self.queue_name = default_queue_name
+ self.queue_name_delimiter = '_' # set default delimiter to '_'
end
# Returns the name of the queue the job will be run on
diff --git a/activejob/lib/active_job/test_helper.rb b/activejob/lib/active_job/test_helper.rb
index ade7a94c9d..bb20d93947 100644
--- a/activejob/lib/active_job/test_helper.rb
+++ b/activejob/lib/active_job/test_helper.rb
@@ -53,7 +53,7 @@ module ActiveJob
end
end
- # Assert that no job have been enqueued.
+ # Asserts that no jobs have been enqueued.
#
# def test_jobs
# assert_no_enqueued_jobs
@@ -137,7 +137,7 @@ module ActiveJob
# Asserts that the job passed in the block has been enqueued with the given arguments.
#
- # def assert_enqueued_job
+ # def test_assert_enqueued_with
# assert_enqueued_with(job: MyJob, args: [1,2,3], queue: 'low') do
# MyJob.perform_later(1,2,3)
# end
diff --git a/activejob/test/cases/queue_naming_test.rb b/activejob/test/cases/queue_naming_test.rb
index 886f41271a..898016a704 100644
--- a/activejob/test/cases/queue_naming_test.rb
+++ b/activejob/test/cases/queue_naming_test.rb
@@ -64,7 +64,7 @@ class QueueNamingTest < ActiveSupport::TestCase
end
end
- test 'queu_name_prefix prepended to the queue name' do
+ test 'queue_name_prefix prepended to the queue name with default delimiter' do
original_queue_name_prefix = ActiveJob::Base.queue_name_prefix
original_queue_name = HelloJob.queue_name
@@ -78,6 +78,23 @@ class QueueNamingTest < ActiveSupport::TestCase
end
end
+ test 'queue_name_prefix prepended to the queue name with custom delimiter' do
+ original_queue_name_prefix = ActiveJob::Base.queue_name_prefix
+ original_queue_name_delimiter = ActiveJob::Base.queue_name_delimiter
+ original_queue_name = HelloJob.queue_name
+
+ begin
+ ActiveJob::Base.queue_name_delimiter = '.'
+ ActiveJob::Base.queue_name_prefix = 'aj'
+ HelloJob.queue_as :low
+ assert_equal 'aj.low', HelloJob.queue_name
+ ensure
+ ActiveJob::Base.queue_name_prefix = original_queue_name_prefix
+ ActiveJob::Base.queue_name_delimiter = original_queue_name_delimiter
+ HelloJob.queue_name = original_queue_name
+ end
+ end
+
test 'uses queue passed to #set' do
job = HelloJob.set(queue: :some_queue).perform_later
assert_equal "some_queue", job.queue_name
diff --git a/activejob/test/jobs/callback_job.rb b/activejob/test/jobs/callback_job.rb
index 056dd073e8..891ed9464e 100644
--- a/activejob/test/jobs/callback_job.rb
+++ b/activejob/test/jobs/callback_job.rb
@@ -1,12 +1,21 @@
class CallbackJob < ActiveJob::Base
before_perform ->(job) { job.history << "CallbackJob ran before_perform" }
- after_perform ->(job) { job.history << "CallbackJob ran after_perform" }
+ after_perform ->(job) { job.history << "CallbackJob ran after_perform" }
before_enqueue ->(job) { job.history << "CallbackJob ran before_enqueue" }
- after_enqueue ->(job) { job.history << "CallbackJob ran after_enqueue" }
+ after_enqueue ->(job) { job.history << "CallbackJob ran after_enqueue" }
- around_perform :around_perform
- around_enqueue :around_enqueue
+ around_perform do |job, block|
+ job.history << "CallbackJob ran around_perform_start"
+ block.call
+ job.history << "CallbackJob ran around_perform_stop"
+ end
+
+ around_enqueue do |job, block|
+ job.history << "CallbackJob ran around_enqueue_start"
+ block.call
+ job.history << "CallbackJob ran around_enqueue_stop"
+ end
def perform(person = "david")
@@ -17,16 +26,4 @@ class CallbackJob < ActiveJob::Base
@history ||= []
end
- # FIXME: Not sure why these can't be declared inline like before/after
- def around_perform
- history << "CallbackJob ran around_perform_start"
- yield
- history << "CallbackJob ran around_perform_stop"
- end
-
- def around_enqueue
- history << "CallbackJob ran around_enqueue_start"
- yield
- history << "CallbackJob ran around_enqueue_stop"
- end
end
diff --git a/activemodel/lib/active_model/dirty.rb b/activemodel/lib/active_model/dirty.rb
index ca04f48c1c..ae185694ca 100644
--- a/activemodel/lib/active_model/dirty.rb
+++ b/activemodel/lib/active_model/dirty.rb
@@ -1,5 +1,6 @@
require 'active_support/hash_with_indifferent_access'
require 'active_support/core_ext/object/duplicable'
+require 'active_support/core_ext/string/filters'
module ActiveModel
# == Active \Model \Dirty
@@ -200,7 +201,11 @@ module ActiveModel
end
def reset_changes
- ActiveSupport::Deprecation.warn "#reset_changes is deprecated and will be removed on Rails 5. Please use #clear_changes_information instead."
+ ActiveSupport::Deprecation.warn(<<-MSG.squish)
+ `#reset_changes` is deprecated and will be removed on Rails 5.
+ Please use `#clear_changes_information` instead.
+ MSG
+
clear_changes_information
end
@@ -224,7 +229,10 @@ module ActiveModel
# Handle <tt>reset_*!</tt> for +method_missing+.
def reset_attribute!(attr)
- ActiveSupport::Deprecation.warn "#reset_#{attr}! is deprecated and will be removed on Rails 5. Please use #restore_#{attr}! instead."
+ ActiveSupport::Deprecation.warn(<<-MSG.squish)
+ `#reset_#{attr}!` is deprecated and will be removed on Rails 5.
+ Please use `#restore_#{attr}!` instead.
+ MSG
restore_attribute!(attr)
end
diff --git a/activemodel/lib/active_model/gem_version.rb b/activemodel/lib/active_model/gem_version.rb
index e37edcf581..932fe3e5a9 100644
--- a/activemodel/lib/active_model/gem_version.rb
+++ b/activemodel/lib/active_model/gem_version.rb
@@ -8,7 +8,7 @@ module ActiveModel
MAJOR = 4
MINOR = 2
TINY = 0
- PRE = "beta2"
+ PRE = "beta4"
STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".")
end
diff --git a/activemodel/lib/active_model/validations.rb b/activemodel/lib/active_model/validations.rb
index 1116f6b8ee..c1e344b215 100644
--- a/activemodel/lib/active_model/validations.rb
+++ b/activemodel/lib/active_model/validations.rb
@@ -392,7 +392,7 @@ module ActiveModel
protected
def run_validations! #:nodoc:
- run_validate_callbacks
+ _run_validate_callbacks
errors.empty?
end
end
diff --git a/activemodel/lib/active_model/validations/callbacks.rb b/activemodel/lib/active_model/validations/callbacks.rb
index 1a5192b0ff..25ccabd66b 100644
--- a/activemodel/lib/active_model/validations/callbacks.rb
+++ b/activemodel/lib/active_model/validations/callbacks.rb
@@ -110,7 +110,7 @@ module ActiveModel
# Overwrite run validations to include callbacks.
def run_validations! #:nodoc:
- run_validation_callbacks { super }
+ _run_validation_callbacks { super }
end
end
end
diff --git a/activemodel/lib/active_model/validations/format.rb b/activemodel/lib/active_model/validations/format.rb
index ff3e95da34..02478dd5b6 100644
--- a/activemodel/lib/active_model/validations/format.rb
+++ b/activemodel/lib/active_model/validations/format.rb
@@ -54,7 +54,7 @@ module ActiveModel
module HelperMethods
# Validates whether the value of the specified attribute is of the correct
- # form, going by the regular expression provided.You can require that the
+ # form, going by the regular expression provided. You can require that the
# attribute matches the regular expression:
#
# class Person < ActiveRecord::Base
diff --git a/activemodel/test/cases/validations/validates_test.rb b/activemodel/test/cases/validations/validates_test.rb
index 699a872e42..8d4b74ee49 100644
--- a/activemodel/test/cases/validations/validates_test.rb
+++ b/activemodel/test/cases/validations/validates_test.rb
@@ -3,7 +3,6 @@ require 'cases/helper'
require 'models/person'
require 'models/topic'
require 'models/person_with_validator'
-require 'validators/email_validator'
require 'validators/namespace/email_validator'
class ValidatesTest < ActiveModel::TestCase
diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md
index e0e107e89d..6bb1ea3cec 100644
--- a/activerecord/CHANGELOG.md
+++ b/activerecord/CHANGELOG.md
@@ -1,3 +1,42 @@
+* 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`.
+
+ *Melanie Gilman & Sean Griffin*
+
+* MySQL enum type lookups, with values matching another type, no longer result
+ in an endless loop.
+
+ Fixes #17402.
+
+ *Yves Senn*
+
+* Raise `ArgumentError` when the body of a scope is not callable.
+
+ *Mauro George*
+
+* Use type column first in multi-column indexes created with `add-reference`.
+
+ *Derek Prior*
+
+* Fix `Relation.rewhere` to work with Range values.
+
+ *Dan Olson*
+
* `AR::UnknownAttributeError` now includes the class name of a record.
User.new(name: "Yuki Nishijima", project_attributes: {name: "kaminari"})
diff --git a/activerecord/activerecord.gemspec b/activerecord/activerecord.gemspec
index 6231851be5..bc10e96244 100644
--- a/activerecord/activerecord.gemspec
+++ b/activerecord/activerecord.gemspec
@@ -24,5 +24,5 @@ Gem::Specification.new do |s|
s.add_dependency 'activesupport', version
s.add_dependency 'activemodel', version
- s.add_dependency 'arel', '>= 6.0.0.beta1', '< 6.1'
+ s.add_dependency 'arel', '>= 6.0.0.beta2', '< 6.1'
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 455a540bdb..bde23fc116 100644
--- a/activerecord/lib/active_record/associations/has_many_through_association.rb
+++ b/activerecord/lib/active_record/associations/has_many_through_association.rb
@@ -1,3 +1,5 @@
+require 'active_support/core_ext/string/filters'
+
module ActiveRecord
# = Active Record Has Many Through Association
module Associations
@@ -63,11 +65,12 @@ module ActiveRecord
save_through_record(record)
if has_cached_counter? && !through_reflection_updates_counter_cache?
- ActiveSupport::Deprecation.warn \
- "Automatic updating of counter caches on through associations has been " \
- "deprecated, and will be removed in Rails 5.0. Instead, please set the " \
- "appropriate counter_cache options on the has_many and belongs_to for " \
- "your associations to #{through_reflection.name}."
+ ActiveSupport::Deprecation.warn(<<-MSG.squish)
+ Automatic updating of counter caches on through associations has been
+ deprecated, and will be removed in Rails 5. Instead, please set the
+ appropriate `counter_cache` options on the `has_many` and `belongs_to`
+ for your associations to #{through_reflection.name}.
+ MSG
update_counter_in_database(1)
end
@@ -158,8 +161,8 @@ module ActiveRecord
if scope.klass.primary_key
count = scope.destroy_all.length
else
- scope.to_a.each do |record|
- record.run_destroy_callbacks
+ scope.each do |record|
+ record._run_destroy_callbacks
end
arel = scope.arel
diff --git a/activerecord/lib/active_record/associations/preloader/association.rb b/activerecord/lib/active_record/associations/preloader/association.rb
index 2300435f91..496c426986 100644
--- a/activerecord/lib/active_record/associations/preloader/association.rb
+++ b/activerecord/lib/active_record/associations/preloader/association.rb
@@ -136,10 +136,6 @@ module ActiveRecord
preload_values = preload_scope.values
preload_binds = preload_scope.bind_values
- if values[:unscope]
- scope.unscope! values[:unscope]
- end
-
scope.where_values = Array(values[:where]) + Array(preload_values[:where])
scope.references_values = Array(values[:references]) + Array(preload_values[:references])
scope.bind_values = (reflection_binds + preload_binds)
@@ -163,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/preloader/through_association.rb b/activerecord/lib/active_record/associations/preloader/through_association.rb
index d57da366bd..12bf3ef138 100644
--- a/activerecord/lib/active_record/associations/preloader/through_association.rb
+++ b/activerecord/lib/active_record/associations/preloader/through_association.rb
@@ -81,6 +81,7 @@ module ActiveRecord
unless reflection_scope.where_values.empty?
scope.includes_values = Array(reflection_scope.values[:includes] || options[:source])
scope.where_values = reflection_scope.values[:where]
+ scope.bind_values = reflection_scope.bind_values
end
scope.references! reflection_scope.values[:references]
diff --git a/activerecord/lib/active_record/attribute_methods.rb b/activerecord/lib/active_record/attribute_methods.rb
index f4a4e3f605..34ec397aee 100644
--- a/activerecord/lib/active_record/attribute_methods.rb
+++ b/activerecord/lib/active_record/attribute_methods.rb
@@ -1,4 +1,5 @@
require 'active_support/core_ext/enumerable'
+require 'active_support/core_ext/string/filters'
require 'mutex_m'
require 'thread_safe'
@@ -90,7 +91,7 @@ module ActiveRecord
def undefine_attribute_methods # :nodoc:
generated_attribute_methods.synchronize do
- super if @attribute_methods_generated
+ super if defined?(@attribute_methods_generated) && @attribute_methods_generated
@attribute_methods_generated = false
end
end
@@ -205,9 +206,11 @@ module ActiveRecord
def column_for_attribute(name)
column = columns_hash[name.to_s]
if column.nil?
- ActiveSupport::Deprecation.warn \
- "`column_for_attribute` will return a null object for non-existent columns " \
- "in Rails 5.0. Use `has_attribute?` if you need to check for an attribute's existence."
+ ActiveSupport::Deprecation.warn(<<-MSG.squish)
+ `#column_for_attribute` will return a null object for non-existent
+ columns in Rails 5. Use `#has_attribute?` if you need to check for
+ an attribute's existence.
+ MSG
end
column
end
diff --git a/activerecord/lib/active_record/attribute_methods/serialization.rb b/activerecord/lib/active_record/attribute_methods/serialization.rb
index cc82d00b20..e5ec5ddca5 100644
--- a/activerecord/lib/active_record/attribute_methods/serialization.rb
+++ b/activerecord/lib/active_record/attribute_methods/serialization.rb
@@ -1,3 +1,5 @@
+require 'active_support/core_ext/string/filters'
+
module ActiveRecord
module AttributeMethods
module Serialization
@@ -51,8 +53,10 @@ module ActiveRecord
end
def serialized_attributes
- ActiveSupport::Deprecation.warn "`serialized_attributes` is deprecated " \
- "without replacement, and will be removed in Rails 5.0."
+ ActiveSupport::Deprecation.warn(<<-MSG.squish)
+ `serialized_attributes` is deprecated without replacement, and will
+ be removed in Rails 5.0.
+ MSG
@serialized_attributes ||= Hash[
columns.select { |t| t.cast_type.is_a?(Type::Serialized) }.map { |c|
diff --git a/activerecord/lib/active_record/attributes.rb b/activerecord/lib/active_record/attributes.rb
index 890a1314d9..3288108a6a 100644
--- a/activerecord/lib/active_record/attributes.rb
+++ b/activerecord/lib/active_record/attributes.rb
@@ -6,7 +6,9 @@ module ActiveRecord
included do
class_attribute :user_provided_columns, instance_accessor: false # :internal:
+ class_attribute :user_provided_defaults, instance_accessor: false # :internal:
self.user_provided_columns = {}
+ self.user_provided_defaults = {}
end
module ClassMethods # :nodoc:
@@ -77,7 +79,11 @@ module ActiveRecord
name = name.to_s
clear_caches_calculated_from_columns
# Assign a new hash to ensure that subclasses do not share a hash
- self.user_provided_columns = user_provided_columns.merge(name => connection.new_column(name, options[:default], cast_type))
+ self.user_provided_columns = user_provided_columns.merge(name => cast_type)
+
+ if options.key?(:default)
+ self.user_provided_defaults = user_provided_defaults.merge(name => options[:default])
+ end
end
# Returns an array of column objects for the table associated with this class.
@@ -99,11 +105,18 @@ module ActiveRecord
def add_user_provided_columns(schema_columns)
existing_columns = schema_columns.map do |column|
- user_provided_columns[column.name] || column
+ new_type = user_provided_columns[column.name]
+ if new_type
+ column.with_type(new_type)
+ else
+ column
+ end
end
existing_column_names = existing_columns.map(&:name)
- new_columns = user_provided_columns.except(*existing_column_names).values
+ new_columns = user_provided_columns.except(*existing_column_names).map do |(name, type)|
+ connection.new_column(name, nil, type)
+ end
existing_columns + new_columns
end
@@ -117,6 +130,10 @@ module ActiveRecord
@content_columns = nil
@default_attributes = nil
end
+
+ def raw_default_values
+ super.merge(user_provided_defaults)
+ end
end
end
end
diff --git a/activerecord/lib/active_record/callbacks.rb b/activerecord/lib/active_record/callbacks.rb
index 1aa760157a..523d492a48 100644
--- a/activerecord/lib/active_record/callbacks.rb
+++ b/activerecord/lib/active_record/callbacks.rb
@@ -289,25 +289,25 @@ module ActiveRecord
end
def destroy #:nodoc:
- run_destroy_callbacks { super }
+ _run_destroy_callbacks { super }
end
def touch(*) #:nodoc:
- run_touch_callbacks { super }
+ _run_touch_callbacks { super }
end
private
def create_or_update #:nodoc:
- run_save_callbacks { super }
+ _run_save_callbacks { super }
end
def _create_record #:nodoc:
- run_create_callbacks { super }
+ _run_create_callbacks { super }
end
def _update_record(*) #:nodoc:
- run_update_callbacks { super }
+ _run_update_callbacks { super }
end
end
end
diff --git a/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb b/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb
index da43e5bb10..46812b75bb 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb
@@ -2,6 +2,7 @@ require 'thread'
require 'thread_safe'
require 'monitor'
require 'set'
+require 'active_support/core_ext/string/filters'
module ActiveRecord
# Raised when a connection could not be obtained within the connection
@@ -360,7 +361,7 @@ module ActiveRecord
synchronize do
owner = conn.owner
- conn.run_checkin_callbacks do
+ conn._run_checkin_callbacks do
conn.expire
end
@@ -449,7 +450,7 @@ module ActiveRecord
end
def checkout_and_verify(c)
- c.run_checkout_callbacks do
+ c._run_checkout_callbacks do
c.verify!
end
c
@@ -518,10 +519,11 @@ module ActiveRecord
end
def connection_pools
- ActiveSupport::Deprecation.warn(
- "In the next release, this will return the same as #connection_pool_list. " \
- "(An array of pools, rather than a hash mapping specs to pools.)"
- )
+ ActiveSupport::Deprecation.warn(<<-MSG.squish)
+ In the next release, this will return the same as `#connection_pool_list`.
+ (An array of pools, rather than a hash mapping specs to pools.)
+ MSG
+
Hash[connection_pool_list.map { |pool| [pool.spec, pool] }]
end
diff --git a/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb b/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb
index eb88845913..679878d860 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb
@@ -108,7 +108,7 @@ module ActiveRecord
when Numeric, ActiveSupport::Duration then value.to_s
when Date, Time then "'#{quoted_date(value)}'"
when Symbol then "'#{quote_string(value.to_s)}'"
- when Class then "'#{value.to_s}'"
+ when Class then "'#{value}'"
else
"'#{quote_string(YAML.dump(value))}'"
end
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 adb9fcaeb8..f8b6daea5a 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb
@@ -60,11 +60,11 @@ module ActiveRecord
def emit_warning_if_null_unspecified(options)
return if options.key?(:null)
- ActiveSupport::Deprecation.warn \
- "`timestamp` was called without specifying an option for `null`. In Rails " \
- "5.0, this behavior will change to `null: false`. You should manually " \
- "specify `null: true` to prevent the behavior of your existing migrations " \
- "from changing."
+ ActiveSupport::Deprecation.warn(<<-MSG.squish)
+ `#timestamp` was called without specifying an option for `null`. In Rails 5,
+ this behavior will change to `null: false`. You should manually specify
+ `null: true` to prevent the behavior of your existing migrations from changing.
+ MSG
end
end
@@ -312,7 +312,7 @@ module ActiveRecord
args.each do |col|
column("#{col}_id", type, options)
column("#{col}_type", :string, polymorphic.is_a?(Hash) ? polymorphic : options) if polymorphic
- index(polymorphic ? %w(id type).map { |t| "#{col}_#{t}" } : "#{col}_id", index_options.is_a?(Hash) ? index_options : {}) if index_options
+ index(polymorphic ? %w(type id).map { |t| "#{col}_#{t}" } : "#{col}_id", index_options.is_a?(Hash) ? index_options : {}) if index_options
end
end
alias :belongs_to :references
diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_dumper.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_dumper.rb
index b05a4f8440..6eab11b88b 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/schema_dumper.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_dumper.rb
@@ -8,7 +8,7 @@ module ActiveRecord
module ColumnDumper
def column_spec(column, types)
spec = prepare_column_options(column, types)
- (spec.keys - [:name, :type]).each{ |k| spec[k].insert(0, "#{k.to_s}: ")}
+ (spec.keys - [:name, :type]).each{ |k| spec[k].insert(0, "#{k}: ")}
spec
end
diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb
index 7105df1ee4..cbf87df356 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb
@@ -629,7 +629,7 @@ module ActiveRecord
type = options.delete(:type) || :integer
add_column(table_name, "#{ref_name}_id", type, options)
add_column(table_name, "#{ref_name}_type", :string, polymorphic.is_a?(Hash) ? polymorphic : options) if polymorphic
- add_index(table_name, polymorphic ? %w[id type].map{ |t| "#{ref_name}_#{t}" } : "#{ref_name}_id", index_options.is_a?(Hash) ? index_options : {}) if index_options
+ add_index(table_name, polymorphic ? %w[type id].map{ |t| "#{ref_name}_#{t}" } : "#{ref_name}_id", index_options.is_a?(Hash) ? index_options : {}) if index_options
end
alias :add_belongs_to :add_reference
diff --git a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb
index a0d9086875..582dd360f0 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb
@@ -14,10 +14,7 @@ module ActiveRecord
module ConnectionAdapters # :nodoc:
extend ActiveSupport::Autoload
- autoload_at 'active_record/connection_adapters/column' do
- autoload :Column
- autoload :NullColumn
- end
+ autoload :Column
autoload :ConnectionSpecification
autoload_at 'active_record/connection_adapters/abstract/schema_definitions' do
@@ -267,7 +264,7 @@ module ActiveRecord
# Returns a bind substitution value given a bind +index+ and +column+
# NOTE: The column param is currently being used by the sqlserver-adapter
- def substitute_at(column, index)
+ def substitute_at(column, index = 0)
Arel::Nodes::BindParam.new '?'
end
@@ -386,6 +383,10 @@ module ActiveRecord
type_map.lookup(sql_type)
end
+ def column_name_for_operation(operation, node) # :nodoc:
+ node.to_sql
+ end
+
protected
def initialize_type_map(m) # :nodoc:
diff --git a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb
index e4cfe843a8..5f512758e9 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb
@@ -91,6 +91,13 @@ module ActiveRecord
collation && !collation.match(/_ci$/)
end
+ def ==(other)
+ super &&
+ collation == other.collation &&
+ strict == other.strict &&
+ extra == other.extra
+ end
+
private
# MySQL misreports NOT NULL column default when none is given.
@@ -109,6 +116,10 @@ module ActiveRecord
raise ArgumentError, "#{type} columns cannot have a default value: #{default.inspect}"
end
end
+
+ def attributes_for_hash
+ super + [collation, strict, extra]
+ end
end
##
@@ -485,7 +496,7 @@ module ActiveRecord
end
end
- def change_column_default(table_name, column_name, default)
+ def change_column_default(table_name, column_name, default) #:nodoc:
column = column_for(table_name, column_name)
change_column table_name, column_name, column.sql_type, :default => default
end
@@ -574,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')
@@ -645,12 +648,6 @@ module ActiveRecord
def initialize_type_map(m) # :nodoc:
super
- 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)
- end
-
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)
@@ -671,6 +668,12 @@ module ActiveRecord
m.alias_type %r(set)i, 'varchar'
m.alias_type %r(year)i, 'integer'
m.alias_type %r(bit)i, 'binary'
+
+ 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)
+ end
end
# MySQL is too stupid to create a temporary table for use subquery, so we have
@@ -825,9 +828,9 @@ module ActiveRecord
# Gather up all of the SET variables...
variable_assignments = variables.map do |k, v|
if v == ':default' || v == :default
- "@@SESSION.#{k.to_s} = DEFAULT" # Sets the value to the global or compile default
+ "@@SESSION.#{k} = DEFAULT" # Sets the value to the global or compile default
elsif !v.nil?
- "@@SESSION.#{k.to_s} = #{quote(v)}"
+ "@@SESSION.#{k} = #{quote(v)}"
end
# or else nil; compact to clear nils out
end.compact.join(', ')
diff --git a/activerecord/lib/active_record/connection_adapters/column.rb b/activerecord/lib/active_record/connection_adapters/column.rb
index 5f9cc6edd0..dd303c73d5 100644
--- a/activerecord/lib/active_record/connection_adapters/column.rb
+++ b/activerecord/lib/active_record/connection_adapters/column.rb
@@ -56,6 +56,26 @@ module ActiveRecord
clone.instance_variable_set('@cast_type', type)
end
end
+
+ def ==(other)
+ other.name == name &&
+ other.default == default &&
+ other.cast_type == cast_type &&
+ other.sql_type == sql_type &&
+ other.null == null &&
+ other.default_function == default_function
+ end
+ alias :eql? :==
+
+ def hash
+ attributes_for_hash.hash
+ end
+
+ private
+
+ def attributes_for_hash
+ [self.class, name, default, cast_type, sql_type, null, default_function]
+ end
end
end
# :startdoc:
diff --git a/activerecord/lib/active_record/connection_adapters/connection_specification.rb b/activerecord/lib/active_record/connection_adapters/connection_specification.rb
index e02824b33d..609ec7dabd 100644
--- a/activerecord/lib/active_record/connection_adapters/connection_specification.rb
+++ b/activerecord/lib/active_record/connection_adapters/connection_specification.rb
@@ -1,4 +1,5 @@
require 'uri'
+require 'active_support/core_ext/string/filters'
module ActiveRecord
module ConnectionAdapters
@@ -221,8 +222,12 @@ module ActiveRecord
# this ambiguous behaviour and in the future this function
# can be removed in favor of resolve_url_connection.
if configurations.key?(spec) || spec !~ /:/
- ActiveSupport::Deprecation.warn "Passing a string to ActiveRecord::Base.establish_connection " \
- "for a configuration lookup is deprecated, please pass a symbol (#{spec.to_sym.inspect}) instead"
+ ActiveSupport::Deprecation.warn(<<-MSG.squish)
+ Passing a string to ActiveRecord::Base.establish_connection for a
+ configuration lookup is deprecated, please pass a symbol
+ (#{spec.to_sym.inspect}) instead.
+ MSG
+
resolve_symbol_connection(spec)
else
resolve_url_connection(spec)
diff --git a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb
index cff6798eb3..3357ed52e5 100644
--- a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb
@@ -88,7 +88,7 @@ module ActiveRecord
end
def clear
- cache.values.each do |hash|
+ cache.each_value do |hash|
hash[:stmt].close
end
cache.clear
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/database_statements.rb b/activerecord/lib/active_record/connection_adapters/postgresql/database_statements.rb
index 89a7257d77..cf379ab210 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql/database_statements.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql/database_statements.rb
@@ -156,7 +156,7 @@ module ActiveRecord
end
end
- def substitute_at(column, index)
+ def substitute_at(column, index = 0)
Arel::Nodes::BindParam.new "$#{index + 1}"
end
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/oid/cidr.rb b/activerecord/lib/active_record/connection_adapters/postgresql/oid/cidr.rb
index a53b4ee8e2..222f10fa8f 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql/oid/cidr.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql/oid/cidr.rb
@@ -12,15 +12,15 @@ module ActiveRecord
# If the subnet mask is equal to /32, don't output it
if subnet_mask == (2**32 - 1)
- "\"#{value.to_s}\""
+ "\"#{value}\""
else
- "\"#{value.to_s}/#{subnet_mask.to_s(2).count('1')}\""
+ "\"#{value}/#{subnet_mask.to_s(2).count('1')}\""
end
end
def type_cast_for_database(value)
if IPAddr === value
- "#{value.to_s}/#{value.instance_variable_get(:@mask_addr).to_s(2).count('1')}"
+ "#{value}/#{value.instance_variable_get(:@mask_addr).to_s(2).count('1')}"
else
value
end
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/oid/range.rb b/activerecord/lib/active_record/connection_adapters/postgresql/oid/range.rb
index 84b9490ba3..961e6224c4 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql/oid/range.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql/oid/range.rb
@@ -1,3 +1,5 @@
+require 'active_support/core_ext/string/filters'
+
module ActiveRecord
module ConnectionAdapters
module PostgreSQL
@@ -25,10 +27,11 @@ module ActiveRecord
if !infinity?(from) && extracted[:exclude_start]
if from.respond_to?(:succ)
from = from.succ
- ActiveSupport::Deprecation.warn \
- "Excluding the beginning of a Range is only partialy supported " \
- "through `#succ`. This is not reliable and will be removed in " \
- "the future."
+ ActiveSupport::Deprecation.warn(<<-MSG.squish)
+ Excluding the beginning of a Range is only partialy supported
+ through `#succ`. This is not reliable and will be removed in
+ the future.
+ MSG
else
raise ArgumentError, "The Ruby Range object does not support excluding the beginning of a Range. (unsupported value: '#{value}')"
end
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb b/activerecord/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb
index e396ff4a1e..35e699eeda 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb
@@ -4,7 +4,7 @@ module ActiveRecord
module OID # :nodoc:
# This class uses the data from PostgreSQL pg_type table to build
# the OID -> Type mapping.
- # - OID is and integer representing the type.
+ # - OID is an integer representing the type.
# - Type is an OID::Type object.
# This class has side effects on the +store+ passed during initialization.
class TypeMapInitializer # :nodoc:
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/quoting.rb b/activerecord/lib/active_record/connection_adapters/postgresql/quoting.rb
index cf5c8d288e..f95f45c689 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql/quoting.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql/quoting.rb
@@ -21,7 +21,7 @@ module ActiveRecord
case value
when Float
if value.infinite? || value.nan?
- "'#{value.to_s}'"
+ "'#{value}'"
else
super
end
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb b/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb
index 799aafbd99..51853c6812 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb
@@ -293,6 +293,23 @@ module ActiveRecord
result.rows.first.first
end
+ # Sets the sequence of a table's primary key to the specified value.
+ def set_pk_sequence!(table, value) #:nodoc:
+ pk, sequence = pk_and_sequence_for(table)
+
+ if pk
+ if sequence
+ quoted_sequence = quote_table_name(sequence)
+
+ select_value <<-end_sql, 'SCHEMA'
+ SELECT setval('#{quoted_sequence}', #{value})
+ end_sql
+ else
+ @logger.warn "#{table} has primary key #{pk} with no default sequence" if @logger
+ end
+ end
+ end
+
# Resets the sequence of a table's primary key to the maximum value.
def reset_pk_sequence!(table, pk = nil, sequence = nil) #:nodoc:
unless pk and sequence
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
index 3294238fa0..9941f74766 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
@@ -78,6 +78,7 @@ module ActiveRecord
NATIVE_DATABASE_TYPES = {
primary_key: "serial primary key",
+ bigserial: "bigserial",
string: { name: "character varying" },
text: { name: "text" },
integer: { name: "integer" },
@@ -103,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" },
@@ -392,6 +394,16 @@ module ActiveRecord
super(oid)
end
+ def column_name_for_operation(operation, node) # :nodoc:
+ OPERATION_ALIASES.fetch(operation) { operation.downcase }
+ end
+
+ OPERATION_ALIASES = { # :nodoc:
+ "maximum" => "max",
+ "minimum" => "min",
+ "average" => "avg",
+ }
+
protected
# Returns the version of the connected PostgreSQL server.
@@ -678,9 +690,9 @@ module ActiveRecord
variables.map do |k, v|
if v == ':default' || v == :default
# Sets the value to the global or compile default
- execute("SET SESSION #{k.to_s} TO DEFAULT", 'SCHEMA')
+ execute("SET SESSION #{k} TO DEFAULT", 'SCHEMA')
elsif !v.nil?
- execute("SET SESSION #{k.to_s} TO #{quote(v)}", 'SCHEMA')
+ execute("SET SESSION #{k} TO #{quote(v)}", 'SCHEMA')
end
end
end
diff --git a/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb b/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb
index 4756896ac5..1b5e3bdbac 100644
--- a/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb
@@ -115,7 +115,7 @@ module ActiveRecord
end
def clear
- cache.values.each do |hash|
+ cache.each_value do |hash|
dealloc hash[:stmt]
end
cache.clear
diff --git a/activerecord/lib/active_record/connection_handling.rb b/activerecord/lib/active_record/connection_handling.rb
index 31e7390bf7..8f51590c99 100644
--- a/activerecord/lib/active_record/connection_handling.rb
+++ b/activerecord/lib/active_record/connection_handling.rb
@@ -1,6 +1,6 @@
module ActiveRecord
module ConnectionHandling
- RAILS_ENV = -> { Rails.env if defined?(Rails) }
+ RAILS_ENV = -> { (Rails.env if defined?(Rails)) || ENV["RAILS_ENV"] || ENV["RACK_ENV"] }
DEFAULT_ENV = -> { RAILS_ENV.call || "default_env" }
# Establishes the connection to the database. Accepts a hash as input where
diff --git a/activerecord/lib/active_record/core.rb b/activerecord/lib/active_record/core.rb
index 5571a2d297..952aeaa703 100644
--- a/activerecord/lib/active_record/core.rb
+++ b/activerecord/lib/active_record/core.rb
@@ -1,6 +1,7 @@
+require 'thread'
require 'active_support/core_ext/hash/indifferent_access'
require 'active_support/core_ext/object/duplicable'
-require 'thread'
+require 'active_support/core_ext/string/filters'
module ActiveRecord
module Core
@@ -88,8 +89,10 @@ module ActiveRecord
mattr_accessor :maintain_test_schema, instance_accessor: false
def self.disable_implicit_join_references=(value)
- ActiveSupport::Deprecation.warn("Implicit join references were removed with Rails 4.1." \
- "Make sure to remove this configuration because it does nothing.")
+ ActiveSupport::Deprecation.warn(<<-MSG.squish)
+ Implicit join references were removed with Rails 4.1.
+ Make sure to remove this configuration because it does nothing.
+ MSG
end
class_attribute :default_connection_handler, instance_writer: false
@@ -135,8 +138,10 @@ module ActiveRecord
id = ids.first
if ActiveRecord::Base === id
id = id.id
- ActiveSupport::Deprecation.warn "You are passing an instance of ActiveRecord::Base to `find`." \
- "Please pass the id of the object by calling `.id`"
+ ActiveSupport::Deprecation.warn(<<-MSG.squish)
+ You are passing an instance of ActiveRecord::Base to `find`.
+ Please pass the id of the object by calling `.id`
+ MSG
end
key = primary_key
@@ -150,6 +155,8 @@ module ActiveRecord
raise RecordNotFound, "Couldn't find #{name} with '#{primary_key}'=#{id}"
end
record
+ rescue RangeError
+ raise RecordNotFound, "Couldn't find #{name} with an out of range value for '#{primary_key}'"
end
def find_by(*args)
@@ -180,6 +187,8 @@ module ActiveRecord
s.execute(hash.values, self, connection).first
rescue TypeError => e
raise ActiveRecord::StatementInvalid.new(e.message, e)
+ rescue RangeError
+ nil
end
end
@@ -261,7 +270,7 @@ module ActiveRecord
# # Instantiates a single new object
# User.new(first_name: 'Jamie')
def initialize(attributes = nil, options = {})
- @attributes = self.class.default_attributes.dup
+ @attributes = self.class._default_attributes.dup
init_internals
initialize_internals_callback
@@ -272,7 +281,7 @@ module ActiveRecord
init_attributes(attributes, options) if attributes
yield self if block_given?
- run_initialize_callbacks
+ _run_initialize_callbacks
end
# Initialize an empty model object from +coder+. +coder+ must contain
@@ -294,8 +303,8 @@ module ActiveRecord
self.class.define_attribute_methods
- run_find_callbacks
- run_initialize_callbacks
+ _run_find_callbacks
+ _run_initialize_callbacks
self
end
@@ -331,7 +340,7 @@ module ActiveRecord
@attributes = @attributes.dup
@attributes.reset(self.class.primary_key)
- run_initialize_callbacks
+ _run_initialize_callbacks
@aggregation_cache = {}
@association_cache = {}
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/gem_version.rb b/activerecord/lib/active_record/gem_version.rb
index 91747d2ccf..e820835626 100644
--- a/activerecord/lib/active_record/gem_version.rb
+++ b/activerecord/lib/active_record/gem_version.rb
@@ -8,7 +8,7 @@ module ActiveRecord
MAJOR = 4
MINOR = 2
TINY = 0
- PRE = "beta2"
+ PRE = "beta4"
STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".")
end
diff --git a/activerecord/lib/active_record/inheritance.rb b/activerecord/lib/active_record/inheritance.rb
index 251d682a02..f58145ab05 100644
--- a/activerecord/lib/active_record/inheritance.rb
+++ b/activerecord/lib/active_record/inheritance.rb
@@ -80,12 +80,12 @@ module ActiveRecord
end
def symbolized_base_class
- ActiveSupport::Deprecation.warn("ActiveRecord::Base.symbolized_base_class is deprecated and will be removed without replacement.")
+ ActiveSupport::Deprecation.warn('`ActiveRecord::Base.symbolized_base_class` is deprecated and will be removed without replacement.')
@symbolized_base_class ||= base_class.to_s.to_sym
end
def symbolized_sti_name
- ActiveSupport::Deprecation.warn("ActiveRecord::Base.symbolized_sti_name is deprecated and will be removed without replacement.")
+ ActiveSupport::Deprecation.warn('`ActiveRecord::Base.symbolized_sti_name` is deprecated and will be removed without replacement.')
@symbolized_sti_name ||= sti_name.present? ? sti_name.to_sym : symbolized_base_class
end
diff --git a/activerecord/lib/active_record/migration.rb b/activerecord/lib/active_record/migration.rb
index d0d9304a36..2024b225e4 100644
--- a/activerecord/lib/active_record/migration.rb
+++ b/activerecord/lib/active_record/migration.rb
@@ -394,8 +394,8 @@ module ActiveRecord
end
def load_schema_if_pending!
- if ActiveRecord::Migrator.needs_migration?
- ActiveRecord::Tasks::DatabaseTasks.load_schema_current
+ if ActiveRecord::Migrator.needs_migration? || !ActiveRecord::Migrator.any_migrations?
+ ActiveRecord::Tasks::DatabaseTasks.load_schema_current_if_exists
check_pending!
end
end
@@ -848,6 +848,10 @@ module ActiveRecord
(migrations(migrations_paths).collect(&:version) - get_all_versions(connection)).size > 0
end
+ def any_migrations?
+ migrations(migrations_paths).any?
+ end
+
def last_version
last_migration.version
end
diff --git a/activerecord/lib/active_record/model_schema.rb b/activerecord/lib/active_record/model_schema.rb
index 48e82d28d9..a444aac23c 100644
--- a/activerecord/lib/active_record/model_schema.rb
+++ b/activerecord/lib/active_record/model_schema.rb
@@ -247,12 +247,12 @@ module ActiveRecord
# Returns a hash where the keys are column names and the values are
# default values when instantiating the AR object for this table.
def column_defaults
- default_attributes.to_hash
+ _default_attributes.to_hash
end
- def default_attributes # :nodoc:
+ def _default_attributes # :nodoc:
@default_attributes ||= attributes_builder.build_from_database(
- columns_hash.transform_values(&:default))
+ raw_default_values)
end
# Returns an array of column names as strings.
@@ -331,6 +331,10 @@ module ActiveRecord
base.table_name
end
end
+
+ def raw_default_values
+ columns_hash.transform_values(&:default)
+ end
end
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/reflection.rb b/activerecord/lib/active_record/reflection.rb
index 22aa175ce2..4b58f2deb7 100644
--- a/activerecord/lib/active_record/reflection.rb
+++ b/activerecord/lib/active_record/reflection.rb
@@ -1,4 +1,5 @@
require 'thread'
+require 'active_support/core_ext/string/filters'
module ActiveRecord
# = Active Record Reflection
@@ -153,8 +154,11 @@ module ActiveRecord
end
def source_macro
- ActiveSupport::Deprecation.warn("ActiveRecord::Base.source_macro is deprecated and " \
- "will be removed without replacement.")
+ ActiveSupport::Deprecation.warn(<<-MSG.squish)
+ ActiveRecord::Base.source_macro is deprecated and will be removed
+ without replacement.
+ MSG
+
macro
end
end
@@ -339,13 +343,14 @@ module ActiveRecord
return unless scope
if scope.arity > 0
- ActiveSupport::Deprecation.warn \
- "The association scope '#{name}' is instance dependent (the scope " \
- "block takes an argument). Preloading happens before the individual " \
- "instances are created. This means that there is no instance being " \
- "passed to the association scope. This will most likely result in " \
- "broken or incorrect behavior. Joining, Preloading and eager loading " \
- "of these associations is deprecated and will be removed in the future."
+ ActiveSupport::Deprecation.warn(<<-MSG.squish)
+ The association scope '#{name}' is instance dependent (the scope
+ block takes an argument). Preloading happens before the individual
+ instances are created. This means that there is no instance being
+ passed to the association scope. This will most likely result in
+ broken or incorrect behavior. Joining, Preloading and eager loading
+ of these associations is deprecated and will be removed in the future.
+ MSG
end
end
alias :check_eager_loadable! :check_preloadable!
@@ -746,8 +751,11 @@ module ActiveRecord
# The macro used by the source association
def source_macro
- ActiveSupport::Deprecation.warn("ActiveRecord::Base.source_macro is deprecated and " \
- "will be removed without replacement.")
+ ActiveSupport::Deprecation.warn(<<-MSG.squish)
+ ActiveRecord::Base.source_macro is deprecated and will be removed
+ without replacement.
+ MSG
+
source_reflection.source_macro
end
diff --git a/activerecord/lib/active_record/relation.rb b/activerecord/lib/active_record/relation.rb
index 7f51e4134d..03bce4f5b7 100644
--- a/activerecord/lib/active_record/relation.rb
+++ b/activerecord/lib/active_record/relation.rb
@@ -79,22 +79,27 @@ module ActiveRecord
scope.unscope!(where: @klass.inheritance_column)
end
- um = scope.where(@klass.arel_table[@klass.primary_key].eq(id_was || id)).arel.compile_update(substitutes, @klass.primary_key)
+ relation = scope.where(@klass.primary_key => (id_was || id))
+ bvs = binds + relation.bind_values
+ um = relation
+ .arel
+ .compile_update(substitutes, @klass.primary_key)
+ reorder_bind_params(um.ast, bvs)
@klass.connection.update(
um,
'SQL',
- binds)
+ bvs,
+ )
end
def substitute_values(values) # :nodoc:
- substitutes = values.sort_by { |arel_attr,_| arel_attr.name }
- binds = substitutes.map do |arel_attr, value|
+ binds = values.map do |arel_attr, value|
[@klass.columns_hash[arel_attr.name], value]
end
- substitutes.each_with_index do |tuple, i|
- tuple[1] = @klass.connection.substitute_at(binds[i][0], i)
+ substitutes = values.each_with_index.map do |(arel_attr, _), i|
+ [arel_attr, @klass.connection.substitute_at(binds[i][0], i)]
end
[substitutes, binds]
@@ -337,7 +342,7 @@ module ActiveRecord
stmt.wheres = arel.constraints
end
- bvs = bind_values + arel.bind_values
+ bvs = arel.bind_values + bind_values
@klass.connection.update stmt, 'SQL', bvs
end
diff --git a/activerecord/lib/active_record/relation/calculations.rb b/activerecord/lib/active_record/relation/calculations.rb
index eaaa409636..c8ebb41131 100644
--- a/activerecord/lib/active_record/relation/calculations.rb
+++ b/activerecord/lib/active_record/relation/calculations.rb
@@ -254,6 +254,7 @@ module ActiveRecord
select_value = operation_over_aggregate_column(column, operation, distinct)
column_alias = select_value.alias
+ column_alias ||= @klass.connection.column_name_for_operation(operation, select_value)
relation.select_values = [select_value]
query_builder = relation.arel
diff --git a/activerecord/lib/active_record/relation/finder_methods.rb b/activerecord/lib/active_record/relation/finder_methods.rb
index c95ec2522b..eacae73ebb 100644
--- a/activerecord/lib/active_record/relation/finder_methods.rb
+++ b/activerecord/lib/active_record/relation/finder_methods.rb
@@ -1,4 +1,5 @@
require 'active_support/deprecation'
+require 'active_support/core_ext/string/filters'
module ActiveRecord
module FinderMethods
@@ -81,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
@@ -284,8 +289,10 @@ module ActiveRecord
def exists?(conditions = :none)
if Base === conditions
conditions = conditions.id
- ActiveSupport::Deprecation.warn "You are passing an instance of ActiveRecord::Base to `exists?`." \
- "Please pass the id of the object by calling `.id`"
+ ActiveSupport::Deprecation.warn(<<-MSG.squish)
+ You are passing an instance of ActiveRecord::Base to `exists?`.
+ Please pass the id of the object by calling `.id`
+ MSG
end
return false if !conditions
@@ -430,19 +437,20 @@ module ActiveRecord
else
find_some(ids)
end
+ rescue RangeError
+ raise RecordNotFound, "Couldn't find #{@klass.name} with an out of range ID"
end
def find_one(id)
if ActiveRecord::Base === id
id = id.id
- ActiveSupport::Deprecation.warn "You are passing an instance of ActiveRecord::Base to `find`." \
- "Please pass the id of the object by calling `.id`"
+ ActiveSupport::Deprecation.warn(<<-MSG.squish)
+ You are passing an instance of ActiveRecord::Base to `find`.
+ Please pass the id of the object by calling `.id`
+ MSG
end
- column = columns_hash[primary_key]
- substitute = connection.substitute_at(column, bind_values.length)
- relation = where(table[primary_key].eq(substitute))
- relation.bind_values += [[column, id]]
+ relation = where(primary_key => id)
record = relation.take
raise_record_not_found_exception!(id, 0, 1) unless record
@@ -451,7 +459,7 @@ module ActiveRecord
end
def find_some(ids)
- result = where(table[primary_key].in(ids)).to_a
+ result = where(primary_key => ids).to_a
expected_size =
if limit_value && ids.size > limit_value
diff --git a/activerecord/lib/active_record/relation/merger.rb b/activerecord/lib/active_record/relation/merger.rb
index 545bf5debc..a8febf6a18 100644
--- a/activerecord/lib/active_record/relation/merger.rb
+++ b/activerecord/lib/active_record/relation/merger.rb
@@ -83,12 +83,12 @@ module ActiveRecord
private
def merge_joins
- return if values[:joins].blank?
+ return if other.joins_values.blank?
if other.klass == relation.klass
- relation.joins!(*values[:joins])
+ relation.joins!(*other.joins_values)
else
- joins_dependency, rest = values[:joins].partition do |join|
+ joins_dependency, rest = other.joins_values.partition do |join|
case join
when Hash, Symbol, Array
true
@@ -108,10 +108,10 @@ module ActiveRecord
def merge_multi_values
lhs_wheres = relation.where_values
- rhs_wheres = values[:where] || []
+ rhs_wheres = other.where_values
lhs_binds = relation.bind_values
- rhs_binds = values[:bind] || []
+ rhs_binds = other.bind_values
removed, kept = partition_overwrites(lhs_wheres, rhs_wheres)
@@ -133,23 +133,23 @@ module ActiveRecord
relation.where_values = where_values
relation.bind_values = bind_values
- if values[:reordering]
+ if other.reordering_value
# override any order specified in the original relation
- relation.reorder! values[:order]
- elsif values[:order]
+ relation.reorder! other.order_values
+ elsif other.order_values
# merge in order_values from relation
- relation.order! values[:order]
+ relation.order! other.order_values
end
- relation.extend(*values[:extending]) unless values[:extending].blank?
+ relation.extend(*other.extending_values) unless other.extending_values.blank?
end
def merge_single_values
- relation.from_value = values[:from] unless relation.from_value
- relation.lock_value = values[:lock] unless relation.lock_value
+ relation.from_value = other.from_value unless relation.from_value
+ relation.lock_value = other.lock_value unless relation.lock_value
- unless values[:create_with].blank?
- relation.create_with_value = (relation.create_with_value || {}).merge(values[:create_with])
+ unless other.create_with_value.blank?
+ relation.create_with_value = (relation.create_with_value || {}).merge(other.create_with_value)
end
end
diff --git a/activerecord/lib/active_record/relation/predicate_builder.rb b/activerecord/lib/active_record/relation/predicate_builder.rb
index 3df0df40ee..e4b6b49087 100644
--- a/activerecord/lib/active_record/relation/predicate_builder.rb
+++ b/activerecord/lib/active_record/relation/predicate_builder.rb
@@ -109,7 +109,7 @@ module ActiveRecord
# FIXME: I think we need to deprecate this behavior
register_handler(Class, ->(attribute, value) { attribute.eq(value.name) })
register_handler(Base, ->(attribute, value) { attribute.eq(value.id) })
- register_handler(Range, ->(attribute, value) { attribute.in(value) })
+ register_handler(Range, ->(attribute, value) { attribute.between(value) })
register_handler(Relation, RelationHandler.new)
register_handler(Array, ArrayHandler.new)
diff --git a/activerecord/lib/active_record/relation/predicate_builder/array_handler.rb b/activerecord/lib/active_record/relation/predicate_builder/array_handler.rb
index b8d9240bf8..b8f3285c3e 100644
--- a/activerecord/lib/active_record/relation/predicate_builder/array_handler.rb
+++ b/activerecord/lib/active_record/relation/predicate_builder/array_handler.rb
@@ -1,3 +1,5 @@
+require 'active_support/core_ext/string/filters'
+
module ActiveRecord
class PredicateBuilder
class ArrayHandler # :nodoc:
@@ -6,9 +8,12 @@ module ActiveRecord
nils, values = values.partition(&:nil?)
if values.any? { |val| val.is_a?(Array) }
- ActiveSupport::Deprecation.warn "Passing a nested array to Active Record " \
- "finder methods is deprecated and will be removed. Flatten your array " \
- "before using it for 'IN' conditions."
+ ActiveSupport::Deprecation.warn(<<-MSG.squish)
+ Passing a nested array to Active Record finder methods is
+ deprecated and will be removed. Flatten your array before using
+ it for 'IN' conditions.
+ MSG
+
values = values.flatten
end
@@ -27,7 +32,7 @@ module ActiveRecord
values_predicate = values_predicate.or(attribute.eq(nil))
end
- array_predicates = ranges.map { |range| attribute.in(range) }
+ array_predicates = ranges.map { |range| attribute.between(range) }
array_predicates.unshift(values_predicate)
array_predicates.inject { |composite, predicate| composite.or(predicate) }
end
diff --git a/activerecord/lib/active_record/relation/predicate_builder/relation_handler.rb b/activerecord/lib/active_record/relation/predicate_builder/relation_handler.rb
index 618fa3cdd9..063150958a 100644
--- a/activerecord/lib/active_record/relation/predicate_builder/relation_handler.rb
+++ b/activerecord/lib/active_record/relation/predicate_builder/relation_handler.rb
@@ -6,7 +6,7 @@ module ActiveRecord
value = value.select(value.klass.arel_table[value.klass.primary_key])
end
- attribute.in(value.arel.ast)
+ attribute.in(value.arel)
end
end
end
diff --git a/activerecord/lib/active_record/relation/query_methods.rb b/activerecord/lib/active_record/relation/query_methods.rb
index bbddd28ccc..a686e3263b 100644
--- a/activerecord/lib/active_record/relation/query_methods.rb
+++ b/activerecord/lib/active_record/relation/query_methods.rb
@@ -1,4 +1,5 @@
require 'active_support/core_ext/array/wrap'
+require 'active_support/core_ext/string/filters'
require 'active_model/forbidden_attributes_protection'
module ActiveRecord
@@ -94,8 +95,10 @@ module ActiveRecord
def check_cached_relation # :nodoc:
if defined?(@arel) && @arel
@arel = nil
- ActiveSupport::Deprecation.warn "Modifying already cached Relation. The " \
- "cache will be reset. Use a cloned Relation to prevent this warning."
+ ActiveSupport::Deprecation.warn(<<-MSG.squish)
+ Modifying already cached Relation. The cache will be reset. Use a
+ cloned Relation to prevent this warning.
+ MSG
end
end
@@ -436,7 +439,7 @@ module ActiveRecord
self
end
- def bind(value)
+ def bind(value) # :nodoc:
spawn.bind!(value)
end
@@ -880,12 +883,15 @@ module ActiveRecord
# Reorder bind indexes if joins produced bind values
bvs = arel.bind_values + bind_values
- arel.ast.grep(Arel::Nodes::BindParam).each_with_index do |bp, i|
+ reorder_bind_params(arel.ast, bvs)
+ arel
+ end
+
+ def reorder_bind_params(ast, bvs)
+ ast.grep(Arel::Nodes::BindParam).each_with_index do |bp, i|
column = bvs[i].first
bp.replace connection.substitute_at(column, i)
end
-
- arel
end
def symbol_unscoping(scope)
@@ -913,7 +919,7 @@ module ActiveRecord
where_values.reject! do |rel|
case rel
- when Arel::Nodes::In, Arel::Nodes::NotIn, Arel::Nodes::Equality, Arel::Nodes::NotEqual
+ when Arel::Nodes::Between, Arel::Nodes::In, Arel::Nodes::NotIn, Arel::Nodes::Equality, Arel::Nodes::NotEqual, Arel::Nodes::LessThanOrEqual, Arel::Nodes::GreaterThanOrEqual
subrelation = (rel.left.kind_of?(Arel::Attributes::Attribute) ? rel.left : rel.right)
subrelation.name == target_value
end
@@ -955,8 +961,7 @@ module ActiveRecord
when Hash
opts = PredicateBuilder.resolve_column_aliases(klass, opts)
- bv_len = bind_values.length
- tmp_opts, bind_values = create_binds(opts, bv_len)
+ tmp_opts, bind_values = create_binds(opts)
self.bind_values += bind_values
attributes = @klass.send(:expand_hash_conditions_for_aggregates, tmp_opts)
@@ -968,7 +973,7 @@ module ActiveRecord
end
end
- def create_binds(opts, idx)
+ def create_binds(opts)
bindable, non_binds = opts.partition do |column, value|
case value
when String, Integer, ActiveRecord::StatementCache::Substitute
@@ -978,12 +983,23 @@ module ActiveRecord
end
end
+ association_binds, non_binds = non_binds.partition do |column, value|
+ value.is_a?(Hash) && association_for_table(column)
+ end
+
new_opts = {}
binds = []
- bindable.each_with_index do |(column,value), index|
+ bindable.each do |(column,value)|
binds.push [@klass.columns_hash[column.to_s], value]
- new_opts[column] = connection.substitute_at(column, index + idx)
+ new_opts[column] = connection.substitute_at(column)
+ end
+
+ association_binds.each do |(column, value)|
+ association_relation = association_for_table(column).klass.send(:relation)
+ association_new_opts, association_bind = association_relation.send(:create_binds, value)
+ new_opts[column] = association_new_opts
+ binds += association_bind
end
non_binds.each { |column,value| new_opts[column] = value }
@@ -991,6 +1007,12 @@ module ActiveRecord
[new_opts, binds]
end
+ def association_for_table(table_name)
+ table_name = table_name.to_s
+ @klass._reflect_on_association(table_name) ||
+ @klass._reflect_on_association(table_name.singularize)
+ end
+
def build_from
opts, name = from_value
case opts
diff --git a/activerecord/lib/active_record/sanitization.rb b/activerecord/lib/active_record/sanitization.rb
index ff70cbed0f..6a130c145b 100644
--- a/activerecord/lib/active_record/sanitization.rb
+++ b/activerecord/lib/active_record/sanitization.rb
@@ -87,6 +87,9 @@ module ActiveRecord
# { address: Address.new("123 abc st.", "chicago") }
# # => "address_street='123 abc st.' and address_city='chicago'"
def sanitize_sql_hash_for_conditions(attrs, default_table_name = self.table_name)
+ ActiveSupport::Deprecation.warn(<<-EOWARN)
+sanitize_sql_hash_for_conditions is deprecated, and will be removed in Rails 5.0
+ EOWARN
attrs = PredicateBuilder.resolve_column_aliases self, attrs
attrs = expand_hash_conditions_for_aggregates(attrs)
@@ -134,7 +137,7 @@ module ActiveRecord
raise_if_bind_arity_mismatch(statement, statement.count('?'), values.size)
bound = values.dup
c = connection
- statement.gsub('?') do
+ statement.gsub(/\?/) do
replace_bind_variable(bound.shift, c)
end
end
diff --git a/activerecord/lib/active_record/schema_dumper.rb b/activerecord/lib/active_record/schema_dumper.rb
index 82c5ca291c..261fb9d992 100644
--- a/activerecord/lib/active_record/schema_dumper.rb
+++ b/activerecord/lib/active_record/schema_dumper.rb
@@ -118,6 +118,8 @@ HEADER
if pkcol
if pk != 'id'
tbl.print %Q(, primary_key: "#{pk}")
+ elsif pkcol.sql_type == 'bigint'
+ tbl.print ", id: :bigserial"
elsif pkcol.sql_type == 'uuid'
tbl.print ", id: :uuid"
tbl.print %Q(, default: "#{pkcol.default_function}") if pkcol.default_function
diff --git a/activerecord/lib/active_record/scoping/named.rb b/activerecord/lib/active_record/scoping/named.rb
index 49cadb66d0..ec1edf0e01 100644
--- a/activerecord/lib/active_record/scoping/named.rb
+++ b/activerecord/lib/active_record/scoping/named.rb
@@ -139,6 +139,10 @@ module ActiveRecord
# Article.published.featured.latest_article
# Article.featured.titles
def scope(name, body, &block)
+ unless body.respond_to?:call
+ raise ArgumentError, 'The scope body needs to be callable.'
+ end
+
if dangerous_class_method?(name)
raise ArgumentError, "You tried to define a scope named \"#{name}\" " \
"on the model \"#{self.name}\", but Active Record already defined " \
diff --git a/activerecord/lib/active_record/tasks/database_tasks.rb b/activerecord/lib/active_record/tasks/database_tasks.rb
index f9b54139d5..1228de2bfd 100644
--- a/activerecord/lib/active_record/tasks/database_tasks.rb
+++ b/activerecord/lib/active_record/tasks/database_tasks.rb
@@ -1,3 +1,5 @@
+require 'active_support/core_ext/string/filters'
+
module ActiveRecord
module Tasks # :nodoc:
class DatabaseAlreadyExists < StandardError; end # :nodoc:
@@ -187,25 +189,35 @@ module ActiveRecord
end
def load_schema(format = ActiveRecord::Base.schema_format, file = nil)
- ActiveSupport::Deprecation.warn \
- "This method will act on a specific connection in the future. " \
- "To act on the current connection, use `load_schema_current` instead."
+ ActiveSupport::Deprecation.warn(<<-MSG.squish)
+ This method will act on a specific connection in the future.
+ To act on the current connection, use `load_schema_current` instead.
+ MSG
load_schema_current(format, file)
end
+ def schema_file(format = ActiveSupport::Base.schema_format)
+ case format
+ when :ruby
+ File.join(db_dir, "schema.rb")
+ when :sql
+ File.join(db_dir, "structure.sql")
+ end
+ end
+
# This method is the successor of +load_schema+. We should rename it
# after +load_schema+ went through a deprecation cycle. (Rails > 4.2)
def load_schema_for(configuration, format = ActiveRecord::Base.schema_format, file = nil) # :nodoc:
+ file ||= schema_file(format)
+
case format
when :ruby
- file ||= File.join(db_dir, "schema.rb")
check_schema_file(file)
purge(configuration)
ActiveRecord::Base.establish_connection(configuration)
load(file)
when :sql
- file ||= File.join(db_dir, "structure.sql")
check_schema_file(file)
purge(configuration)
structure_load(configuration, file)
@@ -214,6 +226,12 @@ module ActiveRecord
end
end
+ def load_schema_current_if_exists(format = ActiveRecord::Base.schema_format, file = nil, environment = env)
+ if File.exist?(file || schema_file(format))
+ load_schema_current(format, file, environment)
+ end
+ end
+
def load_schema_current(format = ActiveRecord::Base.schema_format, file = nil, environment = env)
each_current_configuration(environment) { |configuration|
load_schema_for configuration, format, file
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/transactions.rb b/activerecord/lib/active_record/transactions.rb
index bb06d0304b..f92e1de03b 100644
--- a/activerecord/lib/active_record/transactions.rb
+++ b/activerecord/lib/active_record/transactions.rb
@@ -309,7 +309,7 @@ module ActiveRecord
# Ensure that it is not called if the object was never persisted (failed create),
# but call it after the commit of a destroyed object.
def committed!(should_run_callbacks = true) #:nodoc:
- run_commit_callbacks if should_run_callbacks && destroyed? || persisted?
+ _run_commit_callbacks if should_run_callbacks && destroyed? || persisted?
ensure
force_clear_transaction_record_state
end
@@ -317,7 +317,7 @@ module ActiveRecord
# Call the +after_rollback+ callbacks. The +force_restore_state+ argument indicates if the record
# state should be rolled back to the beginning or just to the last savepoint.
def rolledback!(force_restore_state = false, should_run_callbacks = true) #:nodoc:
- run_rollback_callbacks if should_run_callbacks
+ _run_rollback_callbacks if should_run_callbacks
ensure
restore_transaction_record_state(force_restore_state)
clear_transaction_record_state
diff --git a/activerecord/lib/active_record/type.rb b/activerecord/lib/active_record/type.rb
index e3d6c5957e..e5acbbb6b3 100644
--- a/activerecord/lib/active_record/type.rb
+++ b/activerecord/lib/active_record/type.rb
@@ -4,6 +4,7 @@ require 'active_record/type/numeric'
require 'active_record/type/time_value'
require 'active_record/type/value'
+require 'active_record/type/big_integer'
require 'active_record/type/binary'
require 'active_record/type/boolean'
require 'active_record/type/date'
diff --git a/activerecord/lib/active_record/type/big_integer.rb b/activerecord/lib/active_record/type/big_integer.rb
new file mode 100644
index 0000000000..0c72d8914f
--- /dev/null
+++ b/activerecord/lib/active_record/type/big_integer.rb
@@ -0,0 +1,13 @@
+require 'active_record/type/integer'
+
+module ActiveRecord
+ module Type
+ class BigInteger < Integer # :nodoc:
+ private
+
+ def max_value
+ ::Float::INFINITY
+ end
+ end
+ end
+end
diff --git a/activerecord/lib/active_record/type/boolean.rb b/activerecord/lib/active_record/type/boolean.rb
index 1311be3944..978d16d524 100644
--- a/activerecord/lib/active_record/type/boolean.rb
+++ b/activerecord/lib/active_record/type/boolean.rb
@@ -14,9 +14,13 @@ module ActiveRecord
true
else
if !ConnectionAdapters::Column::FALSE_VALUES.include?(value)
- ActiveSupport::Deprecation.warn(<<-EOM)
- You attempted to assign a value which is not explicitly true or false to a boolean column. Currently this value casts to false. This will change to match Ruby's sematics, and will cast to true in Rails 5.0. If you would like to maintain the current behavior, you should explicitly handle the values you would like cast to false.
- EOM
+ ActiveSupport::Deprecation.warn(<<-MSG.squish)
+ You attempted to assign a value which is not explicitly `true` or `false`
+ to a boolean column. Currently this value casts to `false`. This will
+ change to match Ruby's semantics, and will cast to `true` in Rails 5.
+ If you would like to maintain the current behavior, you should
+ explicitly handle the values you would like cast to `false`.
+ MSG
end
false
end
diff --git a/activerecord/lib/active_record/type/decimal_without_scale.rb b/activerecord/lib/active_record/type/decimal_without_scale.rb
index cabdcecdd7..ff5559e300 100644
--- a/activerecord/lib/active_record/type/decimal_without_scale.rb
+++ b/activerecord/lib/active_record/type/decimal_without_scale.rb
@@ -1,8 +1,8 @@
-require 'active_record/type/integer'
+require 'active_record/type/big_integer'
module ActiveRecord
module Type
- class DecimalWithoutScale < Integer # :nodoc:
+ class DecimalWithoutScale < BigInteger # :nodoc:
def type
:decimal
end
diff --git a/activerecord/lib/active_record/type/integer.rb b/activerecord/lib/active_record/type/integer.rb
index 08477d1303..d69e5b3f28 100644
--- a/activerecord/lib/active_record/type/integer.rb
+++ b/activerecord/lib/active_record/type/integer.rb
@@ -3,21 +3,44 @@ module ActiveRecord
class Integer < Value # :nodoc:
include Numeric
+ def initialize(*)
+ super
+ @range = -max_value...max_value
+ end
+
def type
:integer
end
alias type_cast_for_database type_cast
+ protected
+
+ attr_reader :range
+
private
def cast_value(value)
case value
when true then 1
when false then 0
- else value.to_i rescue nil
+ else
+ result = value.to_i rescue nil
+ ensure_in_range(result) if result
+ result
end
end
+
+ def ensure_in_range(value)
+ unless range.cover?(value)
+ raise RangeError, "#{value} is too large for #{self.class} with limit #{limit || 4}"
+ end
+ end
+
+ def max_value
+ limit = self.limit || 4
+ 1 << (limit * 8 - 1) # 8 bits per byte with one bit for sign
+ end
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..7a9fdd45e8 100644
--- a/activerecord/test/cases/adapters/postgresql/json_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/json_test.rb
@@ -3,8 +3,11 @@
require "cases/helper"
require 'active_record/base'
require 'active_record/connection_adapters/postgresql_adapter'
+require 'support/schema_dumping_helper'
module PostgresqlJSONSharedTestCases
+ include SchemaDumpingHelper
+
class JsonDataType < ActiveRecord::Base
self.table_name = 'json_data_type'
@@ -64,6 +67,11 @@ module PostgresqlJSONSharedTestCases
JsonDataType.reset_column_information
end
+ def test_schema_dumping
+ output = dump_table_schema("json_data_type")
+ assert_match(/t.#{column_type.to_s}\s+"payload",\s+default: {}/, output)
+ end
+
def test_cast_value_on_write
x = JsonDataType.new payload: {"string" => "foo", :symbol => :bar}
assert_equal({"string" => "foo", :symbol => :bar}, x.payload_before_type_cast)
diff --git a/activerecord/test/cases/adapters/postgresql/schema_test.rb b/activerecord/test/cases/adapters/postgresql/schema_test.rb
index 6f40b0d2de..350cb3e065 100644
--- a/activerecord/test/cases/adapters/postgresql/schema_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/schema_test.rb
@@ -388,6 +388,14 @@ class SchemaTest < ActiveRecord::TestCase
assert_equal "1", @connection.select_value("SELECT nextval('#{sequence_name}')")
end
+ def test_set_pk_sequence
+ table_name = "#{SCHEMA_NAME}.#{PK_TABLE_NAME}"
+ _, sequence_name = @connection.pk_and_sequence_for table_name
+ @connection.set_pk_sequence! table_name, 123
+ assert_equal "124", @connection.select_value("SELECT nextval('#{sequence_name}')")
+ @connection.reset_pk_sequence! table_name
+ end
+
private
def columns(table_name)
@connection.send(:column_definitions, table_name).map do |name, type, default|
diff --git a/activerecord/test/cases/adapters/postgresql/uuid_test.rb b/activerecord/test/cases/adapters/postgresql/uuid_test.rb
index ae5b409f99..376dc2490e 100644
--- a/activerecord/test/cases/adapters/postgresql/uuid_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/uuid_test.rb
@@ -110,6 +110,26 @@ class PostgresqlUUIDTest < ActiveRecord::TestCase
end
end
+class PostgresqlLargeKeysTest < ActiveRecord::TestCase
+ include PostgresqlUUIDHelper
+ def setup
+ connection.create_table('big_serials', id: :bigserial) do |t|
+ t.string 'name'
+ end
+ end
+
+ def test_omg
+ schema = StringIO.new
+ ActiveRecord::SchemaDumper.dump(connection, schema)
+ assert_match "create_table \"big_serials\", id: :bigserial, force: true",
+ schema.string
+ end
+
+ def teardown
+ drop_table "big_serials"
+ end
+end
+
class PostgresqlUUIDGenerationTest < ActiveRecord::TestCase
include PostgresqlUUIDHelper
diff --git a/activerecord/test/cases/attributes_test.rb b/activerecord/test/cases/attributes_test.rb
index 79ef0502cb..dbe1eb48db 100644
--- a/activerecord/test/cases/attributes_test.rb
+++ b/activerecord/test/cases/attributes_test.rb
@@ -20,7 +20,7 @@ end
module ActiveRecord
class CustomPropertiesTest < ActiveRecord::TestCase
- def test_overloading_types
+ test "overloading types" do
data = OverloadedType.new
data.overloaded_float = "1.1"
@@ -30,7 +30,7 @@ module ActiveRecord
assert_equal 1.1, data.unoverloaded_float
end
- def test_overloaded_properties_save
+ test "overloaded properties save" do
data = OverloadedType.new
data.overloaded_float = "2.2"
@@ -43,18 +43,18 @@ module ActiveRecord
assert_kind_of Float, UnoverloadedType.last.overloaded_float
end
- def test_properties_assigned_in_constructor
+ test "properties assigned in constructor" do
data = OverloadedType.new(overloaded_float: '3.3')
assert_equal 3, data.overloaded_float
end
- def test_overloaded_properties_with_limit
+ test "overloaded properties with limit" do
assert_equal 50, OverloadedType.columns_hash['overloaded_string_with_limit'].limit
assert_equal 255, UnoverloadedType.columns_hash['overloaded_string_with_limit'].limit
end
- def test_nonexistent_attribute
+ test "nonexistent attribute" do
data = OverloadedType.new(non_existent_decimal: 1)
assert_equal BigDecimal.new(1), data.non_existent_decimal
@@ -63,7 +63,7 @@ module ActiveRecord
end
end
- def test_changing_defaults
+ test "changing defaults" do
data = OverloadedType.new
unoverloaded_data = UnoverloadedType.new
@@ -71,24 +71,28 @@ module ActiveRecord
assert_equal 'the original default', unoverloaded_data.string_with_default
end
- def test_children_inherit_custom_properties
+ test "defaults are not touched on the columns" do
+ assert_equal 'the original default', OverloadedType.columns_hash['string_with_default'].default
+ end
+
+ test "children inherit custom properties" do
data = ChildOfOverloadedType.new(overloaded_float: '4.4')
assert_equal 4, data.overloaded_float
end
- def test_children_can_override_parents
+ test "children can override parents" do
data = GrandchildOfOverloadedType.new(overloaded_float: '4.4')
assert_equal 4.4, data.overloaded_float
end
- def test_overloading_properties_does_not_change_column_order
+ test "overloading properties does not change column order" do
column_names = OverloadedType.column_names
assert_equal %w(id overloaded_float unoverloaded_float overloaded_string_with_limit string_with_default non_existent_decimal), column_names
end
- def test_caches_are_cleared
+ test "caches are cleared" do
klass = Class.new(OverloadedType)
assert_equal 6, klass.columns.length
diff --git a/activerecord/test/cases/base_test.rb b/activerecord/test/cases/base_test.rb
index fb535e74fc..3675401555 100644
--- a/activerecord/test/cases/base_test.rb
+++ b/activerecord/test/cases/base_test.rb
@@ -522,6 +522,10 @@ class BasicsTest < ActiveRecord::TestCase
assert_equal Topic.find(['1-meowmeow', '2-hello']), Topic.find([1, 2])
end
+ def test_find_by_slug_with_range
+ assert_equal Topic.where(id: '1-meowmeow'..'2-hello'), Topic.where(id: 1..2)
+ end
+
def test_equality_of_new_records
assert_not_equal Topic.new, Topic.new
assert_equal false, Topic.new == Topic.new
@@ -985,7 +989,6 @@ class BasicsTest < ActiveRecord::TestCase
class NumericData < ActiveRecord::Base
self.table_name = 'numeric_data'
- attribute :world_population, Type::Integer.new
attribute :my_house_population, Type::Integer.new
attribute :atoms_in_universe, Type::Integer.new
end
@@ -1383,7 +1386,10 @@ class BasicsTest < ActiveRecord::TestCase
c1 = Post.connection.schema_cache.columns('posts')
ActiveRecord::Base.clear_cache!
c2 = Post.connection.schema_cache.columns('posts')
- assert_not_equal c1, c2
+ c1.each_with_index do |v, i|
+ assert_not_same v, c2[i]
+ end
+ assert_equal c1, c2
end
def test_current_scope_is_reset
diff --git a/activerecord/test/cases/calculations_test.rb b/activerecord/test/cases/calculations_test.rb
index ec6a319ab5..e886268a72 100644
--- a/activerecord/test/cases/calculations_test.rb
+++ b/activerecord/test/cases/calculations_test.rb
@@ -461,7 +461,6 @@ class CalculationsTest < ActiveRecord::TestCase
assert_equal 7, Company.includes(:contracts).sum(:developer_id)
end
-
def test_from_option_with_specified_index
if Edge.connection.adapter_name == 'MySQL' or Edge.connection.adapter_name == 'Mysql2'
assert_equal Edge.count(:all), Edge.from('edges USE INDEX(unique_edge_index)').count(:all)
diff --git a/activerecord/test/cases/connection_adapters/merge_and_resolve_default_url_config_test.rb b/activerecord/test/cases/connection_adapters/merge_and_resolve_default_url_config_test.rb
index e1b2804a18..37ad469476 100644
--- a/activerecord/test/cases/connection_adapters/merge_and_resolve_default_url_config_test.rb
+++ b/activerecord/test/cases/connection_adapters/merge_and_resolve_default_url_config_test.rb
@@ -5,10 +5,14 @@ module ActiveRecord
class MergeAndResolveDefaultUrlConfigTest < ActiveRecord::TestCase
def setup
@previous_database_url = ENV.delete("DATABASE_URL")
+ @previous_rack_env = ENV.delete("RACK_ENV")
+ @previous_rails_env = ENV.delete("RAILS_ENV")
end
teardown do
ENV["DATABASE_URL"] = @previous_database_url
+ ENV["RACK_ENV"] = @previous_rack_env
+ ENV["RAILS_ENV"] = @previous_rails_env
end
def resolve_config(config)
@@ -27,6 +31,26 @@ module ActiveRecord
assert_equal expected, actual
end
+ def test_resolver_with_database_uri_and_current_env_symbol_key_and_rails_env
+ ENV['DATABASE_URL'] = "postgres://localhost/foo"
+ ENV['RAILS_ENV'] = "foo"
+
+ config = { "not_production" => { "adapter" => "not_postgres", "database" => "not_foo" } }
+ actual = resolve_spec(:foo, config)
+ expected = { "adapter" => "postgresql", "database" => "foo", "host" => "localhost" }
+ assert_equal expected, actual
+ end
+
+ def test_resolver_with_database_uri_and_current_env_symbol_key_and_rack_env
+ ENV['DATABASE_URL'] = "postgres://localhost/foo"
+ ENV['RACK_ENV'] = "foo"
+
+ config = { "not_production" => { "adapter" => "not_postgres", "database" => "not_foo" } }
+ actual = resolve_spec(:foo, config)
+ expected = { "adapter" => "postgresql", "database" => "foo", "host" => "localhost" }
+ assert_equal expected, actual
+ end
+
def test_resolver_with_database_uri_and_and_current_env_string_key
ENV['DATABASE_URL'] = "postgres://localhost/foo"
config = { "default_env" => { "adapter" => "not_postgres", "database" => "not_foo" } }
@@ -35,6 +59,26 @@ module ActiveRecord
assert_equal expected, actual
end
+ def test_resolver_with_database_uri_and_and_current_env_string_key_and_rails_env
+ ENV['DATABASE_URL'] = "postgres://localhost/foo"
+ ENV['RAILS_ENV'] = "foo"
+
+ config = { "not_production" => {"adapter" => "not_postgres", "database" => "not_foo" } }
+ actual = assert_deprecated { resolve_spec("foo", config) }
+ expected = { "adapter" => "postgresql", "database" => "foo", "host" => "localhost" }
+ assert_equal expected, actual
+ end
+
+ def test_resolver_with_database_uri_and_and_current_env_string_key_and_rack_env
+ ENV['DATABASE_URL'] = "postgres://localhost/foo"
+ ENV['RACK_ENV'] = "foo"
+
+ config = { "not_production" => {"adapter" => "not_postgres", "database" => "not_foo" } }
+ actual = assert_deprecated { resolve_spec("foo", config) }
+ expected = { "adapter" => "postgresql", "database" => "foo", "host" => "localhost" }
+ assert_equal expected, actual
+ end
+
def test_resolver_with_database_uri_and_known_key
ENV['DATABASE_URL'] = "postgres://localhost/foo"
config = { "production" => { "adapter" => "not_postgres", "database" => "not_foo", "host" => "localhost" } }
@@ -139,6 +183,51 @@ module ActiveRecord
assert_equal nil, actual["production"]
assert_equal nil, actual["development"]
assert_equal nil, actual["test"]
+ assert_equal nil, actual[:default_env]
+ assert_equal nil, actual[:production]
+ assert_equal nil, actual[:development]
+ assert_equal nil, actual[:test]
+ end
+
+ def test_blank_with_database_url_with_rails_env
+ ENV['RAILS_ENV'] = "not_production"
+ ENV['DATABASE_URL'] = "postgres://localhost/foo"
+
+ config = {}
+ actual = resolve_config(config)
+ expected = { "adapter" => "postgresql",
+ "database" => "foo",
+ "host" => "localhost" }
+
+ assert_equal expected, actual["not_production"]
+ assert_equal nil, actual["production"]
+ assert_equal nil, actual["default_env"]
+ assert_equal nil, actual["development"]
+ assert_equal nil, actual["test"]
+ assert_equal nil, actual[:default_env]
+ assert_equal nil, actual[:not_production]
+ assert_equal nil, actual[:production]
+ assert_equal nil, actual[:development]
+ assert_equal nil, actual[:test]
+ end
+
+ def test_blank_with_database_url_with_rack_env
+ ENV['RACK_ENV'] = "not_production"
+ ENV['DATABASE_URL'] = "postgres://localhost/foo"
+
+ config = {}
+ actual = resolve_config(config)
+ expected = { "adapter" => "postgresql",
+ "database" => "foo",
+ "host" => "localhost" }
+
+ assert_equal expected, actual["not_production"]
+ assert_equal nil, actual["production"]
+ assert_equal nil, actual["default_env"]
+ assert_equal nil, actual["development"]
+ assert_equal nil, actual["test"]
+ assert_equal nil, actual[:default_env]
+ assert_equal nil, actual[:not_production]
assert_equal nil, actual[:production]
assert_equal nil, actual[:development]
assert_equal nil, actual[:test]
diff --git a/activerecord/test/cases/connection_adapters/mysql_type_lookup_test.rb b/activerecord/test/cases/connection_adapters/mysql_type_lookup_test.rb
index d4d67487db..80244d1439 100644
--- a/activerecord/test/cases/connection_adapters/mysql_type_lookup_test.rb
+++ b/activerecord/test/cases/connection_adapters/mysql_type_lookup_test.rb
@@ -22,6 +22,10 @@ module ActiveRecord
assert_lookup_type :string, "SET('one', 'two', 'three')"
end
+ def test_enum_type_with_value_matching_other_type
+ assert_lookup_type :string, "ENUM('unicode', '8bit', 'none')"
+ end
+
def test_binary_types
assert_lookup_type :binary, 'bit'
assert_lookup_type :binary, 'BIT'
diff --git a/activerecord/test/cases/finder_test.rb b/activerecord/test/cases/finder_test.rb
index ac570ecbe0..dc73faa5be 100644
--- a/activerecord/test/cases/finder_test.rb
+++ b/activerecord/test/cases/finder_test.rb
@@ -99,21 +99,10 @@ class FinderTest < ActiveRecord::TestCase
end
def test_exists_fails_when_parameter_has_invalid_type
- if current_adapter?(:PostgreSQLAdapter, :MysqlAdapter)
- assert_raises ActiveRecord::StatementInvalid do
- Topic.exists?(("9"*53).to_i) # number that's bigger than int
- end
- else
+ assert_raises(RangeError) do
assert_equal false, Topic.exists?(("9"*53).to_i) # number that's bigger than int
end
-
- if current_adapter?(:PostgreSQLAdapter)
- assert_raises ActiveRecord::StatementInvalid do
- Topic.exists?("foo")
- end
- else
- assert_equal false, Topic.exists?("foo")
- end
+ assert_equal false, Topic.exists?("foo")
end
def test_exists_does_not_select_columns_without_alias
@@ -209,6 +198,28 @@ class FinderTest < ActiveRecord::TestCase
assert_equal 2, last_devs.size
end
+ def test_find_with_large_number
+ assert_raises(ActiveRecord::RecordNotFound) { Topic.find('9999999999999999999999999999999') }
+ end
+
+ def test_find_by_with_large_number
+ assert_nil Topic.find_by(id: '9999999999999999999999999999999')
+ end
+
+ def test_find_by_id_with_large_number
+ 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/helper.rb b/activerecord/test/cases/helper.rb
index f5be8a044b..80ac57ec7c 100644
--- a/activerecord/test/cases/helper.rb
+++ b/activerecord/test/cases/helper.rb
@@ -95,7 +95,7 @@ EXPECTED_TIME_ZONE_AWARE_ATTRIBUTES = false
def verify_default_timezone_config
if Time.zone != EXPECTED_ZONE
$stderr.puts <<-MSG
-\n#{self.to_s}
+\n#{self}
Global state `Time.zone` was leaked.
Expected: #{EXPECTED_ZONE}
Got: #{Time.zone}
@@ -103,7 +103,7 @@ def verify_default_timezone_config
end
if ActiveRecord::Base.default_timezone != EXPECTED_DEFAULT_TIMEZONE
$stderr.puts <<-MSG
-\n#{self.to_s}
+\n#{self}
Global state `ActiveRecord::Base.default_timezone` was leaked.
Expected: #{EXPECTED_DEFAULT_TIMEZONE}
Got: #{ActiveRecord::Base.default_timezone}
@@ -111,7 +111,7 @@ def verify_default_timezone_config
end
if ActiveRecord::Base.time_zone_aware_attributes != EXPECTED_TIME_ZONE_AWARE_ATTRIBUTES
$stderr.puts <<-MSG
-\n#{self.to_s}
+\n#{self}
Global state `ActiveRecord::Base.time_zone_aware_attributes` was leaked.
Expected: #{EXPECTED_TIME_ZONE_AWARE_ATTRIBUTES}
Got: #{ActiveRecord::Base.time_zone_aware_attributes}
diff --git a/activerecord/test/cases/migration/references_index_test.rb b/activerecord/test/cases/migration/references_index_test.rb
index 4485701a4e..ad6b828d0b 100644
--- a/activerecord/test/cases/migration/references_index_test.rb
+++ b/activerecord/test/cases/migration/references_index_test.rb
@@ -55,7 +55,7 @@ module ActiveRecord
t.references :foo, :polymorphic => true, :index => true
end
- assert connection.index_exists?(table_name, [:foo_id, :foo_type], :name => :index_testings_on_foo_id_and_foo_type)
+ assert connection.index_exists?(table_name, [:foo_type, :foo_id], name: :index_testings_on_foo_type_and_foo_id)
end
end
@@ -93,7 +93,7 @@ module ActiveRecord
t.references :foo, :polymorphic => true, :index => true
end
- assert connection.index_exists?(table_name, [:foo_id, :foo_type], :name => :index_testings_on_foo_id_and_foo_type)
+ assert connection.index_exists?(table_name, [:foo_type, :foo_id], name: :index_testings_on_foo_type_and_foo_id)
end
end
end
diff --git a/activerecord/test/cases/migration/references_statements_test.rb b/activerecord/test/cases/migration/references_statements_test.rb
index b8b4fa1135..988bd9c89f 100644
--- a/activerecord/test/cases/migration/references_statements_test.rb
+++ b/activerecord/test/cases/migration/references_statements_test.rb
@@ -42,7 +42,7 @@ module ActiveRecord
def test_creates_polymorphic_index
add_reference table_name, :taggable, polymorphic: true, index: true
- assert index_exists?(table_name, [:taggable_id, :taggable_type])
+ assert index_exists?(table_name, [:taggable_type, :taggable_id])
end
def test_creates_reference_type_column_with_default
diff --git a/activerecord/test/cases/migration_test.rb b/activerecord/test/cases/migration_test.rb
index 270e446c69..6b7a0a9000 100644
--- a/activerecord/test/cases/migration_test.rb
+++ b/activerecord/test/cases/migration_test.rb
@@ -15,7 +15,6 @@ class BigNumber < ActiveRecord::Base
unless current_adapter?(:PostgreSQLAdapter, :SQLite3Adapter)
attribute :value_of_e, Type::Integer.new
end
- attribute :world_population, Type::Integer.new
attribute :my_house_population, Type::Integer.new
end
@@ -101,6 +100,19 @@ class MigrationTest < ActiveRecord::TestCase
ActiveRecord::Migrator.migrations_paths = old_path
end
+ def test_any_migrations
+ old_path = ActiveRecord::Migrator.migrations_paths
+ ActiveRecord::Migrator.migrations_paths = MIGRATIONS_ROOT + "/valid"
+
+ assert ActiveRecord::Migrator.any_migrations?
+
+ ActiveRecord::Migrator.migrations_paths = MIGRATIONS_ROOT + "/empty"
+
+ assert_not ActiveRecord::Migrator.any_migrations?
+ ensure
+ ActiveRecord::Migrator.migrations_paths = old_path
+ end
+
def test_migration_version
ActiveRecord::Migrator.run(:up, MIGRATIONS_ROOT + "/version_check", 20131219224947)
end
diff --git a/activerecord/test/cases/relation/where_chain_test.rb b/activerecord/test/cases/relation/where_chain_test.rb
index b9e69bdb08..619055f1e7 100644
--- a/activerecord/test/cases/relation/where_chain_test.rb
+++ b/activerecord/test/cases/relation/where_chain_test.rb
@@ -149,5 +149,33 @@ module ActiveRecord
assert_bound_ast value, Post.arel_table['title'], Arel::Nodes::Equality
assert_equal 'alone', bind.last
end
+
+ def test_rewhere_with_range
+ relation = Post.where(comments_count: 1..3).rewhere(comments_count: 3..5)
+
+ assert_equal 1, relation.where_values.size
+ assert_equal Post.where(comments_count: 3..5), relation
+ end
+
+ def test_rewhere_with_infinite_upper_bound_range
+ relation = Post.where(comments_count: 1..Float::INFINITY).rewhere(comments_count: 3..5)
+
+ assert_equal 1, relation.where_values.size
+ assert_equal Post.where(comments_count: 3..5), relation
+ end
+
+ def test_rewhere_with_infinite_lower_bound_range
+ relation = Post.where(comments_count: -Float::INFINITY..1).rewhere(comments_count: 3..5)
+
+ assert_equal 1, relation.where_values.size
+ assert_equal Post.where(comments_count: 3..5), relation
+ end
+
+ def test_rewhere_with_infinite_range
+ relation = Post.where(comments_count: -Float::INFINITY..Float::INFINITY).rewhere(comments_count: 3..5)
+
+ assert_equal 1, relation.where_values.size
+ assert_equal Post.where(comments_count: 3..5), relation
+ end
end
end
diff --git a/activerecord/test/cases/relation/where_test.rb b/activerecord/test/cases/relation/where_test.rb
index 39c8afdd23..a453203e15 100644
--- a/activerecord/test/cases/relation/where_test.rb
+++ b/activerecord/test/cases/relation/where_test.rb
@@ -7,6 +7,7 @@ require 'models/comment'
require 'models/edge'
require 'models/topic'
require 'models/binary'
+require 'models/vertex'
module ActiveRecord
class WhereTest < ActiveRecord::TestCase
diff --git a/activerecord/test/cases/sanitize_test.rb b/activerecord/test/cases/sanitize_test.rb
index dca85fb5eb..f477cf7d92 100644
--- a/activerecord/test/cases/sanitize_test.rb
+++ b/activerecord/test/cases/sanitize_test.rb
@@ -13,7 +13,9 @@ class SanitizeTest < ActiveRecord::TestCase
quoted_table_name = ActiveRecord::Base.connection.quote_table_name("adorable_animals")
expected_value = "#{quoted_table_name}.#{quoted_column_name} = #{quoted_bambi}"
- assert_equal expected_value, Binary.send(:sanitize_sql_hash, {adorable_animals: {name: 'Bambi'}})
+ assert_deprecated do
+ assert_equal expected_value, Binary.send(:sanitize_sql_hash, {adorable_animals: {name: 'Bambi'}})
+ end
end
def test_sanitize_sql_array_handles_string_interpolation
diff --git a/activerecord/test/cases/schema_dumper_test.rb b/activerecord/test/cases/schema_dumper_test.rb
index 2241c41f36..6303393c22 100644
--- a/activerecord/test/cases/schema_dumper_test.rb
+++ b/activerecord/test/cases/schema_dumper_test.rb
@@ -271,13 +271,6 @@ class SchemaDumperTest < ActiveRecord::TestCase
end
end
- def test_schema_dump_includes_json_shorthand_definition
- output = standard_dump
- if %r{create_table "postgresql_json_data_type"} =~ output
- assert_match %r|t.json "json_data", default: {}|, output
- end
- end
-
def test_schema_dump_includes_inet_shorthand_definition
output = standard_dump
if %r{create_table "postgresql_network_addresses"} =~ output
diff --git a/activerecord/test/cases/scoping/named_scoping_test.rb b/activerecord/test/cases/scoping/named_scoping_test.rb
index d3546bd471..c2816c3670 100644
--- a/activerecord/test/cases/scoping/named_scoping_test.rb
+++ b/activerecord/test/cases/scoping/named_scoping_test.rb
@@ -132,6 +132,13 @@ class NamedScopingTest < ActiveRecord::TestCase
assert_equal Post.ranked_by_comments.limit_by(5), Post.top(5)
end
+ def test_scopes_body_is_a_callable
+ e = assert_raises ArgumentError do
+ Class.new(Post).class_eval { scope :containing_the_letter_z, where("body LIKE '%z%'") }
+ end
+ assert_equal "The scope body needs to be callable.", e.message
+ end
+
def test_active_records_have_scope_named__all__
assert !Topic.all.empty?
diff --git a/activerecord/test/cases/serialization_test.rb b/activerecord/test/cases/serialization_test.rb
index 3f52e80e11..35b13ea247 100644
--- a/activerecord/test/cases/serialization_test.rb
+++ b/activerecord/test/cases/serialization_test.rb
@@ -2,6 +2,8 @@ require "cases/helper"
require 'models/contact'
require 'models/topic'
require 'models/book'
+require 'models/author'
+require 'models/post'
class SerializationTest < ActiveRecord::TestCase
fixtures :books
@@ -92,4 +94,11 @@ class SerializationTest < ActiveRecord::TestCase
book = klazz.find(books(:awdr).id)
assert_equal 'paperback', book.read_attribute_for_serialization(:format)
end
+
+ def test_find_records_by_serialized_attributes_through_join
+ author = Author.create!(name: "David")
+ author.serialized_posts.create!(title: "Hello")
+
+ assert_equal 1, Author.joins(:serialized_posts).where(name: "David", serialized_posts: { title: "Hello" }).length
+ end
end
diff --git a/activerecord/test/cases/type/integer_test.rb b/activerecord/test/cases/type/integer_test.rb
new file mode 100644
index 0000000000..53d6a3a6aa
--- /dev/null
+++ b/activerecord/test/cases/type/integer_test.rb
@@ -0,0 +1,106 @@
+require "cases/helper"
+require "models/company"
+
+module ActiveRecord
+ module Type
+ class IntegerTest < ActiveRecord::TestCase
+ test "simple values" do
+ type = Type::Integer.new
+ assert_equal 1, type.type_cast_from_user(1)
+ assert_equal 1, type.type_cast_from_user('1')
+ assert_equal 1, type.type_cast_from_user('1ignore')
+ assert_equal 0, type.type_cast_from_user('bad1')
+ assert_equal 0, type.type_cast_from_user('bad')
+ assert_equal 1, type.type_cast_from_user(1.7)
+ assert_equal 0, type.type_cast_from_user(false)
+ assert_equal 1, type.type_cast_from_user(true)
+ assert_nil type.type_cast_from_user(nil)
+ end
+
+ test "random objects cast to nil" do
+ type = Type::Integer.new
+ assert_nil type.type_cast_from_user([1,2])
+ assert_nil type.type_cast_from_user({1 => 2})
+ assert_nil type.type_cast_from_user((1..2))
+ end
+
+ test "casting ActiveRecord models" do
+ type = Type::Integer.new
+ firm = Firm.create(:name => 'Apple')
+ assert_nil type.type_cast_from_user(firm)
+ end
+
+ test "casting objects without to_i" do
+ type = Type::Integer.new
+ assert_nil type.type_cast_from_user(::Object.new)
+ end
+
+ test "casting nan and infinity" do
+ type = Type::Integer.new
+ assert_nil type.type_cast_from_user(::Float::NAN)
+ assert_nil type.type_cast_from_user(1.0/0.0)
+ end
+
+ test "changed?" do
+ type = Type::Integer.new
+
+ assert type.changed?(5, 5, '5wibble')
+ assert_not type.changed?(5, 5, '5')
+ assert_not type.changed?(5, 5, '5.0')
+ assert_not type.changed?(nil, nil, nil)
+ end
+
+ test "values below int min value are out of range" do
+ assert_raises(::RangeError) do
+ Integer.new.type_cast_from_user("-2147483649")
+ end
+ end
+
+ test "values above int max value are out of range" do
+ assert_raises(::RangeError) do
+ Integer.new.type_cast_from_user("2147483648")
+ end
+ end
+
+ test "very small numbers are out of range" do
+ assert_raises(::RangeError) do
+ Integer.new.type_cast_from_user("-9999999999999999999999999999999")
+ end
+ end
+
+ test "very large numbers are in range" do
+ assert_raises(::RangeError) do
+ Integer.new.type_cast_from_user("9999999999999999999999999999999")
+ end
+ end
+
+ test "normal numbers are in range" do
+ type = Integer.new
+ assert_equal(0, type.type_cast_from_user("0"))
+ assert_equal(-1, type.type_cast_from_user("-1"))
+ assert_equal(1, type.type_cast_from_user("1"))
+ end
+
+ test "int max value is in range" do
+ assert_equal(2147483647, Integer.new.type_cast_from_user("2147483647"))
+ end
+
+ test "int min value is in range" do
+ assert_equal(-2147483648, Integer.new.type_cast_from_user("-2147483648"))
+ end
+
+ test "columns with a larger limit have larger ranges" do
+ type = Integer.new(limit: 8)
+
+ assert_equal(9223372036854775807, type.type_cast_from_user("9223372036854775807"))
+ assert_equal(-9223372036854775808, type.type_cast_from_user("-9223372036854775808"))
+ assert_raises(::RangeError) do
+ type.type_cast_from_user("-9999999999999999999999999999999")
+ end
+ assert_raises(::RangeError) do
+ type.type_cast_from_user("9999999999999999999999999999999")
+ end
+ end
+ end
+ end
+end
diff --git a/activerecord/test/cases/types_test.rb b/activerecord/test/cases/types_test.rb
index 25e6549072..b0979cbe1f 100644
--- a/activerecord/test/cases/types_test.rb
+++ b/activerecord/test/cases/types_test.rb
@@ -1,5 +1,4 @@
require "cases/helper"
-require 'models/company'
module ActiveRecord
module ConnectionAdapters
@@ -37,52 +36,6 @@ module ActiveRecord
end
end
- def test_type_cast_integer
- type = Type::Integer.new
- assert_equal 1, type.type_cast_from_user(1)
- assert_equal 1, type.type_cast_from_user('1')
- assert_equal 1, type.type_cast_from_user('1ignore')
- assert_equal 0, type.type_cast_from_user('bad1')
- assert_equal 0, type.type_cast_from_user('bad')
- assert_equal 1, type.type_cast_from_user(1.7)
- assert_equal 0, type.type_cast_from_user(false)
- assert_equal 1, type.type_cast_from_user(true)
- assert_nil type.type_cast_from_user(nil)
- end
-
- def test_type_cast_non_integer_to_integer
- type = Type::Integer.new
- assert_nil type.type_cast_from_user([1,2])
- assert_nil type.type_cast_from_user({1 => 2})
- assert_nil type.type_cast_from_user((1..2))
- end
-
- def test_type_cast_activerecord_to_integer
- type = Type::Integer.new
- firm = Firm.create(:name => 'Apple')
- assert_nil type.type_cast_from_user(firm)
- end
-
- def test_type_cast_object_without_to_i_to_integer
- type = Type::Integer.new
- assert_nil type.type_cast_from_user(Object.new)
- end
-
- def test_type_cast_nan_and_infinity_to_integer
- type = Type::Integer.new
- assert_nil type.type_cast_from_user(Float::NAN)
- assert_nil type.type_cast_from_user(1.0/0.0)
- end
-
- def test_changing_integers
- type = Type::Integer.new
-
- assert type.changed?(5, 5, '5wibble')
- assert_not type.changed?(5, 5, '5')
- assert_not type.changed?(5, 5, '5.0')
- assert_not type.changed?(nil, nil, nil)
- end
-
def test_type_cast_float
type = Type::Float.new
assert_equal 1.0, type.type_cast_from_user("1")
diff --git a/activerecord/test/models/author.rb b/activerecord/test/models/author.rb
index 3f34d09a04..3da3a1fd59 100644
--- a/activerecord/test/models/author.rb
+++ b/activerecord/test/models/author.rb
@@ -1,5 +1,6 @@
class Author < ActiveRecord::Base
has_many :posts
+ has_many :serialized_posts
has_one :post
has_many :very_special_comments, :through => :posts
has_many :posts_with_comments, -> { includes(:comments) }, :class_name => "Post"
diff --git a/activerecord/test/models/post.rb b/activerecord/test/models/post.rb
index 67027cbc22..36cf221d45 100644
--- a/activerecord/test/models/post.rb
+++ b/activerecord/test/models/post.rb
@@ -233,3 +233,7 @@ class PostWithCommentWithDefaultScopeReferencesAssociation < ActiveRecord::Base
has_many :comment_with_default_scope_references_associations, foreign_key: :post_id
has_one :first_comment, class_name: "CommentWithDefaultScopeReferencesAssociation", foreign_key: :post_id
end
+
+class SerializedPost < ActiveRecord::Base
+ serialize :title
+end
diff --git a/activerecord/test/schema/postgresql_specific_schema.rb b/activerecord/test/schema/postgresql_specific_schema.rb
index e9294a11b9..7c3b170c08 100644
--- a/activerecord/test/schema/postgresql_specific_schema.rb
+++ b/activerecord/test/schema/postgresql_specific_schema.rb
@@ -1,7 +1,9 @@
ActiveRecord::Schema.define do
- %w(postgresql_tsvectors postgresql_hstores postgresql_arrays postgresql_moneys postgresql_numbers postgresql_times postgresql_network_addresses postgresql_uuids postgresql_ltrees
- postgresql_oids postgresql_xml_data_type defaults geometrics postgresql_timestamp_with_zones postgresql_partitioned_table postgresql_partitioned_table_parent postgresql_json_data_type postgresql_citext).each do |table_name|
+ %w(postgresql_tsvectors postgresql_hstores postgresql_arrays postgresql_moneys postgresql_numbers postgresql_times
+ postgresql_network_addresses postgresql_uuids postgresql_ltrees postgresql_oids postgresql_xml_data_type defaults
+ geometrics postgresql_timestamp_with_zones postgresql_partitioned_table postgresql_partitioned_table_parent
+ postgresql_citext).each do |table_name|
execute "DROP TABLE IF EXISTS #{quote_table_name table_name}"
end
@@ -108,15 +110,6 @@ _SQL
_SQL
end
- if 't' == select_value("select 'json'=ANY(select typname from pg_type)")
- execute <<_SQL
- CREATE TABLE postgresql_json_data_type (
- id SERIAL PRIMARY KEY,
- json_data json default '{}'::json
- );
-_SQL
- end
-
execute <<_SQL
CREATE TABLE postgresql_numbers (
id SERIAL PRIMARY KEY,
diff --git a/activerecord/test/schema/schema.rb b/activerecord/test/schema/schema.rb
index 10de3d34cb..539a0d2a49 100644
--- a/activerecord/test/schema/schema.rb
+++ b/activerecord/test/schema/schema.rb
@@ -311,7 +311,7 @@ ActiveRecord::Schema.define do
end
create_table :cold_jokes, force: true do |t|
- t.string :name
+ t.string :cold_name
end
create_table :friendships, force: true do |t|
@@ -585,6 +585,11 @@ ActiveRecord::Schema.define do
t.integer :tags_with_nullify_count, default: 0
end
+ create_table :serialized_posts, force: true do |t|
+ t.integer :author_id
+ t.string :title, null: false
+ end
+
create_table :price_estimates, force: true do |t|
t.string :estimate_of_type
t.integer :estimate_of_id
diff --git a/activesupport/CHANGELOG.md b/activesupport/CHANGELOG.md
index a935d33686..b2b3cf4bd4 100644
--- a/activesupport/CHANGELOG.md
+++ b/activesupport/CHANGELOG.md
@@ -1,3 +1,12 @@
+* `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.
*James Le Cuirot*
@@ -63,7 +72,7 @@
*Guo Xiang Tan*
-* Added instance_eval version to Object#try, so you can do this:
+* Added instance_eval version to Object#try and Object#try!, so you can do this:
person.try { name.first }
@@ -71,7 +80,7 @@
person.try { |person| person.name.first }
- *DHH*
+ *DHH*, *Ari Pollak*
* Fix the `ActiveSupport::Duration#instance_of?` method to return the right
value with the class itself since it was previously delegated to the
diff --git a/activesupport/lib/active_support/callbacks.rb b/activesupport/lib/active_support/callbacks.rb
index 45231bc101..24c702b602 100644
--- a/activesupport/lib/active_support/callbacks.rb
+++ b/activesupport/lib/active_support/callbacks.rb
@@ -78,7 +78,7 @@ module ActiveSupport
# save
# end
def run_callbacks(kind, &block)
- send "run_#{kind}_callbacks", &block
+ send "_run_#{kind}_callbacks", &block
end
private
@@ -730,7 +730,7 @@ module ActiveSupport
set_callbacks name, CallbackChain.new(name, options)
module_eval <<-RUBY, __FILE__, __LINE__ + 1
- def run_#{name}_callbacks(&block)
+ def _run_#{name}_callbacks(&block)
_run_callbacks(_#{name}_callbacks, &block)
end
RUBY
diff --git a/activesupport/lib/active_support/core_ext/array/access.rb b/activesupport/lib/active_support/core_ext/array/access.rb
index caa499dfa2..45b89d2705 100644
--- a/activesupport/lib/active_support/core_ext/array/access.rb
+++ b/activesupport/lib/active_support/core_ext/array/access.rb
@@ -20,7 +20,11 @@ class Array
# %w( a b c d ).to(-2) # => ["a", "b", "c"]
# %w( a b c ).to(-10) # => []
def to(position)
- self[0..position]
+ if position >= 0
+ first position + 1
+ else
+ self[0..position]
+ end
end
# Equal to <tt>self[1]</tt>.
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/kernel/reporting.rb b/activesupport/lib/active_support/core_ext/kernel/reporting.rb
index 80c531b694..f5179552bb 100644
--- a/activesupport/lib/active_support/core_ext/kernel/reporting.rb
+++ b/activesupport/lib/active_support/core_ext/kernel/reporting.rb
@@ -32,7 +32,7 @@ module Kernel
# For compatibility
def silence_stderr #:nodoc:
ActiveSupport::Deprecation.warn(
- "#silence_stderr is deprecated and will be removed in the next release"
+ "`#silence_stderr` is deprecated and will be removed in the next release."
) #not thread-safe
silence_stream(STDERR) { yield }
end
@@ -87,7 +87,7 @@ module Kernel
# stream # => "error\n"
def capture(stream)
ActiveSupport::Deprecation.warn(
- "#capture(stream) is deprecated and will be removed in the next release"
+ "`#capture(stream)` is deprecated and will be removed in the next release."
) #not thread-safe
stream = stream.to_s
captured_stream = Tempfile.new(stream)
@@ -113,7 +113,7 @@ module Kernel
# This method is not thread-safe.
def quietly
ActiveSupport::Deprecation.warn(
- "#quietly is deprecated and will be removed in the next release"
+ "`#quietly` is deprecated and will be removed in the next release."
) #not thread-safe
silence_stream(STDOUT) do
silence_stream(STDERR) do
diff --git a/activesupport/lib/active_support/core_ext/object/try.rb b/activesupport/lib/active_support/core_ext/object/try.rb
index 31919474ed..56da398978 100644
--- a/activesupport/lib/active_support/core_ext/object/try.rb
+++ b/activesupport/lib/active_support/core_ext/object/try.rb
@@ -9,7 +9,23 @@ class Object
#
# instead of
#
- # @person ? @person.name : nil
+ # @person.name if @person
+ #
+ # +try+ calls can be chained:
+ #
+ # @person.try(:spouse).try(:name)
+ #
+ # instead of
+ #
+ # @person.spouse.name if @person && @person.spouse
+ #
+ # +try+ will also return +nil+ if the receiver does not respond to the method:
+ #
+ # @person.try(:non_existing_method) #=> nil
+ #
+ # instead of
+ #
+ # @person.non_existing_method if @person.respond_to?(:non_existing_method) #=> nil
#
# +try+ returns +nil+ when called on +nil+ regardless of whether it responds
# to the method:
@@ -24,7 +40,7 @@ class Object
#
# The number of arguments in the signature must match. If the object responds
# to the method the call is attempted and +ArgumentError+ is still raised
- # otherwise.
+ # in case of argument mismatch.
#
# If +try+ is called without arguments it yields the receiver to a given
# block unless it is +nil+:
@@ -38,12 +54,19 @@ class Object
#
# @person.try { upcase.truncate(50) }
#
- # Please also note that +try+ is defined on +Object+, therefore it won't work
+ # Please also note that +try+ is defined on +Object+. Therefore, it won't work
# with instances of classes that do not have +Object+ among their ancestors,
# like direct subclasses of +BasicObject+. For example, using +try+ with
# +SimpleDelegator+ will delegate +try+ to the target instead of calling it on
- # delegator itself.
+ # the delegator itself.
def try(*a, &b)
+ try!(*a, &b) if a.empty? || respond_to?(a.first)
+ end
+
+ # Same as #try, but will raise a NoMethodError exception if the receiver is not +nil+ and
+ # does not implement the tried method.
+
+ def try!(*a, &b)
if a.empty? && block_given?
if b.arity.zero?
instance_eval(&b)
@@ -51,16 +74,6 @@ class Object
yield self
end
else
- public_send(*a, &b) if respond_to?(a.first)
- end
- end
-
- # Same as #try, but will raise a NoMethodError exception if the receiving is not nil and
- # does not implement the tried method.
- def try!(*a, &b)
- if a.empty? && block_given?
- yield self
- else
public_send(*a, &b)
end
end
@@ -68,12 +81,12 @@ end
class NilClass
# Calling +try+ on +nil+ always returns +nil+.
- # It becomes specially helpful when navigating through associations that may return +nil+.
+ # It becomes especially helpful when navigating through associations that may return +nil+.
#
# nil.try(:name) # => nil
#
# Without +try+
- # @person && !@person.children.blank? && @person.children.first.name
+ # @person && @person.children.any? && @person.children.first.name
#
# With +try+
# @person.try(:children).try(:first).try(:name)
diff --git a/activesupport/lib/active_support/core_ext/string/filters.rb b/activesupport/lib/active_support/core_ext/string/filters.rb
index 2b1583d4ac..499b9b26bc 100644
--- a/activesupport/lib/active_support/core_ext/string/filters.rb
+++ b/activesupport/lib/active_support/core_ext/string/filters.rb
@@ -20,14 +20,18 @@ class String
self
end
- # Returns a new string with all occurrences of the pattern removed. Short-hand for String#gsub(pattern, '').
- def remove(pattern)
- gsub pattern, ''
+ # Returns a new string with all occurrences of the patterns removed.
+ def remove(*patterns)
+ dup.remove!(*patterns)
end
- # Alters the string by removing all occurrences of the pattern. Short-hand for String#gsub!(pattern, '').
- def remove!(pattern)
- gsub! pattern, ''
+ # Alters the string by removing all occurrences of the patterns.
+ def remove!(*patterns)
+ patterns.each do |pattern|
+ gsub! pattern, ""
+ end
+
+ self
end
# Truncates a given +text+ after a given <tt>length</tt> if +text+ is longer than <tt>length</tt>:
diff --git a/activesupport/lib/active_support/core_ext/string/output_safety.rb b/activesupport/lib/active_support/core_ext/string/output_safety.rb
index c761325108..042283e4fc 100644
--- a/activesupport/lib/active_support/core_ext/string/output_safety.rb
+++ b/activesupport/lib/active_support/core_ext/string/output_safety.rb
@@ -150,7 +150,7 @@ module ActiveSupport #:nodoc:
else
if html_safe?
new_safe_buffer = super
- new_safe_buffer.instance_eval { @html_safe = true }
+ new_safe_buffer.instance_variable_set :@html_safe, true
new_safe_buffer
else
to_str[*args]
diff --git a/activesupport/lib/active_support/dependencies.rb b/activesupport/lib/active_support/dependencies.rb
index 93a11d4586..a89c769e34 100644
--- a/activesupport/lib/active_support/dependencies.rb
+++ b/activesupport/lib/active_support/dependencies.rb
@@ -30,6 +30,10 @@ module ActiveSupport #:nodoc:
mattr_accessor :loaded
self.loaded = Set.new
+ # Stack of files being loaded.
+ mattr_accessor :loading
+ self.loading = []
+
# Should we load files or require them?
mattr_accessor :mechanism
self.mechanism = ENV['NO_RELOAD'] ? :require : :load
@@ -317,6 +321,7 @@ module ActiveSupport #:nodoc:
def clear
log_call
loaded.clear
+ loading.clear
remove_unloadable_constants!
end
@@ -329,6 +334,7 @@ module ActiveSupport #:nodoc:
# Record that we've seen this file *before* loading it to avoid an
# infinite loop with mutual dependencies.
loaded << expanded
+ loading << expanded
begin
if load?
@@ -351,6 +357,8 @@ module ActiveSupport #:nodoc:
rescue Exception
loaded.delete expanded
raise
+ ensure
+ loading.pop
end
# Record history *after* loading so first load gets warnings.
@@ -475,7 +483,7 @@ module ActiveSupport #:nodoc:
expanded = File.expand_path(file_path)
expanded.sub!(/\.rb\z/, '')
- if loaded.include?(expanded)
+ if loading.include?(expanded)
raise "Circular dependency detected while autoloading constant #{qualified_name}"
else
require_or_load(expanded, qualified_name)
diff --git a/activesupport/lib/active_support/dependencies/autoload.rb b/activesupport/lib/active_support/dependencies/autoload.rb
index c0dba5f7fd..13036d521d 100644
--- a/activesupport/lib/active_support/dependencies/autoload.rb
+++ b/activesupport/lib/active_support/dependencies/autoload.rb
@@ -67,7 +67,7 @@ module ActiveSupport
end
def eager_load!
- @_autoloads.values.each { |file| require file }
+ @_autoloads.each_value { |file| require file }
end
def autoloads
diff --git a/activesupport/lib/active_support/duration.rb b/activesupport/lib/active_support/duration.rb
index 584fc1e1c5..baa83223d2 100644
--- a/activesupport/lib/active_support/duration.rb
+++ b/activesupport/lib/active_support/duration.rb
@@ -1,4 +1,3 @@
-require 'active_support/proxy_object'
require 'active_support/core_ext/array/conversions'
require 'active_support/core_ext/object/acts_like'
diff --git a/activesupport/lib/active_support/gem_version.rb b/activesupport/lib/active_support/gem_version.rb
index 6233c45787..bc7933e38b 100644
--- a/activesupport/lib/active_support/gem_version.rb
+++ b/activesupport/lib/active_support/gem_version.rb
@@ -8,7 +8,7 @@ module ActiveSupport
MAJOR = 4
MINOR = 2
TINY = 0
- PRE = "beta2"
+ PRE = "beta4"
STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".")
end
diff --git a/activesupport/lib/active_support/inflector/inflections.rb b/activesupport/lib/active_support/inflector/inflections.rb
index 97401ccec7..486838bd15 100644
--- a/activesupport/lib/active_support/inflector/inflections.rb
+++ b/activesupport/lib/active_support/inflector/inflections.rb
@@ -154,7 +154,7 @@ module ActiveSupport
end
end
- # Add uncountable words that shouldn't be attempted inflected.
+ # Specifies words that are uncountable and should not be inflected.
#
# uncountable 'money'
# uncountable 'money', 'information'
diff --git a/activesupport/lib/active_support/inflector/methods.rb b/activesupport/lib/active_support/inflector/methods.rb
index 0e3c8517d1..74b3a7c2a9 100644
--- a/activesupport/lib/active_support/inflector/methods.rb
+++ b/activesupport/lib/active_support/inflector/methods.rb
@@ -73,7 +73,7 @@ module ActiveSupport
string = string.sub(/^(?:#{inflections.acronym_regex}(?=\b|[A-Z_])|\w)/) { $&.downcase }
end
string.gsub!(/(?:_|(\/))([a-z\d]*)/i) { "#{$1}#{inflections.acronyms[$2] || $2.capitalize}" }
- string.gsub!('/', '::')
+ string.gsub!(/\//, '::')
string
end
@@ -90,7 +90,7 @@ module ActiveSupport
# 'SSLError'.underscore.camelize # => "SslError"
def underscore(camel_cased_word)
return camel_cased_word unless camel_cased_word =~ /[A-Z-]|::/
- word = camel_cased_word.to_s.gsub('::', '/')
+ word = camel_cased_word.to_s.gsub(/::/, '/')
word.gsub!(/(?:(?<=([A-Za-z\d]))|\b)(#{inflections.acronym_regex})(?=\b|[^a-z])/) { "#{$1 && '_'}#{$2.downcase}" }
word.gsub!(/([A-Z\d]+)([A-Z][a-z])/,'\1_\2')
word.gsub!(/([a-z\d])([A-Z])/,'\1_\2')
diff --git a/activesupport/lib/active_support/json/encoding.rb b/activesupport/lib/active_support/json/encoding.rb
index a14ed7ee94..c0ac5af153 100644
--- a/activesupport/lib/active_support/json/encoding.rb
+++ b/activesupport/lib/active_support/json/encoding.rb
@@ -131,7 +131,7 @@ module ActiveSupport
"The JSON encoder in Rails 4.1 no longer supports encoding BigDecimals as JSON numbers. Instead, " \
"the new encoder will always encode them as strings.\n\n" \
"You are seeing this error because you are trying to check the value of the related configuration, " \
- "'active_support.encode_big_decimal_as_string'. If your application depends on this option, you should " \
+ "`active_support.encode_big_decimal_as_string`. If your application depends on this option, you should " \
"add the 'activesupport-json_encoder' gem to your Gemfile. For now, this option will always be true. " \
"In the future, it will be removed from Rails, so you should stop checking its value."
diff --git a/activesupport/lib/active_support/message_verifier.rb b/activesupport/lib/active_support/message_verifier.rb
index 6cb2884fb7..4e0796f4f8 100644
--- a/activesupport/lib/active_support/message_verifier.rb
+++ b/activesupport/lib/active_support/message_verifier.rb
@@ -1,5 +1,6 @@
require 'base64'
require 'active_support/core_ext/object/blank'
+require 'active_support/security_utils'
module ActiveSupport
# +MessageVerifier+ makes it easy to generate and verify messages which are
@@ -37,7 +38,7 @@ module ActiveSupport
raise InvalidSignature if signed_message.blank?
data, digest = signed_message.split("--")
- if data.present? && digest.present? && secure_compare(digest, generate_digest(data))
+ if data.present? && digest.present? && ActiveSupport::SecurityUtils.secure_compare(digest, generate_digest(data))
begin
@serializer.load(::Base64.strict_decode64(data))
rescue ArgumentError => argument_error
@@ -55,17 +56,6 @@ module ActiveSupport
end
private
- # constant-time comparison algorithm to prevent timing attacks
- def secure_compare(a, b)
- return false unless a.bytesize == b.bytesize
-
- l = a.unpack "C#{a.bytesize}"
-
- res = 0
- b.each_byte { |byte| res |= byte ^ l.shift }
- res == 0
- end
-
def generate_digest(data)
require 'openssl' unless defined?(OpenSSL)
OpenSSL::HMAC.hexdigest(OpenSSL::Digest.const_get(@digest).new, @secret, data)
diff --git a/activesupport/lib/active_support/number_helper.rb b/activesupport/lib/active_support/number_helper.rb
index 5ecda9593a..34439ee8be 100644
--- a/activesupport/lib/active_support/number_helper.rb
+++ b/activesupport/lib/active_support/number_helper.rb
@@ -272,12 +272,12 @@ module ActiveSupport
# string containing an i18n scope where to find this hash. It
# might have the following keys:
# * *integers*: <tt>:unit</tt>, <tt>:ten</tt>,
- # *<tt>:hundred</tt>, <tt>:thousand</tt>, <tt>:million</tt>,
- # *<tt>:billion</tt>, <tt>:trillion</tt>,
- # *<tt>:quadrillion</tt>
+ # <tt>:hundred</tt>, <tt>:thousand</tt>, <tt>:million</tt>,
+ # <tt>:billion</tt>, <tt>:trillion</tt>,
+ # <tt>:quadrillion</tt>
# * *fractionals*: <tt>:deci</tt>, <tt>:centi</tt>,
- # *<tt>:mili</tt>, <tt>:micro</tt>, <tt>:nano</tt>,
- # *<tt>:pico</tt>, <tt>:femto</tt>
+ # <tt>:mili</tt>, <tt>:micro</tt>, <tt>:nano</tt>,
+ # <tt>:pico</tt>, <tt>:femto</tt>
# * <tt>:format</tt> - Sets the format of the output string
# (defaults to "%n %u"). The field types are:
# * %u - The quantifier (ex.: 'thousand')
diff --git a/activesupport/lib/active_support/number_helper/number_to_currency_converter.rb b/activesupport/lib/active_support/number_helper/number_to_currency_converter.rb
index 9ae27a896a..fb5adb574a 100644
--- a/activesupport/lib/active_support/number_helper/number_to_currency_converter.rb
+++ b/activesupport/lib/active_support/number_helper/number_to_currency_converter.rb
@@ -13,7 +13,7 @@ module ActiveSupport
end
rounded_number = NumberToRoundedConverter.convert(number, options)
- format.gsub('%n', rounded_number).gsub('%u', options[:unit])
+ format.gsub(/%n/, rounded_number).gsub(/%u/, options[:unit])
end
private
diff --git a/activesupport/lib/active_support/number_helper/number_to_percentage_converter.rb b/activesupport/lib/active_support/number_helper/number_to_percentage_converter.rb
index eafe2844f7..1af294a03e 100644
--- a/activesupport/lib/active_support/number_helper/number_to_percentage_converter.rb
+++ b/activesupport/lib/active_support/number_helper/number_to_percentage_converter.rb
@@ -5,7 +5,7 @@ module ActiveSupport
def convert
rounded_number = NumberToRoundedConverter.convert(number, options)
- options[:format].gsub('%n', rounded_number)
+ options[:format].gsub(/%n/, rounded_number)
end
end
end
diff --git a/activesupport/lib/active_support/security_utils.rb b/activesupport/lib/active_support/security_utils.rb
new file mode 100644
index 0000000000..64c4801179
--- /dev/null
+++ b/activesupport/lib/active_support/security_utils.rb
@@ -0,0 +1,20 @@
+module ActiveSupport
+ module SecurityUtils
+ # Constant time string comparison.
+ #
+ # The values compared should be of fixed length, such as strings
+ # that have already been processed by HMAC. This should not be used
+ # on variable length plaintext strings because it could leak length info
+ # via timing attacks.
+ def secure_compare(a, b)
+ return false unless a.bytesize == b.bytesize
+
+ l = a.unpack "C#{a.bytesize}"
+
+ res = 0
+ b.each_byte { |byte| res |= byte ^ l.shift }
+ res == 0
+ end
+ module_function :secure_compare
+ end
+end
diff --git a/activesupport/lib/active_support/test_case.rb b/activesupport/lib/active_support/test_case.rb
index 4c3e77b7fd..a4ba5989b1 100644
--- a/activesupport/lib/active_support/test_case.rb
+++ b/activesupport/lib/active_support/test_case.rb
@@ -25,7 +25,7 @@ module ActiveSupport
if test_order.nil?
ActiveSupport::Deprecation.warn "You did not specify a value for the " \
- "configuration option 'active_support.test_order'. In Rails 5.0, " \
+ "configuration option `active_support.test_order`. In Rails 5, " \
"the default value of this option will change from `:sorted` to " \
"`:random`.\n" \
"To disable this warning and keep the current behavior, you can add " \
diff --git a/activesupport/lib/active_support/time_with_zone.rb b/activesupport/lib/active_support/time_with_zone.rb
index 4a0ed356b1..dbee145196 100644
--- a/activesupport/lib/active_support/time_with_zone.rb
+++ b/activesupport/lib/active_support/time_with_zone.rb
@@ -75,8 +75,8 @@ module ActiveSupport
# Returns a <tt>Time.local()</tt> instance of the simultaneous time in your
# system's <tt>ENV['TZ']</tt> zone.
- def localtime
- utc.respond_to?(:getlocal) ? utc.getlocal : utc.to_time.getlocal
+ def localtime(utc_offset = nil)
+ utc.respond_to?(:getlocal) ? utc.getlocal(utc_offset) : utc.to_time.getlocal(utc_offset)
end
alias_method :getlocal, :localtime
@@ -201,15 +201,11 @@ module ActiveSupport
end
alias_method :to_formatted_s, :to_s
- # Replaces <tt>%Z</tt> and <tt>%z</tt> directives with +zone+ and
- # +formatted_offset+, respectively, before passing to Time#strftime, so
- # that zone information is correct
+ # Replaces <tt>%Z</tt> directive with +zone before passing to Time#strftime,
+ # so that zone information is correct.
def strftime(format)
- format = format.gsub('%Z', zone)
- .gsub('%z', formatted_offset(false))
- .gsub('%:z', formatted_offset(true))
- .gsub('%::z', formatted_offset(true) + ":00")
- time.strftime(format)
+ format = format.gsub(/((?:\A|[^%])(?:%%)*)%Z/, "\\1#{zone}")
+ getlocal(utc_offset).strftime(format)
end
# Use the time in UTC for comparisons.
diff --git a/activesupport/test/autoloading_fixtures/typo.rb b/activesupport/test/autoloading_fixtures/typo.rb
new file mode 100644
index 0000000000..8e047f5fd4
--- /dev/null
+++ b/activesupport/test/autoloading_fixtures/typo.rb
@@ -0,0 +1,2 @@
+TypO = 1
+
diff --git a/activesupport/test/core_ext/duration_test.rb b/activesupport/test/core_ext/duration_test.rb
index 5a2af7f943..a5d254e115 100644
--- a/activesupport/test/core_ext/duration_test.rb
+++ b/activesupport/test/core_ext/duration_test.rb
@@ -30,7 +30,6 @@ class DurationTest < ActiveSupport::TestCase
assert ActiveSupport::Duration === 1.day
assert !(ActiveSupport::Duration === 1.day.to_i)
assert !(ActiveSupport::Duration === 'foo')
- assert !(ActiveSupport::Duration === ActiveSupport::ProxyObject.new)
end
def test_equals
diff --git a/activesupport/test/core_ext/object/try_test.rb b/activesupport/test/core_ext/object/try_test.rb
index 225c20fa36..efc6beaf02 100644
--- a/activesupport/test/core_ext/object/try_test.rb
+++ b/activesupport/test/core_ext/object/try_test.rb
@@ -30,10 +30,6 @@ class ObjectTryTest < ActiveSupport::TestCase
assert_raise(NoMethodError) { @string.try!(method, 'llo', 'y') }
end
- def test_try_only_block_bang
- assert_equal @string.reverse, @string.try! { |s| s.reverse }
- end
-
def test_valid_method
assert_equal 5, @string.try(:size)
end
@@ -59,6 +55,10 @@ class ObjectTryTest < ActiveSupport::TestCase
assert_equal @string.reverse, @string.try { |s| s.reverse }
end
+ def test_try_only_block_bang
+ assert_equal @string.reverse, @string.try! { |s| s.reverse }
+ end
+
def test_try_only_block_nil
ran = false
nil.try { ran = true }
@@ -69,6 +69,10 @@ class ObjectTryTest < ActiveSupport::TestCase
assert_equal @string.reverse, @string.try { reverse }
end
+ def test_try_with_instance_eval_block_bang
+ assert_equal @string.reverse, @string.try! { reverse }
+ end
+
def test_try_with_private_method_bang
klass = Class.new do
private
diff --git a/activesupport/test/core_ext/string_ext_test.rb b/activesupport/test/core_ext/string_ext_test.rb
index 2f4691817f..119e62369d 100644
--- a/activesupport/test/core_ext/string_ext_test.rb
+++ b/activesupport/test/core_ext/string_ext_test.rb
@@ -260,8 +260,18 @@ class StringInflectionsTest < ActiveSupport::TestCase
end
def test_remove
- assert_equal "Summer", "Fast Summer".remove(/Fast /)
- assert_equal "Summer", "Fast Summer".remove!(/Fast /)
+ original = "This is a good day to die"
+ assert_equal "This is a good day", original.remove(" to die")
+ assert_equal "This is a good day", original.remove(" to ", /die/)
+ assert_equal "This is a good day to die", original
+ end
+
+ def test_remove!
+ original = "This is a very good day to die"
+ assert_equal "This is a good day to die", original.remove!(" very")
+ assert_equal "This is a good day to die", original
+ assert_equal "This is a good day", original.remove!(" to ", /die/)
+ assert_equal "This is a good day", original
end
def test_constantize
@@ -404,11 +414,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/core_ext/time_with_zone_test.rb b/activesupport/test/core_ext/time_with_zone_test.rb
index 3000da8da4..ad4062e5fe 100644
--- a/activesupport/test/core_ext/time_with_zone_test.rb
+++ b/activesupport/test/core_ext/time_with_zone_test.rb
@@ -79,6 +79,11 @@ class TimeWithZoneTest < ActiveSupport::TestCase
assert_equal '1999-12-31 19:00:00 EST -0500', @twz.strftime('%Y-%m-%d %H:%M:%S %Z %z')
end
+ def test_strftime_with_escaping
+ assert_equal '%Z %z', @twz.strftime('%%Z %%z')
+ assert_equal '%EST %-0500', @twz.strftime('%%%Z %%%z')
+ end
+
def test_inspect
assert_equal 'Fri, 31 Dec 1999 19:00:00 EST -05:00', @twz.inspect
end
diff --git a/activesupport/test/dependencies_test.rb b/activesupport/test/dependencies_test.rb
index 899bb75eae..f2f60167c4 100644
--- a/activesupport/test/dependencies_test.rb
+++ b/activesupport/test/dependencies_test.rb
@@ -157,6 +157,31 @@ class DependenciesTest < ActiveSupport::TestCase
end
end
+ def test_ensures_the_expected_constant_is_defined
+ with_autoloading_fixtures do
+ e = assert_raise(LoadError) { Typo }
+ assert_match %r{Unable to autoload constant Typo, expected .*activesupport/test/autoloading_fixtures/typo.rb to define it}, e.message
+ end
+ end
+
+ def test_require_dependency_does_not_assume_any_particular_constant_is_defined
+ with_autoloading_fixtures do
+ require_dependency 'typo'
+ assert_equal 1, TypO
+ end
+ end
+
+ # Regression, see https://github.com/rails/rails/issues/16468.
+ def test_require_dependency_interaction_with_autoloading
+ with_autoloading_fixtures do
+ require_dependency 'typo'
+ assert_equal 1, TypO
+
+ e = assert_raise(LoadError) { Typo }
+ assert_match %r{Unable to autoload constant Typo, expected .*activesupport/test/autoloading_fixtures/typo.rb to define it}, e.message
+ end
+ end
+
def test_module_loading
with_autoloading_fixtures do
assert_kind_of Module, A
diff --git a/activesupport/test/dependencies_test_helpers.rb b/activesupport/test/dependencies_test_helpers.rb
index 9268512a97..e4d5197112 100644
--- a/activesupport/test/dependencies_test_helpers.rb
+++ b/activesupport/test/dependencies_test_helpers.rb
@@ -13,6 +13,7 @@ module DependenciesTestHelpers
ActiveSupport::Dependencies.autoload_paths = prior_autoload_paths
ActiveSupport::Dependencies.mechanism = old_mechanism
ActiveSupport::Dependencies.explicitly_unloadable_constants = []
+ ActiveSupport::Dependencies.clear
end
def with_autoloading_fixtures(&block)
diff --git a/activesupport/test/json/encoding_test.rb b/activesupport/test/json/encoding_test.rb
index ad358ad21d..7e976aa772 100644
--- a/activesupport/test/json/encoding_test.rb
+++ b/activesupport/test/json/encoding_test.rb
@@ -68,7 +68,7 @@ class TestJSONEncoding < ActiveSupport::TestCase
[ 1.0/0.0, %(null) ],
[ -1.0/0.0, %(null) ],
[ BigDecimal('0.0')/BigDecimal('0.0'), %(null) ],
- [ BigDecimal('2.5'), %("#{BigDecimal('2.5').to_s}") ]]
+ [ BigDecimal('2.5'), %("#{BigDecimal('2.5')}") ]]
StringTests = [[ 'this is the <string>', %("this is the \\u003cstring\\u003e")],
[ 'a "string" with quotes & an ampersand', %("a \\"string\\" with quotes \\u0026 an ampersand") ],
diff --git a/activesupport/test/security_utils_test.rb b/activesupport/test/security_utils_test.rb
new file mode 100644
index 0000000000..08d2e3baa6
--- /dev/null
+++ b/activesupport/test/security_utils_test.rb
@@ -0,0 +1,9 @@
+require 'abstract_unit'
+require 'active_support/security_utils'
+
+class SecurityUtilsTest < ActiveSupport::TestCase
+ def test_secure_compare_should_perform_string_comparison
+ assert ActiveSupport::SecurityUtils.secure_compare('a', 'a')
+ assert !ActiveSupport::SecurityUtils.secure_compare('a', 'b')
+ end
+end
diff --git a/guides/source/4_2_release_notes.md b/guides/source/4_2_release_notes.md
index a598c7c319..3a9be62865 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.
@@ -358,9 +358,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.
@@ -395,6 +395,9 @@ Please refer to the [Changelog][action-pack] for detailed changes.
### Deprecations
+* Deprecated the `only_path` option on `*_path` helpers.
+ ([Commit](https://github.com/rails/rails/commit/aa1fadd48fb40dd9396a383696134a259aa59db9))
+
* Deprecated `assert_tag`, `assert_no_tag`, `find_tag` and `find_all_tag` in
favor of `assert_select`.
([Commit](https://github.com/rails/rails-dom-testing/commit/b12850bc5ff23ba4b599bf2770874dd4f11bf750))
@@ -468,7 +471,7 @@ Please refer to the [Changelog][action-pack] for detailed changes.
([Pull Request](https://github.com/rails/rails/pull/14280))
* When the Rails server is set to serve static assets, gzip assets will now be
- served if the client supports it and a pre-generated gzip file (.gz) is on disk.
+ served if the client supports it and a pre-generated gzip file (`.gz`) is on disk.
By default the asset pipeline generates `.gz` files for all compressible assets.
Serving gzip files minimizes data transfer and speeds up asset requests. Always
[use a CDN](http://guides.rubyonrails.org/asset_pipeline.html#cdns) if you are
@@ -476,7 +479,7 @@ Please refer to the [Changelog][action-pack] for detailed changes.
([Pull Request](https://github.com/rails/rails/pull/16466))
* The way `assert_select` works has changed; specifically a different library
- is used to interpret css selectors, build the transient DOM that the
+ is used to interpret CSS selectors, build the transient DOM that the
selectors are applied against, and to extract the data from that DOM. These
changes should only affect edge cases. Examples:
* Values in attribute selectors may need to be quoted if they contain
@@ -534,7 +537,7 @@ Please refer to the [Changelog][action-mailer] for detailed changes.
* Deprecated `*_path` helpers in mailers. Always use `*_url` helpers instead.
([Pull Request](https://github.com/rails/rails/pull/15840))
-* Deprecated `deliver` / `deliver!` in favour of `deliver_now` / `deliver_now!`.
+* Deprecated `deliver` / `deliver!` in favor of `deliver_now` / `deliver_now!`.
([Pull Request](https://github.com/rails/rails/pull/16582))
### Notable changes
@@ -593,7 +596,7 @@ Please refer to the [Changelog][active-record] for detailed changes.
([Pull Request](https://github.com/rails/rails/pull/15704))
* Deprecated returning `nil` from `column_for_attribute` when no column
- exists. It will return a null object in Rails 5.0
+ exists. It will return a null object in Rails 5.0.
([Pull Request](https://github.com/rails/rails/pull/15878))
* Deprecated using `.joins`, `.preload` and `.eager_load` with associations
@@ -645,7 +648,7 @@ Please refer to the [Changelog][active-record] for detailed changes.
([Commit](https://github.com/rails/rails/commit/e2f232aba15937a4b9d14bd91e0392c6d55be58d))
* `ActiveRecord::Dirty` now detects in-place changes to mutable values.
- Serialized attributes on ActiveRecord models will no longer save when
+ Serialized attributes on Active Record models will no longer save when
unchanged. This also works with other types such as string columns and json
columns on PostgreSQL.
(Pull Requests [1](https://github.com/rails/rails/pull/15674),
@@ -750,6 +753,10 @@ 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.
diff --git a/guides/source/_welcome.html.erb b/guides/source/_welcome.html.erb
index f84f1cb376..f2315bfe22 100644
--- a/guides/source/_welcome.html.erb
+++ b/guides/source/_welcome.html.erb
@@ -15,5 +15,5 @@
</p>
<% end %>
<p>
- The guides for earlier releases: <a href="http://guides.rubyonrails.org/v4.1.4/">Rails 4.1.4</a>, <a href="http://guides.rubyonrails.org/v4.0.8/">Rails 4.0.8</a>, <a href="http://guides.rubyonrails.org/v3.2.19/">Rails 3.2.19</a> and <a href="http://guides.rubyonrails.org/v2.3.11/">Rails 2.3.11</a>.
+ The guides for earlier releases: <a href="http://guides.rubyonrails.org/v4.1.6/">Rails 4.1.6</a>, <a href="http://guides.rubyonrails.org/v4.0.10/">Rails 4.0.10</a>, <a href="http://guides.rubyonrails.org/v3.2.19/">Rails 3.2.19</a> and <a href="http://guides.rubyonrails.org/v2.3.11/">Rails 2.3.11</a>.
</p>
diff --git a/guides/source/action_controller_overview.md b/guides/source/action_controller_overview.md
index 8890ea453e..1ca0d9ed55 100644
--- a/guides/source/action_controller_overview.md
+++ b/guides/source/action_controller_overview.md
@@ -1213,12 +1213,12 @@ Create the controller and views.
* `app/views`
```
- errors/
- not_found.html.erb
- unprocessable_entity.html.erb
- server_error.html.erb
- layouts/
- error.html.erb
+ errors/
+ not_found.html.erb
+ unprocessable_entity.html.erb
+ server_error.html.erb
+ layouts/
+ error.html.erb
```
Do not forget to set the correct status code on the controller as shown before.
diff --git a/guides/source/active_job_basics.md b/guides/source/active_job_basics.md
index 9c34418fab..ca851371a9 100644
--- a/guides/source/active_job_basics.md
+++ b/guides/source/active_job_basics.md
@@ -41,10 +41,12 @@ This section will provide a step-by-step guide to creating a job and enqueuing i
### Create the Job
Active Job provides a Rails generator to create jobs. The following will create a
-job in `app/jobs`:
+job in `app/jobs` (with an attached test case under `test/jobs`):
```bash
$ bin/rails generate job guests_cleanup
+invoke test_unit
+create test/jobs/guests_cleanup_job_test.rb
create app/jobs/guests_cleanup_job.rb
```
@@ -52,7 +54,6 @@ You can also create a job that will run on a specific queue:
```bash
$ bin/rails generate job guests_cleanup --queue urgent
-create app/jobs/guests_cleanup_job.rb
```
As you can see, you can generate jobs just like you use other generators with
@@ -78,15 +79,18 @@ end
Enqueue a job like so:
```ruby
-MyJob.perform_later record # Enqueue a job to be performed as soon the queueing system is free.
+# Enqueue a job to be performed as soon the queueing system is free.
+MyJob.perform_later record
```
```ruby
-MyJob.set(wait_until: Date.tomorrow.noon).perform_later(record) # Enqueue a job to be performed tomorrow at noon.
+# Enqueue a job to be performed tomorrow at noon.
+MyJob.set(wait_until: Date.tomorrow.noon).perform_later(record)
```
```ruby
-MyJob.set(wait: 1.week).perform_later(record) # Enqueue a job to be performed 1 week from now.
+# Enqueue a job to be performed 1 week from now.
+MyJob.set(wait: 1.week).perform_later(record)
```
That's it!
@@ -108,9 +112,9 @@ see the API Documentation for [ActiveJob::QueueAdapters](http://api.rubyonrails.
You can easily change your queueing backend:
```ruby
-# be sure to have the adapter gem in your Gemfile and follow the adapter specific
-# installation and deployment instructions
-Rails.application.config.active_job.queue_adapter = :sidekiq
+# be sure to have the adapter gem in your Gemfile and follow
+# the adapter specific installation and deployment instructions
+config.active_job.queue_adapter = :sidekiq
```
@@ -149,15 +153,38 @@ end
# environment
```
-If you want more control on what queue a job will be run you can pass a :queue
-option to #set:
+The default queue name prefix delimiter is '_'. This can be changed by setting
+`config.active_job.queue_name_delimiter` in `application.rb`:
+
+```ruby
+# config/application.rb
+module YourApp
+ class Application < Rails::Application
+ config.active_job.queue_name_prefix = Rails.env
+ config.active_job.queue_name_delimiter = '.'
+ end
+end
+
+# app/jobs/guests_cleanup.rb
+class GuestsCleanupJob < ActiveJob::Base
+ queue_as :low_priority
+ #....
+end
+
+# Now your job will run on queue production.low_priority on your
+# production environment and on staging.low_priority on your staging
+# environment
+```
+
+If you want more control on what queue a job will be run you can pass a `:queue`
+option to `#set`:
```ruby
MyJob.set(queue: :another_queue).perform_later(record)
```
-To control the queue from the job level you can pass a block to queue_as. The
-block will be executed in the job context (so you can access self.arguments)
+To control the queue from the job level you can pass a block to `#queue_as`. The
+block will be executed in the job context (so you can access `self.arguments`)
and you must return the queue name:
```ruby
@@ -179,7 +206,6 @@ end
ProcessVideoJob.perform_later(Video.last)
```
-
NOTE: Make sure your queueing backend "listens" on your queue name. For some
backends you need to specify the queues to listen to.
@@ -240,12 +266,13 @@ UserMailer.welcome(@user).deliver_later
GlobalID
--------
+
Active Job supports GlobalID for parameters. This makes it possible to pass live
Active Record objects to your job instead of class/id pairs, which you then have
to manually deserialize. Before, jobs would look like this:
```ruby
-class TrashableCleanupJob
+class TrashableCleanupJob < ActiveJob::Base
def perform(trashable_class, trashable_id, depth)
trashable = trashable_class.constantize.find(trashable_id)
trashable.cleanup(depth)
@@ -256,14 +283,14 @@ end
Now you can simply do:
```ruby
-class TrashableCleanupJob
+class TrashableCleanupJob < ActiveJob::Base
def perform(trashable, depth)
trashable.cleanup(depth)
end
end
```
-This works with any class that mixes in `ActiveModel::GlobalIdentification`, which
+This works with any class that mixes in `GlobalID::Identification`, which
by default has been mixed into Active Model classes.
diff --git a/guides/source/active_record_basics.md b/guides/source/active_record_basics.md
index ecf3483d7e..bd074d0055 100644
--- a/guides/source/active_record_basics.md
+++ b/guides/source/active_record_basics.md
@@ -31,7 +31,7 @@ Object Relational Mapping system.
in his book _Patterns of Enterprise Application Architecture_. In
Active Record, objects carry both persistent data and behavior which
operates on that data. Active Record takes the opinion that ensuring
-data access logic is part of the object will educate users of that
+data access logic as part of the object will educate users of that
object on how to write to and read from the database.
### Object Relational Mapping
diff --git a/guides/source/active_record_migrations.md b/guides/source/active_record_migrations.md
index 229c6ee458..c8a31fe7b8 100644
--- a/guides/source/active_record_migrations.md
+++ b/guides/source/active_record_migrations.md
@@ -466,7 +466,7 @@ add_foreign_key :articles, :authors
```
This adds a new foreign key to the `author_id` column of the `articles`
-table. The key references the `id` column of the `articles` table. If the
+table. The key references the `id` column of the `authors` table. If the
column names can not be derived from the table names, you can use the
`:column` and `:primary_key` options.
diff --git a/guides/source/active_record_validations.md b/guides/source/active_record_validations.md
index 1c1b863fe9..546c0608ee 100644
--- a/guides/source/active_record_validations.md
+++ b/guides/source/active_record_validations.md
@@ -427,7 +427,7 @@ class Essay < ActiveRecord::Base
validates :content, length: {
minimum: 300,
maximum: 400,
- tokenizer: lambda { |str| str.scan(/\w+/) },
+ tokenizer: lambda { |str| str.split(/\s+/) },
too_short: "must have at least %{count} words",
too_long: "must have at most %{count} words"
}
@@ -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/active_support_core_extensions.md b/guides/source/active_support_core_extensions.md
index de42f13145..f6f96b79c6 100644
--- a/guides/source/active_support_core_extensions.md
+++ b/guides/source/active_support_core_extensions.md
@@ -1833,16 +1833,14 @@ attribute names:
```ruby
def full_messages
- full_messages = []
-
- each do |attribute, messages|
- ...
- attr_name = attribute.to_s.gsub('.', '_').humanize
- attr_name = @base.class.human_attribute_name(attribute, default: attr_name)
- ...
- end
+ map { |attribute, message| full_message(attribute, message) }
+end
- full_messages
+def full_message
+ ...
+ attr_name = attribute.to_s.tr('.', '_').humanize
+ attr_name = @base.class.human_attribute_name(attribute, default: attr_name)
+ ...
end
```
diff --git a/guides/source/active_support_instrumentation.md b/guides/source/active_support_instrumentation.md
index 7033947468..9dfacce560 100644
--- a/guides/source/active_support_instrumentation.md
+++ b/guides/source/active_support_instrumentation.md
@@ -135,7 +135,9 @@ Action Controller
| `:format` | html/js/json/xml etc |
| `:method` | HTTP request verb |
| `:path` | Request path |
+| `:status` | HTTP status code |
| `:view_runtime` | Amount spent in view in ms |
+| `:db_runtime` | Amount spent executing database queries in ms |
```ruby
{
@@ -223,11 +225,11 @@ Active Record
### sql.active_record
-| Key | Value |
-| ------------ | --------------------- |
-| `:sql` | SQL statement |
-| `:name` | Name of the operation |
-| `:object_id` | `self.object_id` |
+| Key | Value |
+| ---------------- | --------------------- |
+| `:sql` | SQL statement |
+| `:name` | Name of the operation |
+| `:connection_id` | `self.object_id` |
INFO. The adapters will add their own data as well.
diff --git a/guides/source/asset_pipeline.md b/guides/source/asset_pipeline.md
index c19c8e0bec..ae0f19c02a 100644
--- a/guides/source/asset_pipeline.md
+++ b/guides/source/asset_pipeline.md
@@ -1347,8 +1347,8 @@ config.assets.digest = true
Rails 4 no longer sets default config values for Sprockets in `test.rb`, so
`test.rb` now requires Sprockets configuration. The old defaults in the test
-environment are: `config.assets.compile = true`, `config.assets.compress =
-false`, `config.assets.debug = false` and `config.assets.digest = false`.
+environment are: `config.assets.compile = true`, `config.assets.compress = false`,
+`config.assets.debug = false` and `config.assets.digest = false`.
The following should also be added to `Gemfile`:
diff --git a/guides/source/command_line.md b/guides/source/command_line.md
index b9014724bd..e065d56168 100644
--- a/guides/source/command_line.md
+++ b/guides/source/command_line.md
@@ -394,16 +394,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
diff --git a/guides/source/configuring.md b/guides/source/configuring.md
index 58c3f217eb..2957232186 100644
--- a/guides/source/configuring.md
+++ b/guides/source/configuring.md
@@ -153,7 +153,7 @@ pipeline is enabled. It is set to true by default.
* `config.assets.manifest` defines the full path to be used for the asset precompiler's manifest file. Defaults to a file named `manifest-<random>.json` in the `config.assets.prefix` directory within the public folder.
-* `config.assets.digest` enables the use of MD5 fingerprints in asset names. Set to `true` by default in `production.rb`.
+* `config.assets.digest` enables the use of MD5 fingerprints in asset names. Set to `true` by default in `production.rb` and `development.rb`.
* `config.assets.debug` disables the concatenation and compression of assets. Set to `true` by default in `development.rb`.
diff --git a/guides/source/form_helpers.md b/guides/source/form_helpers.md
index 16fa23c129..cb45e38614 100644
--- a/guides/source/form_helpers.md
+++ b/guides/source/form_helpers.md
@@ -506,7 +506,7 @@ As the name implies, this only generates option tags. To generate a working sele
<%= collection_select(:person, :city_id, City.all, :id, :name) %>
```
-As with other helpers, if you were to use the collection_select helper on a form builder scoped to the @person object, the syntax would be:
+As with other helpers, if you were to use the `collection_select` helper on a form builder scoped to the `@person` object, the syntax would be:
```erb
<%= f.collection_select(:city_id, City.all, :id, :name) %>
diff --git a/guides/source/getting_started.md b/guides/source/getting_started.md
index 1769448531..92f8ef5b08 100644
--- a/guides/source/getting_started.md
+++ b/guides/source/getting_started.md
@@ -195,8 +195,8 @@ TIP: Compiling CoffeeScript and JavaScript asset compression requires you
have a JavaScript runtime available on your system, in the absence
of a runtime you will see an `execjs` error during asset compilation.
Usually Mac OS X and Windows come with a JavaScript runtime installed.
-Rails adds the `therubyracer` gem to the generated `Gemfile` in a
-commented line for new apps and you can uncomment if you need it.
+Rails adds the `therubyracer` gem to the generated `Gemfile` in a
+commented line for new apps and you can uncomment if you need it.
`therubyrhino` is the recommended runtime for JRuby users and is added by
default to the `Gemfile` in apps generated under JRuby. You can investigate
all the supported runtimes at [ExecJS](https://github.com/sstephenson/execjs#readme).
@@ -338,8 +338,8 @@ You can create, read, update and destroy items for a resource and these
operations are referred to as _CRUD_ operations.
Rails provides a `resources` method which can be used to declare a standard REST
-resource. Here's what `config/routes.rb` should look like after the
-_article resource_ is declared.
+resource. You need to add the _article resource_ to the
+`config/routes.rb` as follows:
```ruby
Rails.application.routes.draw do
diff --git a/guides/source/ruby_on_rails_guides_guidelines.md b/guides/source/ruby_on_rails_guides_guidelines.md
index 6206b3c715..c0438f6341 100644
--- a/guides/source/ruby_on_rails_guides_guidelines.md
+++ b/guides/source/ruby_on_rails_guides_guidelines.md
@@ -54,6 +54,7 @@ API Documentation Guidelines
The guides and the API should be coherent and consistent where appropriate. In particular, these sections of the [API Documentation Guidelines](api_documentation_guidelines.html) also apply to the guides:
* [Wording](api_documentation_guidelines.html#wording)
+* [English](api_documentation_guidelines.html#english)
* [Example Code](api_documentation_guidelines.html#example-code)
* [Filenames](api_documentation_guidelines.html#file-names)
* [Fonts](api_documentation_guidelines.html#fonts)
diff --git a/guides/source/testing.md b/guides/source/testing.md
index b784098fbb..8ad1eed72c 100644
--- a/guides/source/testing.md
+++ b/guides/source/testing.md
@@ -905,8 +905,10 @@ Testing Routes
Like everything else in your Rails application, it is recommended that you test your routes. An example test for a route in the default `show` action of `Articles` controller above should look like:
```ruby
-test "should route to article" do
- assert_routing '/articles/1', {controller: "articles", action: "show", id: "1"}
+class ArticleRoutesTest < ActionController::TestCase
+ test "should route to article" do
+ assert_routing '/articles/1', { controller: "articles", action: "show", id: "1" }
+ end
end
```
diff --git a/guides/source/upgrading_ruby_on_rails.md b/guides/source/upgrading_ruby_on_rails.md
index 8a1d7af923..aac2aef615 100644
--- a/guides/source/upgrading_ruby_on_rails.md
+++ b/guides/source/upgrading_ruby_on_rails.md
@@ -177,7 +177,7 @@ after_bundle do
end
```
-### Rails Html Sanitizer
+### Rails HTML Sanitizer
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
@@ -200,15 +200,18 @@ Read the [gem's readme](https://github.com/rails/rails-html-sanitizer) for more
The documentation for `PermitScrubber` and `TargetScrubber` explains how you
can gain complete control over when and how elements should be stripped.
-If your application needs to use the old behaviour, include `rails-deprecated_sanitizer` in your Gemfile:
+If your application needs to use the old sanitizer implementation, include `rails-deprecated_sanitizer` in your Gemfile:
```ruby
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).
-TODO: Mention https://github.com/rails/rails/commit/4e97d7585a2f4788b9eed98c6cdaf4bb6f2cf5ce
+
+### Masked Authenticity Tokens
+In order to mitigate SSL attacks, `form_authenticity_token` is now masked so that it varies with each request. Thus, tokens are validated by unmasking and then decrypting. As a result, any strategies for verifying requests from non-rails forms that relied on a static session CSRF token have to take this into account.
Upgrading from Rails 4.0 to Rails 4.1
-------------------------------------
@@ -233,7 +236,7 @@ will now trigger CSRF protection. Switch to
xhr :get, :index, format: :js
```
-to explicitly test an XmlHttpRequest.
+to explicitly test an `XmlHttpRequest`.
If you really mean to load JavaScript from remote `<script>` tags, skip CSRF
protection on that action.
@@ -588,7 +591,7 @@ response body, you should be using `render :plain` as most browsers will escape
unsafe content in the response for you.
We will be deprecating the use of `render :text` in a future version. So please
-start using the more precise `:plain:`, `:html`, and `:body` options instead.
+start using the more precise `:plain`, `:html`, and `:body` options instead.
Using `render :text` may pose a security risk, as the content is sent as
`text/html`.
@@ -767,7 +770,7 @@ this gem such as `whitelist_attributes` or `mass_assignment_sanitizer` options.
* Rails 4.0 has deprecated `ActiveRecord::TestCase` in favor of `ActiveSupport::TestCase`.
* Rails 4.0 has deprecated the old-style hash based finder API. This means that
- methods which previously accepted "finder options" no longer do.
+ methods which previously accepted "finder options" no longer do. For example, `Book.find(:all, conditions: { name: '1984' })` has been deprecated in favor of `Book.where(name: '1984')`
* All dynamic methods except for `find_by_...` and `find_by_...!` are deprecated.
Here's how you can handle the changes:
@@ -918,7 +921,7 @@ The order in which helpers from more than one directory are loaded has changed i
### Active Record Observer and Action Controller Sweeper
-Active Record Observer and Action Controller Sweeper have been extracted to the `rails-observers` gem. You will need to add the `rails-observers` gem if you require these features.
+`ActiveRecord::Observer` and `ActionController::Caching::Sweeper` have been extracted to the `rails-observers` gem. You will need to add the `rails-observers` gem if you require these features.
### sprockets-rails
diff --git a/rails.gemspec b/rails.gemspec
index a304b16f57..99685252e0 100644
--- a/rails.gemspec
+++ b/rails.gemspec
@@ -16,7 +16,7 @@ Gem::Specification.new do |s|
s.email = 'david@loudthinking.com'
s.homepage = 'http://www.rubyonrails.org'
- s.files = ['README.md'] + Dir['guides/**/*']
+ s.files = ['README.md'] + Dir['guides/**/*'] - Dir['guides/output/**/*']
s.add_dependency 'activesupport', version
s.add_dependency 'actionpack', version
diff --git a/railties/CHANGELOG.md b/railties/CHANGELOG.md
index e1a11482e6..0d91b19ed2 100644
--- a/railties/CHANGELOG.md
+++ b/railties/CHANGELOG.md
@@ -89,13 +89,7 @@
*Rafael Mendonça França*
-* Add a generic --skip-gems options to generator
-
- This option is useful if users want to remove some gems like jbuilder,
- turbolinks, coffee-rails, etc that don't have specific options on the
- generator.
-
- rails new my_app --skip-gems turbolinks coffee-rails
+* 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 bc966e87c6..18d9cb72d6 100644
--- a/railties/lib/rails/application.rb
+++ b/railties/lib/rails/application.rb
@@ -88,6 +88,7 @@ module Rails
def inherited(base)
super
Rails.app_class = base
+ add_lib_to_load_path!(find_root(base.called_from))
end
def instance
@@ -98,6 +99,10 @@ module Rails
new(initial_variable_values, &block).run_load_hooks!
end
+ def find_root(from)
+ find_root_with_flag "config.ru", from, Dir.pwd
+ end
+
# Makes the +new+ method public.
#
# Note that Rails::Application inherits from Rails::Engine, which
@@ -129,8 +134,6 @@ module Rails
# are these actually used?
@initial_variable_values = initial_variable_values
@block = block
-
- add_lib_to_load_path!
end
# Returns true if the application is initialized.
@@ -313,8 +316,8 @@ module Rails
# are changing config.root inside your application definition or having a custom
# Rails application, you will need to add lib to $LOAD_PATH on your own in case
# you need to load files in lib/ during the application configuration as well.
- def add_lib_to_load_path! #:nodoc:
- path = File.join config.root, 'lib'
+ def self.add_lib_to_load_path!(root) #:nodoc:
+ path = File.join root, 'lib'
if File.exist?(path) && !$LOAD_PATH.include?(path)
$LOAD_PATH.unshift(path)
end
@@ -358,7 +361,7 @@ module Rails
end
def config #:nodoc:
- @config ||= Application::Configuration.new(find_root_with_flag("config.ru", Dir.pwd))
+ @config ||= Application::Configuration.new(self.class.find_root(self.class.called_from))
end
def config=(configuration) #:nodoc:
diff --git a/railties/lib/rails/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/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/gem_version.rb b/railties/lib/rails/gem_version.rb
index 4411ec33ef..8abed99f2c 100644
--- a/railties/lib/rails/gem_version.rb
+++ b/railties/lib/rails/gem_version.rb
@@ -8,7 +8,7 @@ module Rails
MAJOR = 4
MINOR = 2
TINY = 0
- PRE = "beta2"
+ PRE = "beta4"
STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".")
end
diff --git a/railties/lib/rails/generators/app_base.rb b/railties/lib/rails/generators/app_base.rb
index 1eca86bd30..92ed9136a0 100644
--- a/railties/lib/rails/generators/app_base.rb
+++ b/railties/lib/rails/generators/app_base.rb
@@ -41,9 +41,6 @@ module Rails
class_option :skip_active_record, type: :boolean, aliases: '-O', default: false,
desc: 'Skip Active Record files'
- class_option :skip_gems, type: :array, default: [],
- desc: 'Skip the provided gems files'
-
class_option :skip_sprockets, type: :boolean, aliases: '-S', default: false,
desc: 'Skip Sprockets files'
@@ -65,6 +62,9 @@ module Rails
class_option :edge, type: :boolean, default: false,
desc: "Setup the #{name} with Gemfile pointing to Rails repository"
+ class_option :skip_turbolinks, type: :boolean, default: false,
+ desc: 'Skip turbolinks gem'
+
class_option :skip_test_unit, type: :boolean, aliases: '-T', default: false,
desc: 'Skip Test::Unit files'
@@ -79,7 +79,7 @@ module Rails
end
def initialize(*args)
- @gem_filter = lambda { |gem| !options[:skip_gems].include?(gem.name) }
+ @gem_filter = lambda { |gem| true }
@extra_entries = []
super
convert_database_option_for_jruby
@@ -287,8 +287,11 @@ module Rails
"Use #{options[:javascript]} as the JavaScript library")
end
- gems << GemfileEntry.version("turbolinks", nil,
- "Turbolinks makes following links in your web application faster. Read more: https://github.com/rails/turbolinks")
+ unless options[:skip_turbolinks]
+ gems << GemfileEntry.version("turbolinks", nil,
+ "Turbolinks makes following links in your web application faster. Read more: https://github.com/rails/turbolinks")
+ end
+
gems
end
end
diff --git a/railties/lib/rails/generators/rails/app/templates/Gemfile b/railties/lib/rails/generators/rails/app/templates/Gemfile
index 827039f144..5961f7515c 100644
--- a/railties/lib/rails/generators/rails/app/templates/Gemfile
+++ b/railties/lib/rails/generators/rails/app/templates/Gemfile
@@ -40,7 +40,7 @@ group :development, :test do
<% end -%>
end
-<% if RUBY_PLATFORM.match(/bccwin|cygwin|emx|mingw|mswin|wince/) -%>
+<% if RUBY_PLATFORM.match(/bccwin|cygwin|emx|mingw|mswin|wince|java/) -%>
# Windows does not include zoneinfo files, so bundle the tzinfo-data gem
-gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw]
+gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby]
<% end -%>
diff --git a/railties/lib/rails/rack/log_tailer.rb b/railties/lib/rails/rack/log_tailer.rb
index bc26421a9e..46517713c9 100644
--- a/railties/lib/rails/rack/log_tailer.rb
+++ b/railties/lib/rails/rack/log_tailer.rb
@@ -4,7 +4,7 @@ module Rails
module Rack
class LogTailer
def initialize(app, log = nil)
- ActiveSupport::Deprecation.warn "LogTailer is deprecated and will be removed on Rails 5"
+ ActiveSupport::Deprecation.warn('LogTailer is deprecated and will be removed on Rails 5.')
@app = app
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/lib/rails/templates/rails/mailers/email.html.erb b/railties/lib/rails/templates/rails/mailers/email.html.erb
index 1dc1d70f8d..0b08a01896 100644
--- a/railties/lib/rails/templates/rails/mailers/email.html.erb
+++ b/railties/lib/rails/templates/rails/mailers/email.html.erb
@@ -2,6 +2,10 @@
<html><head>
<meta name="viewport" content="width=device-width" />
<style type="text/css">
+ html, body, iframe {
+ height: 100%;
+ }
+
body {
margin: 0;
}
@@ -38,7 +42,6 @@
iframe {
border: 0;
width: 100%;
- height: 800px;
}
</style>
</head>
diff --git a/railties/test/application/configuration_test.rb b/railties/test/application/configuration_test.rb
index 0eddf644d9..2b6eb3624a 100644
--- a/railties/test/application/configuration_test.rb
+++ b/railties/test/application/configuration_test.rb
@@ -59,6 +59,20 @@ module ApplicationTests
end
end
+ test "lib dir is on LOAD_PATH during config" do
+ app_file 'lib/my_logger.rb', <<-RUBY
+ require "logger"
+ class MyLogger < ::Logger
+ end
+ RUBY
+ add_to_top_of_config <<-RUBY
+ require 'my_logger'
+ config.logger = MyLogger.new STDOUT
+ RUBY
+ require "#{app_path}/config/environment"
+ assert_equal 'MyLogger', Rails.application.config.logger.class.name
+ end
+
test "a renders exception on pending migration" do
add_to_config <<-RUBY
config.active_record.migration_error = :page_load
diff --git a/railties/test/application/middleware/exceptions_test.rb b/railties/test/application/middleware/exceptions_test.rb
index 42096cfec4..a7472b37f1 100644
--- a/railties/test/application/middleware/exceptions_test.rb
+++ b/railties/test/application/middleware/exceptions_test.rb
@@ -60,6 +60,21 @@ module ApplicationTests
assert_equal "YOU FAILED BRO", last_response.body
end
+ test "url generation error when action_dispatch.show_exceptions is set raises an exception" do
+ controller :foo, <<-RUBY
+ class FooController < ActionController::Base
+ def index
+ raise ActionController::UrlGenerationError
+ end
+ end
+ RUBY
+
+ app.config.action_dispatch.show_exceptions = true
+
+ get '/foo'
+ assert_equal 500, last_response.status
+ end
+
test "unspecified route when action_dispatch.show_exceptions is not set raises an exception" do
app.config.action_dispatch.show_exceptions = false
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/generators/app_generator_test.rb b/railties/test/generators/app_generator_test.rb
index b492258efb..b7cbe04003 100644
--- a/railties/test/generators/app_generator_test.rb
+++ b/railties/test/generators/app_generator_test.rb
@@ -450,12 +450,11 @@ class AppGeneratorTest < Rails::Generators::TestCase
end
end
- def test_generator_if_skip_gems_is_given
- run_generator [destination_root, "--skip-gems", "turbolinks", "coffee-rails"]
+ def test_generator_if_skip_turbolinks_is_given
+ run_generator [destination_root, "--skip-turbolinks"]
assert_file "Gemfile" do |content|
assert_no_match(/turbolinks/, content)
- assert_no_match(/coffee-rails/, content)
end
assert_file "app/views/layouts/application.html.erb" do |content|
assert_no_match(/data-turbolinks-track/, content)
@@ -491,7 +490,7 @@ class AppGeneratorTest < Rails::Generators::TestCase
def test_psych_gem
run_generator
- gem_regex = /gem 'psych',\s+'~> 2.0', \s+platforms: :rbx/
+ gem_regex = /gem 'psych',\s+'~> 2.0',\s+platforms: :rbx/
assert_file "Gemfile" do |content|
if defined?(Rubinius)
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
diff --git a/version.rb b/version.rb
index 4411ec33ef..8abed99f2c 100644
--- a/version.rb
+++ b/version.rb
@@ -8,7 +8,7 @@ module Rails
MAJOR = 4
MINOR = 2
TINY = 0
- PRE = "beta2"
+ PRE = "beta4"
STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".")
end