aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Gemfile20
-rw-r--r--Gemfile.lock12
-rw-r--r--actioncable/Rakefile2
-rw-r--r--actioncable/lib/action_cable/connection/client_socket.rb2
-rw-r--r--actionmailer/Rakefile2
-rw-r--r--actionmailer/lib/action_mailer/preview.rb9
-rw-r--r--actionpack/CHANGELOG.md30
-rw-r--r--actionpack/Rakefile2
-rw-r--r--actionpack/lib/action_controller/metal/conditional_get.rb5
-rw-r--r--actionpack/lib/action_controller/metal/data_streaming.rb3
-rw-r--r--actionpack/lib/action_controller/metal/implicit_render.rb4
-rw-r--r--actionpack/lib/action_controller/metal/redirecting.rb2
-rw-r--r--actionpack/lib/action_controller/metal/strong_parameters.rb7
-rw-r--r--actionpack/lib/action_controller/test_case.rb14
-rw-r--r--actionpack/lib/action_dispatch/http/response.rb23
-rw-r--r--actionpack/lib/action_dispatch/journey/nfa/dot.rb2
-rw-r--r--actionpack/lib/action_dispatch/middleware/cookies.rb4
-rw-r--r--actionpack/lib/action_dispatch/middleware/session/cache_store.rb2
-rw-r--r--actionpack/lib/action_dispatch/middleware/stack.rb2
-rw-r--r--actionpack/lib/action_dispatch/routing/mapper.rb4
-rw-r--r--actionpack/lib/action_dispatch/routing/route_set.rb25
-rw-r--r--actionpack/lib/action_dispatch/routing/routes_proxy.rb2
-rw-r--r--actionpack/lib/action_dispatch/testing/integration.rb6
-rw-r--r--actionpack/test/controller/force_ssl_test.rb2
-rw-r--r--actionpack/test/controller/integration_test.rb36
-rw-r--r--actionpack/test/controller/parameters/parameters_permit_test.rb7
-rw-r--r--actionpack/test/controller/render_test.rb2
-rw-r--r--actionpack/test/controller/request/test_request_test.rb5
-rw-r--r--actionpack/test/controller/required_params_test.rb6
-rw-r--r--actionpack/test/controller/routing_test.rb4
-rw-r--r--actionpack/test/controller/send_file_test.rb14
-rw-r--r--actionpack/test/dispatch/cookies_test.rb27
-rw-r--r--actionpack/test/dispatch/routing_test.rb42
-rw-r--r--actionview/Rakefile2
-rw-r--r--actionview/lib/action_view/helpers/asset_tag_helper.rb33
-rw-r--r--actionview/lib/action_view/helpers/asset_url_helper.rb72
-rw-r--r--actionview/lib/action_view/helpers/capture_helper.rb2
-rw-r--r--actionview/lib/action_view/helpers/date_helper.rb30
-rw-r--r--actionview/lib/action_view/helpers/form_helper.rb5
-rw-r--r--actionview/lib/action_view/helpers/form_tag_helper.rb33
-rw-r--r--actionview/lib/action_view/layouts.rb33
-rw-r--r--actionview/test/template/tag_helper_test.rb4
-rw-r--r--actionview/test/template/template_test.rb6
-rw-r--r--activejob/Rakefile2
-rw-r--r--activejob/lib/active_job/arguments.rb2
-rw-r--r--activejob/lib/active_job/test_helper.rb2
-rw-r--r--activejob/test/cases/exceptions_test.rb2
-rw-r--r--activejob/test/cases/test_helper_test.rb7
-rw-r--r--activejob/test/jobs/application_job.rb4
-rw-r--r--activejob/test/jobs/inherited_job.rb5
-rw-r--r--activemodel/Rakefile2
-rw-r--r--activemodel/lib/active_model/type/decimal.rb25
-rw-r--r--activemodel/lib/active_model/type/helpers/numeric.rb13
-rw-r--r--activemodel/lib/active_model/type/immutable_string.rb11
-rw-r--r--activerecord/CHANGELOG.md19
-rw-r--r--activerecord/Rakefile2
-rw-r--r--activerecord/lib/active_record/association_relation.rb5
-rw-r--r--activerecord/lib/active_record/associations.rb19
-rw-r--r--activerecord/lib/active_record/associations/association.rb8
-rw-r--r--activerecord/lib/active_record/associations/collection_association.rb43
-rw-r--r--activerecord/lib/active_record/associations/collection_proxy.rb25
-rw-r--r--activerecord/lib/active_record/associations/has_many_association.rb2
-rw-r--r--activerecord/lib/active_record/associations/join_dependency.rb12
-rw-r--r--activerecord/lib/active_record/associations/join_dependency/join_part.rb4
-rw-r--r--activerecord/lib/active_record/associations/preloader/association.rb24
-rw-r--r--activerecord/lib/active_record/associations/preloader/collection_association.rb1
-rw-r--r--activerecord/lib/active_record/associations/preloader/singular_association.rb1
-rw-r--r--activerecord/lib/active_record/associations/singular_association.rb12
-rw-r--r--activerecord/lib/active_record/attribute.rb2
-rw-r--r--activerecord/lib/active_record/attribute_methods/primary_key.rb6
-rw-r--r--activerecord/lib/active_record/attribute_methods/read.rb10
-rw-r--r--activerecord/lib/active_record/attribute_methods/time_zone_conversion.rb16
-rw-r--r--activerecord/lib/active_record/attribute_methods/write.rb14
-rw-r--r--activerecord/lib/active_record/autosave_association.rb4
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb4
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract_adapter.rb12
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb40
-rw-r--r--activerecord/lib/active_record/connection_adapters/mysql/database_statements.rb16
-rw-r--r--activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb6
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/oid.rb2
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/oid/array.rb13
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb (renamed from activerecord/lib/active_record/connection_adapters/postgresql/oid/rails_5_1_point.rb)19
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/oid/point.rb28
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb55
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb6
-rw-r--r--activerecord/lib/active_record/connection_handling.rb2
-rw-r--r--activerecord/lib/active_record/core.rb6
-rw-r--r--activerecord/lib/active_record/dynamic_matchers.rb10
-rw-r--r--activerecord/lib/active_record/fixtures.rb2
-rw-r--r--activerecord/lib/active_record/migration/command_recorder.rb10
-rw-r--r--activerecord/lib/active_record/model_schema.rb25
-rw-r--r--activerecord/lib/active_record/nested_attributes.rb31
-rw-r--r--activerecord/lib/active_record/persistence.rb12
-rw-r--r--activerecord/lib/active_record/querying.rb4
-rw-r--r--activerecord/lib/active_record/reflection.rb25
-rw-r--r--activerecord/lib/active_record/relation.rb9
-rw-r--r--activerecord/lib/active_record/relation/calculations.rb2
-rw-r--r--activerecord/lib/active_record/relation/delegation.rb2
-rw-r--r--activerecord/lib/active_record/relation/finder_methods.rb6
-rw-r--r--activerecord/lib/active_record/relation/predicate_builder.rb28
-rw-r--r--activerecord/lib/active_record/relation/predicate_builder/case_sensitive_handler.rb21
-rw-r--r--activerecord/lib/active_record/relation/predicate_builder/class_handler.rb6
-rw-r--r--activerecord/lib/active_record/relation/query_methods.rb16
-rw-r--r--activerecord/lib/active_record/relation/where_clause_factory.rb2
-rw-r--r--activerecord/lib/active_record/result.rb4
-rw-r--r--activerecord/lib/active_record/statement_cache.rb4
-rw-r--r--activerecord/lib/active_record/table_metadata.rb2
-rw-r--r--activerecord/lib/active_record/tasks/mysql_database_tasks.rb2
-rw-r--r--activerecord/lib/active_record/tasks/postgresql_database_tasks.rb17
-rw-r--r--activerecord/lib/active_record/type.rb4
-rw-r--r--activerecord/lib/active_record/type/type_map.rb6
-rw-r--r--activerecord/lib/active_record/validations/uniqueness.rb32
-rw-r--r--activerecord/test/cases/adapters/mysql2/connection_test.rb21
-rw-r--r--activerecord/test/cases/adapters/postgresql/array_test.rb6
-rw-r--r--activerecord/test/cases/adapters/postgresql/geometric_test.rb12
-rw-r--r--activerecord/test/cases/adapters/postgresql/rename_table_test.rb8
-rw-r--r--activerecord/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb6
-rw-r--r--activerecord/test/cases/associations/belongs_to_associations_test.rb6
-rw-r--r--activerecord/test/cases/associations/inverse_associations_test.rb27
-rw-r--r--activerecord/test/cases/attribute_methods/read_test.rb1
-rw-r--r--activerecord/test/cases/attribute_methods_test.rb10
-rw-r--r--activerecord/test/cases/attributes_test.rb6
-rw-r--r--activerecord/test/cases/autosave_association_test.rb2
-rw-r--r--activerecord/test/cases/enum_test.rb40
-rw-r--r--activerecord/test/cases/fixtures_test.rb4
-rw-r--r--activerecord/test/cases/migration/column_attributes_test.rb2
-rw-r--r--activerecord/test/cases/migration/columns_test.rb8
-rw-r--r--activerecord/test/cases/quoting_test.rb8
-rw-r--r--activerecord/test/cases/relation/where_test.rb2
-rw-r--r--activerecord/test/cases/relation_test.rb8
-rw-r--r--activerecord/test/cases/view_test.rb12
-rw-r--r--activerecord/test/fixtures/all/namespaced/accounts.yml2
-rw-r--r--activerecord/test/fixtures/books.yml1
-rw-r--r--activerecord/test/models/book.rb1
-rw-r--r--activerecord/test/schema/schema.rb1
-rw-r--r--activesupport/Rakefile2
-rwxr-xr-xactivesupport/bin/generate_tables2
-rw-r--r--activesupport/lib/active_support/backtrace_cleaner.rb6
-rw-r--r--activesupport/lib/active_support/cache/memory_store.rb2
-rw-r--r--activesupport/lib/active_support/callbacks.rb20
-rw-r--r--activesupport/lib/active_support/core_ext/class/subclasses.rb17
-rw-r--r--activesupport/lib/active_support/dependencies.rb2
-rw-r--r--activesupport/lib/active_support/i18n_railtie.rb17
-rw-r--r--activesupport/lib/active_support/message_encryptor.rb7
-rw-r--r--activesupport/lib/active_support/multibyte/unicode.rb24
-rw-r--r--activesupport/lib/active_support/notifications/fanout.rb2
-rw-r--r--activesupport/lib/active_support/testing/assertions.rb2
-rw-r--r--activesupport/lib/active_support/time_with_zone.rb4
-rw-r--r--activesupport/test/core_ext/duration_test.rb6
-rw-r--r--activesupport/test/message_encryptor_test.rb10
-rw-r--r--activesupport/test/multibyte_grapheme_break_conformance_test.rb2
-rw-r--r--activesupport/test/multibyte_normalization_conformance_test.rb2
-rw-r--r--activesupport/test/test_case_test.rb9
-rw-r--r--activesupport/test/xml_mini/jdom_engine_test.rb3
-rw-r--r--guides/assets/stylesheets/main.css3
-rw-r--r--guides/bug_report_templates/active_job_gem.rb32
-rw-r--r--guides/bug_report_templates/active_job_master.rb31
-rw-r--r--guides/rails_guides/levenshtein.rb4
-rw-r--r--guides/rails_guides/markdown/renderer.rb17
-rw-r--r--guides/source/5_0_release_notes.md8
-rw-r--r--guides/source/action_view_overview.md14
-rw-r--r--guides/source/active_record_callbacks.md2
-rw-r--r--guides/source/active_record_querying.md2
-rw-r--r--guides/source/active_support_core_extensions.md2
-rw-r--r--guides/source/asset_pipeline.md13
-rw-r--r--guides/source/association_basics.md12
-rw-r--r--guides/source/caching_with_rails.md2
-rw-r--r--guides/source/configuring.md8
-rw-r--r--guides/source/contributing_to_ruby_on_rails.md3
-rw-r--r--guides/source/credits.html.erb4
-rw-r--r--guides/source/engines.md2
-rw-r--r--guides/source/getting_started.md3
-rw-r--r--guides/source/i18n.md2
-rw-r--r--guides/source/initialization.md4
-rw-r--r--guides/source/security.md4
-rw-r--r--guides/source/testing.md19
-rw-r--r--railties/lib/rails/app_loader.rb2
-rw-r--r--railties/lib/rails/commands/server.rb2
-rw-r--r--railties/lib/rails/generators.rb4
-rw-r--r--railties/lib/rails/generators/app_base.rb15
-rw-r--r--railties/lib/rails/generators/base.rb4
-rw-r--r--railties/lib/rails/generators/rails/app/templates/config/initializers/new_framework_defaults.rb.tt4
-rw-r--r--railties/lib/rails/templates/rails/mailers/email.html.erb5
-rw-r--r--railties/test/application/asset_debugging_test.rb97
-rw-r--r--railties/test/application/bin_setup_test.rb18
-rw-r--r--railties/test/json_params_parsing_test.rb16
-rwxr-xr-xtools/profile2
187 files changed, 1317 insertions, 720 deletions
diff --git a/Gemfile b/Gemfile
index 83276212f7..7fec1d72d8 100644
--- a/Gemfile
+++ b/Gemfile
@@ -25,10 +25,10 @@ gem "bcrypt", "~> 3.1.11", require: false
gem "uglifier", ">= 1.3.0", require: false
# Track stable branch of sass because it doesn't have circular require warnings.
-gem "sass", github: "sass/sass", branch: "stable", require: false
+gem "sass", git: "https://github.com/sass/sass", branch: "stable", require: false
# FIXME: Remove this fork after https://github.com/nex3/rb-inotify/pull/49 is fixed.
-gem "rb-inotify", github: "matthewd/rb-inotify", branch: "close-handling", require: false
+gem "rb-inotify", git: "https://github.com/matthewd/rb-inotify", branch: "close-handling", require: false
group :doc do
gem "sdoc", "~> 0.4.0"
@@ -43,19 +43,19 @@ gem "listen", "~> 3.0.5", require: false
# Active Job.
group :job do
- gem "resque", github: "resque/resque", require: false
+ gem "resque", git: "https://github.com/resque/resque", require: false
gem "resque-scheduler", require: false
gem "sidekiq", require: false
gem "sucker_punch", require: false
- gem "delayed_job", require: false, github: "collectiveidea/delayed_job"
- gem "queue_classic", github: "QueueClassic/queue_classic", branch: "master", require: false, platforms: :ruby
+ gem "delayed_job", require: false, git: "https://github.com/collectiveidea/delayed_job"
+ gem "queue_classic", git: "https://github.com/QueueClassic/queue_classic", branch: "master", require: false, platforms: :ruby
gem "sneakers", require: false
gem "que", require: false
gem "backburner", require: false
#TODO: add qu after it support Rails 5.1
# gem 'qu-rails', github: "bkeepers/qu", branch: "master", require: false
gem "qu-redis", require: false
- gem "delayed_job_active_record", require: false, github: "collectiveidea/delayed_job_active_record"
+ gem "delayed_job_active_record", require: false, git: "https://github.com/collectiveidea/delayed_job_active_record"
gem "sequel", require: false
end
@@ -109,10 +109,10 @@ end
platforms :jruby do
if ENV["AR_JDBC"]
- gem "activerecord-jdbcsqlite3-adapter", github: "jruby/activerecord-jdbc-adapter", branch: "master"
+ gem "activerecord-jdbcsqlite3-adapter", git: "https://github.com/jruby/activerecord-jdbc-adapter", branch: "master"
group :db do
- gem "activerecord-jdbcmysql-adapter", github: "jruby/activerecord-jdbc-adapter", branch: "master"
- gem "activerecord-jdbcpostgresql-adapter", github: "jruby/activerecord-jdbc-adapter", branch: "master"
+ gem "activerecord-jdbcmysql-adapter", git: "https://github.com/jruby/activerecord-jdbc-adapter", branch: "master"
+ gem "activerecord-jdbcpostgresql-adapter", git: "https://github.com/jruby/activerecord-jdbc-adapter", branch: "master"
end
else
gem "activerecord-jdbcsqlite3-adapter", ">= 1.3.0"
@@ -134,7 +134,7 @@ if ENV["ORACLE_ENHANCED"]
platforms :ruby do
gem "ruby-oci8", "~> 2.2"
end
- gem "activerecord-oracle_enhanced-adapter", github: "rsim/oracle-enhanced", branch: "master"
+ gem "activerecord-oracle_enhanced-adapter", git: "https://github.com/rsim/oracle-enhanced", branch: "master"
end
# A gem necessary for Active Record tests with IBM DB.
diff --git a/Gemfile.lock b/Gemfile.lock
index cf8bb0fec9..c42815d915 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -1,5 +1,5 @@
GIT
- remote: git://github.com/QueueClassic/queue_classic.git
+ remote: https://github.com/QueueClassic/queue_classic
revision: c26f2c9f6f6133b946fbcdd7b7ec905a4aca9f94
branch: master
specs:
@@ -7,14 +7,14 @@ GIT
pg (>= 0.17, < 0.19)
GIT
- remote: git://github.com/collectiveidea/delayed_job.git
+ remote: https://github.com/collectiveidea/delayed_job
revision: 71f1d5faf934d3057abca942f0d410327bc69087
specs:
delayed_job (4.1.1)
activesupport (>= 3.0, < 5.1)
GIT
- remote: git://github.com/collectiveidea/delayed_job_active_record.git
+ remote: https://github.com/collectiveidea/delayed_job_active_record
revision: 61e688e03b2ef4004b08de6d1e0a123fda8fffad
specs:
delayed_job_active_record (4.1.0)
@@ -22,7 +22,7 @@ GIT
delayed_job (>= 3.0, < 5)
GIT
- remote: git://github.com/matthewd/rb-inotify.git
+ remote: https://github.com/matthewd/rb-inotify
revision: 90553518d1fb79aedc98a3036c59bd2b6731ac40
branch: close-handling
specs:
@@ -30,7 +30,7 @@ GIT
ffi (>= 0.5.0)
GIT
- remote: git://github.com/resque/resque.git
+ remote: https://github.com/resque/resque
revision: 06036388ec61e573c761ac5a25a2ef3c76537ec7
specs:
resque (1.27.0)
@@ -41,7 +41,7 @@ GIT
vegas (~> 0.1.2)
GIT
- remote: git://github.com/sass/sass.git
+ remote: https://github.com/sass/sass
revision: 3fda1cbe70d615e7ef96e28db4fd1f8a3ebb5505
branch: stable
specs:
diff --git a/actioncable/Rakefile b/actioncable/Rakefile
index 34649547a2..648de57004 100644
--- a/actioncable/Rakefile
+++ b/actioncable/Rakefile
@@ -21,7 +21,7 @@ namespace :test do
task :isolated do
Dir.glob("test/**/*_test.rb").all? do |file|
sh(Gem.ruby, "-w", "-Ilib:test", file)
- end or raise "Failures"
+ end || raise("Failures")
end
task :integration do
diff --git a/actioncable/lib/action_cable/connection/client_socket.rb b/actioncable/lib/action_cable/connection/client_socket.rb
index c48f000d9c..70a2bbecb1 100644
--- a/actioncable/lib/action_cable/connection/client_socket.rb
+++ b/actioncable/lib/action_cable/connection/client_socket.rb
@@ -89,7 +89,7 @@ module ActionCable
code ||= 1000
reason ||= ""
- unless code == 1000 or (code >= 3000 and code <= 4999)
+ unless code == 1000 || (code >= 3000 && code <= 4999)
raise ArgumentError, "Failed to execute 'close' on WebSocket: " +
"The code must be either 1000, or between 3000 and 4999. " +
"#{code} is neither."
diff --git a/actionmailer/Rakefile b/actionmailer/Rakefile
index 059d98fb28..6f05d236d9 100644
--- a/actionmailer/Rakefile
+++ b/actionmailer/Rakefile
@@ -18,6 +18,6 @@ namespace :test do
task :isolated do
Dir.glob("test/**/*_test.rb").all? do |file|
sh(Gem.ruby, "-w", "-Ilib:test", file)
- end or raise "Failures"
+ end || raise("Failures")
end
end
diff --git a/actionmailer/lib/action_mailer/preview.rb b/actionmailer/lib/action_mailer/preview.rb
index d88ca7ace4..93a11453bf 100644
--- a/actionmailer/lib/action_mailer/preview.rb
+++ b/actionmailer/lib/action_mailer/preview.rb
@@ -34,11 +34,12 @@ module ActionMailer
# Either a class or a string can be passed in as the Interceptor. If a
# string is passed in it will be <tt>constantize</tt>d.
def register_preview_interceptor(interceptor)
- preview_interceptor = case interceptor
- when String, Symbol
- interceptor.to_s.camelize.constantize
+ preview_interceptor = \
+ case interceptor
+ when String, Symbol
+ interceptor.to_s.camelize.constantize
else
- interceptor
+ interceptor
end
unless preview_interceptors.include?(preview_interceptor)
diff --git a/actionpack/CHANGELOG.md b/actionpack/CHANGELOG.md
index a66a1e8af3..96af4d9397 100644
--- a/actionpack/CHANGELOG.md
+++ b/actionpack/CHANGELOG.md
@@ -1,10 +1,38 @@
+* Make `fixture_file_upload` work in integration tests.
+
+ *Yuji Yaginuma*
+
+* Add `to_param` to `ActionController::Parameters` deprecations.
+
+ In the future `ActionController::Parameters` are discouraged from being used
+ in URLs without explicit whitelisting. Go through `to_h` to use `to_param`.
+
+ *Kir Shatrov*
+
+* Fix nested multiple roots
+
+ The PR #20940 enabled the use of multiple roots with different constraints
+ at the top level but unfortunately didn't work when those roots were inside
+ a namespace and also broke the use of root inside a namespace after a top
+ level root was defined because the check for the existence of the named route
+ used the global :root name and not the namespaced name.
+
+ This is fixed by using the name_for_action method to expand the :root name to
+ the full namespaced name. We can pass nil for the second argument as we're not
+ dealing with resource definitions so don't need to handle the cases for edit
+ and new routes.
+
+ Fixes #26148.
+
+ *Ryo Hashimoto*, *Andrew White*
+
* Include the content of the flash in the auto-generated etag. This solves the following problem:
1. POST /messages
2. redirect_to messages_url, notice: 'Message was created'
3. GET /messages/1
4. GET /messages
-
+
Step 4 would before still include the flash message, even though it's no longer relevant,
because the etag cache was recorded with the flash in place and didn't change when it was gone.
diff --git a/actionpack/Rakefile b/actionpack/Rakefile
index 4bbbcfe9ff..31dd1865f9 100644
--- a/actionpack/Rakefile
+++ b/actionpack/Rakefile
@@ -21,7 +21,7 @@ namespace :test do
task :isolated do
test_files.all? do |file|
sh(Gem.ruby, "-w", "-Ilib:test", file)
- end or raise "Failures"
+ end || raise("Failures")
end
end
diff --git a/actionpack/lib/action_controller/metal/conditional_get.rb b/actionpack/lib/action_controller/metal/conditional_get.rb
index a26ebd2b24..89bf60a0bb 100644
--- a/actionpack/lib/action_controller/metal/conditional_get.rb
+++ b/actionpack/lib/action_controller/metal/conditional_get.rb
@@ -242,8 +242,9 @@ module ActionController
response.date = Time.now unless response.date?
end
- # Sets an HTTP 1.1 Cache-Control header of <tt>no-cache</tt> so no caching should
- # occur by the browser or intermediate caches (like caching proxy servers).
+ # Sets an HTTP 1.1 Cache-Control header of <tt>no-cache</tt>. This means the
+ # resource will be marked as stale, so clients must always revalidate.
+ # Intermediate/browser caches may still store the asset.
def expires_now
response.cache_control.replace(no_cache: true)
end
diff --git a/actionpack/lib/action_controller/metal/data_streaming.rb b/actionpack/lib/action_controller/metal/data_streaming.rb
index b598dd4d77..f089c8423b 100644
--- a/actionpack/lib/action_controller/metal/data_streaming.rb
+++ b/actionpack/lib/action_controller/metal/data_streaming.rb
@@ -64,12 +64,13 @@ module ActionController #:nodoc:
# http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9
# for the Cache-Control header spec.
def send_file(path, options = {}) #:doc:
- raise MissingFile, "Cannot read file #{path}" unless File.file?(path) and File.readable?(path)
+ raise MissingFile, "Cannot read file #{path}" unless File.file?(path) && File.readable?(path)
options[:filename] ||= File.basename(path) unless options[:url_based_filename]
send_file_headers! options
self.status = options[:status] || 200
+ self.content_type = options[:type] if options.key?(:type)
self.content_type = options[:content_type] if options.key?(:content_type)
response.send_file path
end
diff --git a/actionpack/lib/action_controller/metal/implicit_render.rb b/actionpack/lib/action_controller/metal/implicit_render.rb
index 4137db99ea..8615c16c6f 100644
--- a/actionpack/lib/action_controller/metal/implicit_render.rb
+++ b/actionpack/lib/action_controller/metal/implicit_render.rb
@@ -61,8 +61,8 @@ module ActionController
def method_for_action(action_name)
super || if template_exists?(action_name.to_s, _prefixes)
- "default_render"
- end
+ "default_render"
+ end
end
private
diff --git a/actionpack/lib/action_controller/metal/redirecting.rb b/actionpack/lib/action_controller/metal/redirecting.rb
index 3c7cc15627..2bd4296aff 100644
--- a/actionpack/lib/action_controller/metal/redirecting.rb
+++ b/actionpack/lib/action_controller/metal/redirecting.rb
@@ -111,7 +111,7 @@ module ActionController
`fallback_location` represents the location to use if the request has
no HTTP referer information.
MESSAGE
- request.headers["Referer"] or raise RedirectBackError
+ request.headers["Referer"] || raise(RedirectBackError)
when Proc
_compute_redirect_to_location request, options.call
else
diff --git a/actionpack/lib/action_controller/metal/strong_parameters.rb b/actionpack/lib/action_controller/metal/strong_parameters.rb
index d62e01d185..387c2aa0b9 100644
--- a/actionpack/lib/action_controller/metal/strong_parameters.rb
+++ b/actionpack/lib/action_controller/metal/strong_parameters.rb
@@ -2,6 +2,7 @@ require "active_support/core_ext/hash/indifferent_access"
require "active_support/core_ext/hash/transform_values"
require "active_support/core_ext/array/wrap"
require "active_support/core_ext/string/filters"
+require "active_support/core_ext/object/to_query"
require "active_support/rescuable"
require "action_dispatch/http/upload"
require "rack/test"
@@ -577,7 +578,7 @@ module ActionController
# +other_hash+ merges into current hash.
def merge(other_hash)
new_instance_with_inherited_permitted_status(
- @parameters.merge(other_hash)
+ @parameters.merge(other_hash.to_h)
)
end
@@ -619,6 +620,10 @@ module ActionController
end
end
+ # Undefine `to_param` such that it gets caught in the `method_missing`
+ # deprecation cycle below.
+ undef_method :to_param
+
def method_missing(method_sym, *args, &block)
if @parameters.respond_to?(method_sym)
message = <<-DEPRECATE.squish
diff --git a/actionpack/lib/action_controller/test_case.rb b/actionpack/lib/action_controller/test_case.rb
index d84320b713..09f2a79d85 100644
--- a/actionpack/lib/action_controller/test_case.rb
+++ b/actionpack/lib/action_controller/test_case.rb
@@ -51,7 +51,7 @@ module ActionController
super(env)
self.session = session
- self.session_options = TestSession::DEFAULT_OPTIONS
+ self.session_options = TestSession::DEFAULT_OPTIONS.dup
@controller_class = controller_class
@custom_param_parsers = {
xml: lambda { |raw_post| Hash.from_xml(raw_post)["hash"] }
@@ -663,14 +663,14 @@ module ActionController
def non_kwarg_request_warning
ActiveSupport::Deprecation.warn(<<-MSG.strip_heredoc)
- ActionController::TestCase HTTP request methods will accept only
- keyword arguments in future Rails versions.
+ ActionController::TestCase HTTP request methods will accept only
+ keyword arguments in future Rails versions.
- Examples:
+ Examples:
- get :show, params: { id: 1 }, session: { user_id: 1 }
- process :update, method: :post, params: { id: 1 }
- MSG
+ get :show, params: { id: 1 }, session: { user_id: 1 }
+ process :update, method: :post, params: { id: 1 }
+ MSG
end
def document_root_element
diff --git a/actionpack/lib/action_dispatch/http/response.rb b/actionpack/lib/action_dispatch/http/response.rb
index 9788431943..e8173e2a99 100644
--- a/actionpack/lib/action_dispatch/http/response.rb
+++ b/actionpack/lib/action_dispatch/http/response.rb
@@ -224,8 +224,10 @@ module ActionDispatch # :nodoc:
# Sets the HTTP content type.
def content_type=(content_type)
- header_info = parse_content_type
- set_content_type content_type.to_s, header_info.charset || self.class.default_charset
+ return unless content_type
+ new_header_info = parse_content_type(content_type.to_s)
+ prev_header_info = parsed_content_type_header
+ set_content_type new_header_info.mime_type, new_header_info.charset || prev_header_info.charset || self.class.default_charset
end
# Sets the HTTP response's content MIME type. For example, in the controller
@@ -238,7 +240,7 @@ module ActionDispatch # :nodoc:
# information.
def content_type
- parse_content_type.mime_type
+ parsed_content_type_header.mime_type
end
def sending_file=(v)
@@ -253,7 +255,7 @@ module ActionDispatch # :nodoc:
# response.charset = 'utf-16' # => 'utf-16'
# response.charset = nil # => 'utf-8'
def charset=(charset)
- header_info = parse_content_type
+ header_info = parsed_content_type_header
if false == charset
set_header CONTENT_TYPE, header_info.mime_type
else
@@ -265,7 +267,7 @@ module ActionDispatch # :nodoc:
# The charset of the response. HTML wants to know the encoding of the
# content you're giving them, so we need to send that along.
def charset
- header_info = parse_content_type
+ header_info = parsed_content_type_header
header_info.charset || self.class.default_charset
end
@@ -403,8 +405,7 @@ module ActionDispatch # :nodoc:
ContentTypeHeader = Struct.new :mime_type, :charset
NullContentTypeHeader = ContentTypeHeader.new nil, nil
- def parse_content_type
- content_type = get_header CONTENT_TYPE
+ def parse_content_type(content_type)
if content_type
type, charset = content_type.split(/;\s*charset=/)
type = nil if type.empty?
@@ -414,6 +415,12 @@ module ActionDispatch # :nodoc:
end
end
+ # Small internal convenience method to get the parsed version of the current
+ # content type header.
+ def parsed_content_type_header
+ parse_content_type(get_header(CONTENT_TYPE))
+ end
+
def set_content_type(content_type, charset)
type = (content_type || "").dup
type << "; charset=#{charset}" if charset
@@ -450,7 +457,7 @@ module ActionDispatch # :nodoc:
def assign_default_content_type_and_charset!
return if content_type
- ct = parse_content_type
+ ct = parsed_content_type_header
set_content_type(ct.mime_type || Mime[:html].to_s,
ct.charset || self.class.default_charset)
end
diff --git a/actionpack/lib/action_dispatch/journey/nfa/dot.rb b/actionpack/lib/action_dispatch/journey/nfa/dot.rb
index 0cd71b726a..8119e5d9da 100644
--- a/actionpack/lib/action_dispatch/journey/nfa/dot.rb
+++ b/actionpack/lib/action_dispatch/journey/nfa/dot.rb
@@ -26,7 +26,7 @@ digraph nfa {
node [shape = circle];
#{edges.join "\n"}
}
- eodot
+ eodot
end
end
end
diff --git a/actionpack/lib/action_dispatch/middleware/cookies.rb b/actionpack/lib/action_dispatch/middleware/cookies.rb
index ff83c4beca..6f4fab396a 100644
--- a/actionpack/lib/action_dispatch/middleware/cookies.rb
+++ b/actionpack/lib/action_dispatch/middleware/cookies.rb
@@ -372,7 +372,7 @@ module ActionDispatch
handle_options(options)
- if @cookies[name.to_s] != value or options[:expires]
+ if @cookies[name.to_s] != value || options[:expires]
@cookies[name.to_s] = value
@set_cookies[name.to_s] = options
@delete_cookies.delete(name.to_s)
@@ -576,7 +576,7 @@ module ActionDispatch
"Read the upgrade documentation to learn more about this new config option."
end
- secret = key_generator.generate_key(request.encrypted_cookie_salt || "")
+ secret = key_generator.generate_key(request.encrypted_cookie_salt || "")[0, ActiveSupport::MessageEncryptor.key_len]
sign_secret = key_generator.generate_key(request.encrypted_signed_cookie_salt || "")
@encryptor = ActiveSupport::MessageEncryptor.new(secret, sign_secret, digest: digest, serializer: ActiveSupport::MessageEncryptor::NullSerializer)
end
diff --git a/actionpack/lib/action_dispatch/middleware/session/cache_store.rb b/actionpack/lib/action_dispatch/middleware/session/cache_store.rb
index d99c2fd411..71274bc13a 100644
--- a/actionpack/lib/action_dispatch/middleware/session/cache_store.rb
+++ b/actionpack/lib/action_dispatch/middleware/session/cache_store.rb
@@ -19,7 +19,7 @@ module ActionDispatch
# Get a session from the cache.
def find_session(env, sid)
- unless sid and session = @cache.read(cache_key(sid))
+ unless sid && (session = @cache.read(cache_key(sid)))
sid, session = generate_sid, {}
end
[sid, session]
diff --git a/actionpack/lib/action_dispatch/middleware/stack.rb b/actionpack/lib/action_dispatch/middleware/stack.rb
index e49bf54115..466eb8b3f1 100644
--- a/actionpack/lib/action_dispatch/middleware/stack.rb
+++ b/actionpack/lib/action_dispatch/middleware/stack.rb
@@ -119,7 +119,7 @@ them to actual class references. For example:
"#{klass}" => #{converted_klass}
- eowarn
+ eowarn
converted_klass
else
klass
diff --git a/actionpack/lib/action_dispatch/routing/mapper.rb b/actionpack/lib/action_dispatch/routing/mapper.rb
index b3acac42fc..4ec1b8ee1f 100644
--- a/actionpack/lib/action_dispatch/routing/mapper.rb
+++ b/actionpack/lib/action_dispatch/routing/mapper.rb
@@ -1607,7 +1607,7 @@ module ActionDispatch
def root(path, options = {})
if path.is_a?(String)
options[:to] = path
- elsif path.is_a?(Hash) and options.empty?
+ elsif path.is_a?(Hash) && options.empty?
options = path
else
raise ArgumentError, "must be called with a path and/or options"
@@ -1927,7 +1927,7 @@ to this:
end
def match_root_route(options)
- name = has_named_route?(:root) ? nil : :root
+ name = has_named_route?(name_for_action(:root, nil)) ? nil : :root
args = ["/", { as: name, via: :get }.merge!(options)]
match(*args)
diff --git a/actionpack/lib/action_dispatch/routing/route_set.rb b/actionpack/lib/action_dispatch/routing/route_set.rb
index 112a38b868..8d0bf680c8 100644
--- a/actionpack/lib/action_dispatch/routing/route_set.rb
+++ b/actionpack/lib/action_dispatch/routing/route_set.rb
@@ -282,16 +282,17 @@ module ActionDispatch
mod.module_eval do
define_method(name) do |*args|
last = args.last
- options = case last
- when Hash
- args.pop
- when ActionController::Parameters
- if last.permitted?
- args.pop.to_h
- else
- raise ArgumentError, ActionDispatch::Routing::INSECURE_URL_PARAMETERS_MESSAGE
- end
- end
+ options = \
+ case last
+ when Hash
+ args.pop
+ when ActionController::Parameters
+ if last.permitted?
+ args.pop.to_h
+ else
+ raise ArgumentError, ActionDispatch::Routing::INSECURE_URL_PARAMETERS_MESSAGE
+ end
+ end
helper.call self, args, options
end
end
@@ -596,8 +597,8 @@ module ActionDispatch
# :controller, :action or :id is not found, don't pull any
# more keys from the recall.
def normalize_controller_action_id!
- use_recall_for(:controller) or return
- use_recall_for(:action) or return
+ use_recall_for(:controller) || return
+ use_recall_for(:action) || return
use_recall_for(:id)
end
diff --git a/actionpack/lib/action_dispatch/routing/routes_proxy.rb b/actionpack/lib/action_dispatch/routing/routes_proxy.rb
index 3592683136..ee847eaeed 100644
--- a/actionpack/lib/action_dispatch/routing/routes_proxy.rb
+++ b/actionpack/lib/action_dispatch/routing/routes_proxy.rb
@@ -19,7 +19,7 @@ module ActionDispatch
end
end
- def respond_to?(method, include_private = false)
+ def respond_to_missing?(method, include_private = false)
super || @helpers.respond_to?(method)
end
diff --git a/actionpack/lib/action_dispatch/testing/integration.rb b/actionpack/lib/action_dispatch/testing/integration.rb
index f5ec28a9c2..720651fa1f 100644
--- a/actionpack/lib/action_dispatch/testing/integration.rb
+++ b/actionpack/lib/action_dispatch/testing/integration.rb
@@ -179,7 +179,7 @@ module ActionDispatch
DEFAULT_HOST = "www.example.com"
include Minitest::Assertions
- include TestProcess, RequestHelpers, Assertions
+ include RequestHelpers, Assertions
%w( status status_message headers body redirect? ).each do |method|
delegate method, to: :response, allow_nil: true
@@ -502,7 +502,7 @@ module ActionDispatch
integration_session.default_url_options = options
end
- def respond_to?(method, include_private = false)
+ def respond_to_missing?(method, include_private = false)
integration_session.respond_to?(method, include_private) || super
end
@@ -711,6 +711,8 @@ module ActionDispatch
# Consult the Rails Testing Guide for more.
class IntegrationTest < ActiveSupport::TestCase
+ include TestProcess
+
module UrlOptions
extend ActiveSupport::Concern
def url_options
diff --git a/actionpack/test/controller/force_ssl_test.rb b/actionpack/test/controller/force_ssl_test.rb
index 8d5e3ce2fe..2b3859aa57 100644
--- a/actionpack/test/controller/force_ssl_test.rb
+++ b/actionpack/test/controller/force_ssl_test.rb
@@ -229,14 +229,12 @@ class ForceSSLFlashTest < ActionController::TestCase
assert_response 302
assert_equal "http://test.host/force_ssl_flash/cheeseburger", redirect_to_url
- # FIXME: AC::TestCase#build_request_uri doesn't build a new uri if PATH_INFO exists
@request.env.delete("PATH_INFO")
get :cheeseburger
assert_response 301
assert_equal "https://test.host/force_ssl_flash/cheeseburger", redirect_to_url
- # FIXME: AC::TestCase#build_request_uri doesn't build a new uri if PATH_INFO exists
@request.env.delete("PATH_INFO")
get :use_flash
diff --git a/actionpack/test/controller/integration_test.rb b/actionpack/test/controller/integration_test.rb
index 9044eff801..d3bc77d3ef 100644
--- a/actionpack/test/controller/integration_test.rb
+++ b/actionpack/test/controller/integration_test.rb
@@ -1281,3 +1281,39 @@ class IntegrationRequestEncodersTest < ActionDispatch::IntegrationTest
end
end
end
+
+class IntegrationFileUploadTest < ActionDispatch::IntegrationTest
+ class IntegrationController < ActionController::Base
+ def test_file_upload
+ render plain: params[:file].size
+ end
+ end
+
+ def self.routes
+ @routes ||= ActionDispatch::Routing::RouteSet.new
+ end
+
+ def self.call(env)
+ routes.call(env)
+ end
+
+ def app
+ self.class
+ end
+
+ def self.fixture_path
+ File.dirname(__FILE__) + "/../fixtures/multipart"
+ end
+
+ routes.draw do
+ post "test_file_upload", to: "integration_file_upload_test/integration#test_file_upload"
+ end
+
+ def test_fixture_file_upload
+ post "/test_file_upload",
+ params: {
+ file: fixture_file_upload("/mona_lisa.jpg", "image/jpg")
+ }
+ assert_equal "159528", @response.body
+ end
+end
diff --git a/actionpack/test/controller/parameters/parameters_permit_test.rb b/actionpack/test/controller/parameters/parameters_permit_test.rb
index 164efd936c..728d8e1279 100644
--- a/actionpack/test/controller/parameters/parameters_permit_test.rb
+++ b/actionpack/test/controller/parameters/parameters_permit_test.rb
@@ -237,6 +237,13 @@ class ParametersPermitTest < ActiveSupport::TestCase
assert @params.merge(a: "b").permitted?
end
+ test "merge with parameters" do
+ other_params = ActionController::Parameters.new(id: "1234").permit!
+ merged_params = @params.merge(other_params)
+
+ assert merged_params[:id]
+ end
+
test "modifying the parameters" do
@params[:person][:hometown] = "Chicago"
@params[:person][:family] = { brother: "Jonas" }
diff --git a/actionpack/test/controller/render_test.rb b/actionpack/test/controller/render_test.rb
index bf83131189..399c7489b7 100644
--- a/actionpack/test/controller/render_test.rb
+++ b/actionpack/test/controller/render_test.rb
@@ -226,7 +226,7 @@ class TestController < ActionController::Base
end
def head_and_return
- head :ok and return
+ head(:ok) && return
raise "should not reach this line"
end
diff --git a/actionpack/test/controller/request/test_request_test.rb b/actionpack/test/controller/request/test_request_test.rb
index 6e0ca957c3..fa049fbc9f 100644
--- a/actionpack/test/controller/request/test_request_test.rb
+++ b/actionpack/test/controller/request/test_request_test.rb
@@ -6,6 +6,11 @@ class ActionController::TestRequestTest < ActionController::TestCase
assert @request.session_options
end
+ def test_mutating_session_options_does_not_affect_default_options
+ @request.session_options[:myparam] = 123
+ assert_equal nil, ActionController::TestSession::DEFAULT_OPTIONS[:myparam]
+ end
+
ActionDispatch::Session::AbstractStore::DEFAULT_OPTIONS.each_key do |option|
test "rack default session options #{option} exists in session options and is default" do
assert_equal(ActionDispatch::Session::AbstractStore::DEFAULT_OPTIONS[option],
diff --git a/actionpack/test/controller/required_params_test.rb b/actionpack/test/controller/required_params_test.rb
index 315d1ff3e8..9fa2b6dbb0 100644
--- a/actionpack/test/controller/required_params_test.rb
+++ b/actionpack/test/controller/required_params_test.rb
@@ -77,4 +77,10 @@ class ParametersRequireTest < ActiveSupport::TestCase
ActionController::Parameters.new(foo: "bar").merge!(bar: "foo")
end
end
+
+ test "to_query is not supported" do
+ assert_deprecated do
+ ActionController::Parameters.new(foo: "bar").to_param
+ end
+ end
end
diff --git a/actionpack/test/controller/routing_test.rb b/actionpack/test/controller/routing_test.rb
index d1cc0f7d68..7be2ad2b28 100644
--- a/actionpack/test/controller/routing_test.rb
+++ b/actionpack/test/controller/routing_test.rb
@@ -211,7 +211,7 @@ class LegacyRouteSetTests < ActiveSupport::TestCase
def test_class_and_lambda_constraints
subdomain = Class.new {
def matches?(request)
- request.subdomain.present? and request.subdomain != "clients"
+ request.subdomain.present? && request.subdomain != "clients"
end
}
@@ -229,7 +229,7 @@ class LegacyRouteSetTests < ActiveSupport::TestCase
def test_lambda_constraints
rs.draw do
get "/", constraints: lambda { |req|
- req.subdomain.present? and req.subdomain != "clients" },
+ req.subdomain.present? && req.subdomain != "clients" },
to: lambda { |env| [200, {}, %w{default}] }
get "/", constraints: lambda { |req|
diff --git a/actionpack/test/controller/send_file_test.rb b/actionpack/test/controller/send_file_test.rb
index 25420ead3b..8dc565ac8d 100644
--- a/actionpack/test/controller/send_file_test.rb
+++ b/actionpack/test/controller/send_file_test.rb
@@ -233,4 +233,18 @@ class SendFileTest < ActionController::TestCase
response = process("file")
assert_equal 200, response.status
end
+
+ def test_send_file_charset_with_type_options_key
+ @controller = SendFileWithActionControllerLive.new
+ @controller.options = { type: "text/calendar; charset=utf-8" }
+ response = process("file")
+ assert_equal "text/calendar; charset=utf-8", response.headers["Content-Type"]
+ end
+
+ def test_send_file_charset_with_content_type_options_key
+ @controller = SendFileWithActionControllerLive.new
+ @controller.options = { content_type: "text/calendar" }
+ response = process("file")
+ assert_equal "text/calendar; charset=utf-8", response.headers["Content-Type"]
+ end
end
diff --git a/actionpack/test/dispatch/cookies_test.rb b/actionpack/test/dispatch/cookies_test.rb
index 4d3d83f45a..38cf0a2346 100644
--- a/actionpack/test/dispatch/cookies_test.rb
+++ b/actionpack/test/dispatch/cookies_test.rb
@@ -603,7 +603,7 @@ class CookiesTest < ActionController::TestCase
secret = key_generator.generate_key(encrypted_cookie_salt)
sign_secret = key_generator.generate_key(encrypted_signed_cookie_salt)
- marshal_value = ActiveSupport::MessageEncryptor.new(secret, sign_secret, serializer: Marshal).encrypt_and_sign("bar")
+ marshal_value = ActiveSupport::MessageEncryptor.new(secret[0, ActiveSupport::MessageEncryptor.key_len], sign_secret, serializer: Marshal).encrypt_and_sign("bar")
@request.headers["Cookie"] = "foo=#{marshal_value}"
get :get_encrypted_cookie
@@ -612,7 +612,7 @@ class CookiesTest < ActionController::TestCase
assert_not_equal "bar", cookies[:foo]
assert_equal "bar", cookies.encrypted[:foo]
- encryptor = ActiveSupport::MessageEncryptor.new(secret, sign_secret, serializer: JSON)
+ encryptor = ActiveSupport::MessageEncryptor.new(secret[0, ActiveSupport::MessageEncryptor.key_len], sign_secret, serializer: JSON)
assert_equal "bar", encryptor.decrypt_and_verify(@response.cookies["foo"])
end
@@ -624,7 +624,7 @@ class CookiesTest < ActionController::TestCase
encrypted_signed_cookie_salt = @request.env["action_dispatch.encrypted_signed_cookie_salt"]
secret = key_generator.generate_key(encrypted_cookie_salt)
sign_secret = key_generator.generate_key(encrypted_signed_cookie_salt)
- json_value = ActiveSupport::MessageEncryptor.new(secret, sign_secret, serializer: JSON).encrypt_and_sign("bar")
+ json_value = ActiveSupport::MessageEncryptor.new(secret[0, ActiveSupport::MessageEncryptor.key_len], sign_secret, serializer: JSON).encrypt_and_sign("bar")
@request.headers["Cookie"] = "foo=#{json_value}"
get :get_encrypted_cookie
@@ -636,6 +636,19 @@ class CookiesTest < ActionController::TestCase
assert_nil @response.cookies["foo"]
end
+ def test_compat_encrypted_cookie_using_64_byte_key
+ # Cookie generated with 64 bytes secret
+ message = ["566d4e75536d686e633246564e6b493062557079626c566d51574d30515430394c53315665564a694e4563786555744f57537454576b396a5a31566a626e52525054303d2d2d34663234333330623130623261306163363562316266323335396164666364613564643134623131"].pack("H*")
+ @request.headers["Cookie"] = "foo=#{message}"
+
+ get :get_encrypted_cookie
+
+ cookies = @controller.send :cookies
+ assert_not_equal "bar", cookies[:foo]
+ assert_equal "bar", cookies.encrypted[:foo]
+ assert_nil @response.cookies["foo"]
+ end
+
def test_accessing_nonexistent_encrypted_cookie_should_not_raise_invalid_message
get :set_encrypted_cookie
assert_nil @controller.send(:cookies).encrypted[:non_existent_attribute]
@@ -799,7 +812,7 @@ class CookiesTest < ActionController::TestCase
key_generator = @request.env["action_dispatch.key_generator"]
secret = key_generator.generate_key(@request.env["action_dispatch.encrypted_cookie_salt"])
sign_secret = key_generator.generate_key(@request.env["action_dispatch.encrypted_signed_cookie_salt"])
- encryptor = ActiveSupport::MessageEncryptor.new(secret, sign_secret)
+ encryptor = ActiveSupport::MessageEncryptor.new(secret[0, ActiveSupport::MessageEncryptor.key_len], sign_secret)
assert_equal "bar", encryptor.decrypt_and_verify(@response.cookies["foo"])
end
@@ -838,7 +851,7 @@ class CookiesTest < ActionController::TestCase
key_generator = @request.env["action_dispatch.key_generator"]
secret = key_generator.generate_key(@request.env["action_dispatch.encrypted_cookie_salt"])
sign_secret = key_generator.generate_key(@request.env["action_dispatch.encrypted_signed_cookie_salt"])
- encryptor = ActiveSupport::MessageEncryptor.new(secret, sign_secret, serializer: JSON)
+ encryptor = ActiveSupport::MessageEncryptor.new(secret[0, ActiveSupport::MessageEncryptor.key_len], sign_secret, serializer: JSON)
assert_equal "bar", encryptor.decrypt_and_verify(@response.cookies["foo"])
end
@@ -877,7 +890,7 @@ class CookiesTest < ActionController::TestCase
key_generator = @request.env["action_dispatch.key_generator"]
secret = key_generator.generate_key(@request.env["action_dispatch.encrypted_cookie_salt"])
sign_secret = key_generator.generate_key(@request.env["action_dispatch.encrypted_signed_cookie_salt"])
- encryptor = ActiveSupport::MessageEncryptor.new(secret, sign_secret, serializer: JSON)
+ encryptor = ActiveSupport::MessageEncryptor.new(secret[0, ActiveSupport::MessageEncryptor.key_len], sign_secret, serializer: JSON)
assert_equal "bar", encryptor.decrypt_and_verify(@response.cookies["foo"])
end
@@ -916,7 +929,7 @@ class CookiesTest < ActionController::TestCase
key_generator = @request.env["action_dispatch.key_generator"]
secret = key_generator.generate_key(@request.env["action_dispatch.encrypted_cookie_salt"])
sign_secret = key_generator.generate_key(@request.env["action_dispatch.encrypted_signed_cookie_salt"])
- encryptor = ActiveSupport::MessageEncryptor.new(secret, sign_secret, serializer: JSON)
+ encryptor = ActiveSupport::MessageEncryptor.new(secret[0, ActiveSupport::MessageEncryptor.key_len], sign_secret, serializer: JSON)
assert_equal "bar", encryptor.decrypt_and_verify(@response.cookies["foo"])
end
diff --git a/actionpack/test/dispatch/routing_test.rb b/actionpack/test/dispatch/routing_test.rb
index ee5c30ef0e..6ba52e37b6 100644
--- a/actionpack/test/dispatch/routing_test.rb
+++ b/actionpack/test/dispatch/routing_test.rb
@@ -3669,6 +3669,48 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest
end
end
+ def test_multiple_roots
+ draw do
+ namespace :foo do
+ root "pages#index", constraints: { host: "www.example.com" }
+ root "admin/pages#index", constraints: { host: "admin.example.com" }
+ end
+
+ root "pages#index", constraints: { host: "www.example.com" }
+ root "admin/pages#index", constraints: { host: "admin.example.com" }
+ end
+
+ get "http://www.example.com/foo"
+ assert_equal "foo/pages#index", @response.body
+
+ get "http://admin.example.com/foo"
+ assert_equal "foo/admin/pages#index", @response.body
+
+ get "http://www.example.com/"
+ assert_equal "pages#index", @response.body
+
+ get "http://admin.example.com/"
+ assert_equal "admin/pages#index", @response.body
+ end
+
+ def test_multiple_namespaced_roots
+ draw do
+ namespace :foo do
+ root "test#index"
+ end
+
+ root "test#index"
+
+ namespace :bar do
+ root "test#index"
+ end
+ end
+
+ assert_equal "/foo", foo_root_path
+ assert_equal "/", root_path
+ assert_equal "/bar", bar_root_path
+ end
+
private
def draw(&block)
diff --git a/actionview/Rakefile b/actionview/Rakefile
index f9a7112ade..6c3fc59b0a 100644
--- a/actionview/Rakefile
+++ b/actionview/Rakefile
@@ -14,7 +14,7 @@ namespace :test do
task :isolated do
Dir.glob("test/{actionpack,activerecord,template}/**/*_test.rb").all? do |file|
sh(Gem.ruby, "-w", "-Ilib:test", file)
- end or raise "Failures"
+ end || raise("Failures")
end
Rake::TestTask.new(:template) do |t|
diff --git a/actionview/lib/action_view/helpers/asset_tag_helper.rb b/actionview/lib/action_view/helpers/asset_tag_helper.rb
index 6cac4bc0ad..b1563ac490 100644
--- a/actionview/lib/action_view/helpers/asset_tag_helper.rb
+++ b/actionview/lib/action_view/helpers/asset_tag_helper.rb
@@ -56,7 +56,7 @@ module ActionView
# # => <script src="http://www.example.com/xmlhr.js"></script>
def javascript_include_tag(*sources)
options = sources.extract_options!.stringify_keys
- path_options = options.extract!("protocol", "extname", "host").symbolize_keys
+ path_options = options.extract!("protocol", "extname", "host", "skip_pipeline").symbolize_keys
sources.uniq.map { |source|
tag_options = {
"src" => path_to_javascript(source, path_options)
@@ -92,8 +92,7 @@ module ActionView
# # <link href="/css/stylish.css" media="screen" rel="stylesheet" />
def stylesheet_link_tag(*sources)
options = sources.extract_options!.stringify_keys
- path_options = options.extract!("protocol", "host").symbolize_keys
-
+ path_options = options.extract!("protocol", "host", "skip_pipeline").symbolize_keys
sources.uniq.map { |source|
tag_options = {
"rel" => "stylesheet",
@@ -174,7 +173,7 @@ module ActionView
tag("link", {
rel: "shortcut icon",
type: "image/x-icon",
- href: path_to_image(source)
+ href: path_to_image(source, skip_pipeline: options.delete(:skip_pipeline))
}.merge!(options.symbolize_keys))
end
@@ -212,7 +211,7 @@ module ActionView
options = options.symbolize_keys
check_for_image_tag_errors(options)
- src = options[:src] = path_to_image(source)
+ src = options[:src] = path_to_image(source, skip_pipeline: options.delete(:skip_pipeline))
unless src.start_with?("cid:") || src.start_with?("data:") || src.blank?
options[:alt] = options.fetch(:alt) { image_alt(src) }
@@ -258,6 +257,8 @@ module ActionView
# * <tt>:size</tt> - Supplied as "{Width}x{Height}" or "{Number}", so "30x45" becomes
# width="30" and height="45", and "50" becomes width="50" and height="50".
# <tt>:size</tt> will be ignored if the value is not in the correct format.
+ # * <tt>:poster_skip_pipeline</tt> will bypass the asset pipeline when using
+ # the <tt>:poster</tt> option instead using an asset in the public folder.
#
# ==== Examples
#
@@ -269,6 +270,8 @@ module ActionView
# # => <video preload="none" controls="controls" src="/videos/trailer.ogg" ></video>
# video_tag("trailer.m4v", size: "16x10", poster: "screenshot.png")
# # => <video src="/videos/trailer.m4v" width="16" height="10" poster="/assets/screenshot.png"></video>
+ # video_tag("trailer.m4v", size: "16x10", poster: "screenshot.png", poster_skip_pipeline: true)
+ # # => <video src="/videos/trailer.m4v" width="16" height="10" poster="screenshot.png"></video>
# video_tag("/trailers/hd.avi", size: "16x16")
# # => <video src="/trailers/hd.avi" width="16" height="16"></video>
# video_tag("/trailers/hd.avi", size: "16")
@@ -282,9 +285,12 @@ module ActionView
# video_tag(["trailer.ogg", "trailer.flv"], size: "160x120")
# # => <video height="120" width="160"><source src="/videos/trailer.ogg" /><source src="/videos/trailer.flv" /></video>
def video_tag(*sources)
- multiple_sources_tag("video", sources) do |options|
- options[:poster] = path_to_image(options[:poster]) if options[:poster]
- options[:width], options[:height] = extract_dimensions(options.delete(:size)) if options[:size]
+ options = sources.extract_options!.symbolize_keys
+ public_poster_folder = options.delete(:poster_skip_pipeline)
+ sources << options
+ multiple_sources_tag_builder("video", sources) do |tag_options|
+ tag_options[:poster] = path_to_image(tag_options[:poster], skip_pipeline: public_poster_folder) if tag_options[:poster]
+ tag_options[:width], tag_options[:height] = extract_dimensions(tag_options.delete(:size)) if tag_options[:size]
end
end
@@ -301,22 +307,23 @@ module ActionView
# audio_tag("sound.wav", "sound.mid")
# # => <audio><source src="/audios/sound.wav" /><source src="/audios/sound.mid" /></audio>
def audio_tag(*sources)
- multiple_sources_tag("audio", sources)
+ multiple_sources_tag_builder("audio", sources)
end
private
- def multiple_sources_tag(type, sources)
- options = sources.extract_options!.symbolize_keys
+ def multiple_sources_tag_builder(type, sources)
+ options = sources.extract_options!.symbolize_keys
+ skip_pipeline = options.delete(:skip_pipeline)
sources.flatten!
yield options if block_given?
if sources.size > 1
content_tag(type, options) do
- safe_join sources.map { |source| tag("source", src: send("path_to_#{type}", source)) }
+ safe_join sources.map { |source| tag("source", src: send("path_to_#{type}", source, skip_pipeline: skip_pipeline)) }
end
else
- options[:src] = send("path_to_#{type}", sources.first)
+ options[:src] = send("path_to_#{type}", sources.first, skip_pipeline: skip_pipeline)
content_tag(type, nil, options)
end
end
diff --git a/actionview/lib/action_view/helpers/asset_url_helper.rb b/actionview/lib/action_view/helpers/asset_url_helper.rb
index 76a4893f2e..0967245855 100644
--- a/actionview/lib/action_view/helpers/asset_url_helper.rb
+++ b/actionview/lib/action_view/helpers/asset_url_helper.rb
@@ -118,16 +118,67 @@ module ActionView
module AssetUrlHelper
URI_REGEXP = %r{^[-a-z]+://|^(?:cid|data):|^//}i
- # Computes the path to asset in public directory. If :type
- # options is set, a file extension will be appended and scoped
- # to the corresponding public directory.
+ # This is the entry point for all assets.
+ # When using the asset pipeline (i.e. sprockets and sprockets-rails), the
+ # behavior is "enhanced". You can bypass the asset pipeline by passing in
+ # <tt>skip_pipeline: true</tt> to the options.
#
# All other asset *_path helpers delegate through this method.
#
- # asset_path "application.js" # => /assets/application.js
- # asset_path "application", type: :javascript # => /assets/application.js
- # asset_path "application", type: :stylesheet # => /assets/application.css
- # asset_path "http://www.example.com/js/xmlhr.js" # => http://www.example.com/js/xmlhr.js
+ # === With the asset pipeline
+ #
+ # All options passed to +asset_path+ will be passed to +compute_asset_path+
+ # which is implemented by sprockets-rails.
+ #
+ # asset_path("application.js") # => "/assets/application-60aa4fdc5cea14baf5400fba1abf4f2a46a5166bad4772b1effe341570f07de9.js"
+ #
+ # === Without the asset pipeline (<tt>skip_pipeline: true</tt>)
+ #
+ # Accepts a <tt>type</tt> option that can specify the asset's extension. No error
+ # checking is done to verify the source passed into +asset_path+ is valid
+ # and that the file exists on disk.
+ #
+ # asset_path("application.js", skip_pipeline: true) # => "application.js"
+ # asset_path("filedoesnotexist.png", skip_pipeline: true) # => "filedoesnotexist.png"
+ # asset_path("application", type: :javascript, skip_pipeline: true) # => "/javascripts/application.js"
+ # asset_path("application", type: :stylesheet, skip_pipeline: true) # => "/stylesheets/application.css"
+ #
+ # === Options applying to all assets
+ #
+ # Below lists scenarios that apply to +asset_path+ whether or not you're
+ # using the asset pipeline.
+ #
+ # - All fully qualified urls are returned immediately. This bypasses the
+ # asset pipeline and all other behavior described.
+ #
+ # asset_path("http://www.example.com/js/xmlhr.js") # => "http://www.example.com/js/xmlhr.js"
+ #
+ # - All assets that begin with a forward slash are assumed to be full
+ # urls and will not be expanded. This will bypass the asset pipeline.
+ #
+ # asset_path("/foo.png") # => "/foo.png"
+ #
+ # - All blank strings will be returned immediately. This bypasses the
+ # asset pipeline and all other behavior described.
+ #
+ # asset_path("") # => ""
+ #
+ # - If <tt>config.relative_url_root</tt> is specified, all assets will have that
+ # root prepended.
+ #
+ # Rails.application.config.relative_url_root = "bar"
+ # asset_path("foo.js", skip_pipeline: true) # => "bar/foo.js"
+ #
+ # - A different asset host can be specified via <tt>config.action_controller.asset_host</tt>
+ # this is commonly used in conjunction with a CDN.
+ #
+ # Rails.application.config.action_controller.asset_host = "assets.example.com"
+ # asset_path("foo.js", skip_pipeline: true) # => "http://assets.example.com/foo.js"
+ #
+ # - An extension name can be specified manually with <tt>extname</tt>.
+ #
+ # asset_path("foo", skip_pipeline: true, extname: ".js") # => "/foo.js"
+ # asset_path("foo.css", skip_pipeline: true, extname: ".js") # => "/foo.css.js"
def asset_path(source, options = {})
raise ArgumentError, "nil is not a valid asset source" if source.nil?
@@ -142,7 +193,11 @@ module ActionView
end
if source[0] != ?/
- source = compute_asset_path(source, options)
+ if options[:skip_pipeline]
+ source = public_compute_asset_path(source, options)
+ else
+ source = compute_asset_path(source, options)
+ end
end
relative_url_root = defined?(config.relative_url_root) && config.relative_url_root
@@ -203,6 +258,7 @@ module ActionView
dir = ASSET_PUBLIC_DIRECTORIES[options[:type]] || ""
File.join(dir, source)
end
+ alias :public_compute_asset_path :compute_asset_path
# Pick an asset host for this source. Returns +nil+ if no host is set,
# the host if no wildcard is set, the host interpolated with the
diff --git a/actionview/lib/action_view/helpers/capture_helper.rb b/actionview/lib/action_view/helpers/capture_helper.rb
index 5b569b5923..719592b5c5 100644
--- a/actionview/lib/action_view/helpers/capture_helper.rb
+++ b/actionview/lib/action_view/helpers/capture_helper.rb
@@ -37,7 +37,7 @@ module ActionView
def capture(*args)
value = nil
buffer = with_output_buffer { value = yield(*args) }
- if string = buffer.presence || value and string.is_a?(String)
+ if (string = buffer.presence || value) && string.is_a?(String)
ERB::Util.html_escape string
end
end
diff --git a/actionview/lib/action_view/helpers/date_helper.rb b/actionview/lib/action_view/helpers/date_helper.rb
index 74c6f0ab1c..61ce1d36e0 100644
--- a/actionview/lib/action_view/helpers/date_helper.rb
+++ b/actionview/lib/action_view/helpers/date_helper.rb
@@ -1011,12 +1011,13 @@ module ActionView
# css_class_attribute(:year, 'date optional', { year: 'my-year' })
# => "date optional my-year"
def css_class_attribute(type, html_options_class, options) # :nodoc:
- css_class = case options
- when Hash
- options[type.to_sym]
- else
- type
- end
+ css_class = \
+ case options
+ when Hash
+ options[type.to_sym]
+ else
+ type
+ end
[html_options_class, css_class].compact.join(" ")
end
@@ -1025,15 +1026,16 @@ module ActionView
# prompt_option_tag(:month, prompt: 'Select month')
# => "<option value="">Select month</option>"
def prompt_option_tag(type, options)
- prompt = case options
- when Hash
- default_options = { year: false, month: false, day: false, hour: false, minute: false, second: false }
- default_options.merge!(options)[type.to_sym]
- when String
- options
+ prompt = \
+ case options
+ when Hash
+ default_options = { year: false, month: false, day: false, hour: false, minute: false, second: false }
+ default_options.merge!(options)[type.to_sym]
+ when String
+ options
else
- I18n.translate(:"datetime.prompts.#{type}", locale: @options[:locale])
- end
+ I18n.translate(:"datetime.prompts.#{type}", locale: @options[:locale])
+ end
prompt ? content_tag("option".freeze, prompt, value: "") : ""
end
diff --git a/actionview/lib/action_view/helpers/form_helper.rb b/actionview/lib/action_view/helpers/form_helper.rb
index 7d574f0a14..124a14f1d9 100644
--- a/actionview/lib/action_view/helpers/form_helper.rb
+++ b/actionview/lib/action_view/helpers/form_helper.rb
@@ -965,6 +965,7 @@ module ActionView
# # => <input type="radio" id="post_category_rails" name="post[category]" value="rails" checked="checked" />
# # <input type="radio" id="post_category_java" name="post[category]" value="java" />
#
+ # # Let's say that @user.receive_newsletter returns "no":
# radio_button("user", "receive_newsletter", "yes")
# radio_button("user", "receive_newsletter", "no")
# # => <input type="radio" id="user_receive_newsletter_yes" name="user[receive_newsletter]" value="yes" />
@@ -1286,7 +1287,7 @@ module ActionView
@object_name, @object, @template, @options = object_name, object, template, options
@default_options = @options ? @options.slice(:index, :namespace) : {}
if @object_name.to_s.match(/\[\]$/)
- if object ||= @template.instance_variable_get("@#{Regexp.last_match.pre_match}") and object.respond_to?(:to_param)
+ if (object ||= @template.instance_variable_get("@#{Regexp.last_match.pre_match}")) && object.respond_to?(:to_param)
@auto_index = object.to_param
else
raise ArgumentError, "object[] naming but object param and @object var don't exist or don't respond to to_param: #{object.inspect}"
@@ -1711,7 +1712,7 @@ module ActionView
# # => <input type="radio" id="post_category_rails" name="post[category]" value="rails" checked="checked" />
# # <input type="radio" id="post_category_java" name="post[category]" value="java" />
#
- # # Let's say that @user.category returns "no":
+ # # Let's say that @user.receive_newsletter returns "no":
# radio_button("receive_newsletter", "yes")
# radio_button("receive_newsletter", "no")
# # => <input type="radio" id="user_receive_newsletter_yes" name="user[receive_newsletter]" value="yes" />
diff --git a/actionview/lib/action_view/helpers/form_tag_helper.rb b/actionview/lib/action_view/helpers/form_tag_helper.rb
index a8abe6b7c4..7bd473507b 100644
--- a/actionview/lib/action_view/helpers/form_tag_helper.rb
+++ b/actionview/lib/action_view/helpers/form_tag_helper.rb
@@ -857,23 +857,24 @@ module ActionView
authenticity_token = html_options.delete("authenticity_token")
method = html_options.delete("method").to_s.downcase
- method_tag = case method
- when "get"
- html_options["method"] = "get"
- ""
- when "post", ""
- html_options["method"] = "post"
- token_tag(authenticity_token, form_options: {
- action: html_options["action"],
- method: "post"
- })
+ method_tag = \
+ case method
+ when "get"
+ html_options["method"] = "get"
+ ""
+ when "post", ""
+ html_options["method"] = "post"
+ token_tag(authenticity_token, form_options: {
+ action: html_options["action"],
+ method: "post"
+ })
else
- html_options["method"] = "post"
- method_tag(method) + token_tag(authenticity_token, form_options: {
- action: html_options["action"],
- method: method
- })
- end
+ html_options["method"] = "post"
+ method_tag(method) + token_tag(authenticity_token, form_options: {
+ action: html_options["action"],
+ method: method
+ })
+ end
if html_options.delete("enforce_utf8") { true }
utf8_enforcer_tag + method_tag
diff --git a/actionview/lib/action_view/layouts.rb b/actionview/lib/action_view/layouts.rb
index b6bf6b9374..dd5f6e7300 100644
--- a/actionview/lib/action_view/layouts.rb
+++ b/actionview/lib/action_view/layouts.rb
@@ -290,11 +290,12 @@ module ActionView
RUBY
end
- layout_definition = case _layout
- when String
- _layout.inspect
- when Symbol
- <<-RUBY
+ layout_definition = \
+ case _layout
+ when String
+ _layout.inspect
+ when Symbol
+ <<-RUBY
#{_layout}.tap do |layout|
return #{default_behavior} if layout.nil?
unless layout.is_a?(String) || !layout
@@ -303,21 +304,21 @@ module ActionView
end
end
RUBY
- when Proc
- define_method :_layout_from_proc, &_layout
- protected :_layout_from_proc
- <<-RUBY
+ when Proc
+ define_method :_layout_from_proc, &_layout
+ protected :_layout_from_proc
+ <<-RUBY
result = _layout_from_proc(#{_layout.arity == 0 ? '' : 'self'})
return #{default_behavior} if result.nil?
result
RUBY
- when false
- nil
- when true
- raise ArgumentError, "Layouts must be specified as a String, Symbol, Proc, false, or nil"
- when nil
- name_clause
- end
+ when false
+ nil
+ when true
+ raise ArgumentError, "Layouts must be specified as a String, Symbol, Proc, false, or nil"
+ when nil
+ name_clause
+ end
self.class_eval <<-RUBY, __FILE__, __LINE__ + 1
def _layout(formats)
diff --git a/actionview/test/template/tag_helper_test.rb b/actionview/test/template/tag_helper_test.rb
index 278c3e855f..f1e5946e14 100644
--- a/actionview/test/template/tag_helper_test.rb
+++ b/actionview/test/template/tag_helper_test.rb
@@ -284,12 +284,12 @@ class TagHelperTest < ActionView::TestCase
def test_tag_does_not_honor_html_safe_double_quotes_as_attributes
assert_dom_equal '<p title="&quot;">content</p>',
- content_tag('p', "content", title: '"'.html_safe)
+ content_tag("p", "content", title: '"'.html_safe)
end
def test_data_tag_does_not_honor_html_safe_double_quotes_as_attributes
assert_dom_equal '<p data-title="&quot;">content</p>',
- content_tag('p', "content", data: { title: '"'.html_safe })
+ content_tag("p", "content", data: { title: '"'.html_safe })
end
def test_skip_invalid_escaped_attributes
diff --git a/actionview/test/template/template_test.rb b/actionview/test/template/template_test.rb
index 2988f152be..9d31a98703 100644
--- a/actionview/test/template/template_test.rb
+++ b/actionview/test/template/template_test.rb
@@ -80,7 +80,7 @@ class TestERBTemplate < ActiveSupport::TestCase
end
def test_raw_template
- @template = new_template("<%= hello %>", :handler => ActionView::Template::Handlers::Raw.new)
+ @template = new_template("<%= hello %>", handler: ActionView::Template::Handlers::Raw.new)
assert_equal "<%= hello %>", render
end
@@ -189,7 +189,9 @@ class TestERBTemplate < ActiveSupport::TestCase
@template = new_template("hello \xFCmlat", virtual_path: nil)
render
end
- assert_match(/\xFC/, e.message)
+ # Hack: We write the regexp this way because the parser of RuboCop
+ # errs with /\xFC/.
+ assert_match(Regexp.new("\xFC"), e.message)
end
def with_external_encoding(encoding)
diff --git a/activejob/Rakefile b/activejob/Rakefile
index da153c8a49..3953116061 100644
--- a/activejob/Rakefile
+++ b/activejob/Rakefile
@@ -46,7 +46,7 @@ namespace :test do
dir = File.dirname(__FILE__)
Dir.glob("#{dir}/test/cases/**/*_test.rb").all? do |file|
sh(Gem.ruby, "-w", "-I#{dir}/lib", "-I#{dir}/test", file)
- end or raise "Failures"
+ end || raise("Failures")
end
end
diff --git a/activejob/lib/active_job/arguments.rb b/activejob/lib/active_job/arguments.rb
index d94b015014..41ce5f863b 100644
--- a/activejob/lib/active_job/arguments.rb
+++ b/activejob/lib/active_job/arguments.rb
@@ -104,7 +104,7 @@ module ActiveJob
end
def serialized_global_id?(hash)
- hash.size == 1 and hash.include?(GLOBALID_KEY)
+ hash.size == 1 && hash.include?(GLOBALID_KEY)
end
def deserialize_global_id(hash)
diff --git a/activejob/lib/active_job/test_helper.rb b/activejob/lib/active_job/test_helper.rb
index 35fee7452c..bbd2a0c06c 100644
--- a/activejob/lib/active_job/test_helper.rb
+++ b/activejob/lib/active_job/test_helper.rb
@@ -11,7 +11,7 @@ module ActiveJob
def before_setup # :nodoc:
test_adapter = queue_adapter_for_test
- @old_queue_adapters = (ActiveJob::Base.subclasses << ActiveJob::Base).select do |klass|
+ @old_queue_adapters = (ActiveJob::Base.descendants << ActiveJob::Base).select do |klass|
# only override explicitly set adapters, a quirk of `class_attribute`
klass.singleton_class.public_instance_methods(false).include?(:_queue_adapter)
end.map do |klass|
diff --git a/activejob/test/cases/exceptions_test.rb b/activejob/test/cases/exceptions_test.rb
index 9ee1dbfa0a..dbe55f7430 100644
--- a/activejob/test/cases/exceptions_test.rb
+++ b/activejob/test/cases/exceptions_test.rb
@@ -58,7 +58,7 @@ class ExceptionsTest < ActiveJob::TestCase
test "custom handling of job that exceeds retry attempts" do
perform_enqueued_jobs do
- RetryJob.perform_later 'CustomCatchError', 6
+ RetryJob.perform_later "CustomCatchError", 6
assert_equal "Dealt with a job that failed to retry in a custom way after 6 attempts", JobBuffer.last_value
end
end
diff --git a/activejob/test/cases/test_helper_test.rb b/activejob/test/cases/test_helper_test.rb
index 2398402d5d..253c557cc5 100644
--- a/activejob/test/cases/test_helper_test.rb
+++ b/activejob/test/cases/test_helper_test.rb
@@ -5,6 +5,7 @@ require "jobs/hello_job"
require "jobs/logging_job"
require "jobs/nested_job"
require "jobs/rescue_job"
+require "jobs/inherited_job"
require "models/person"
class EnqueuedJobsTest < ActiveJob::TestCase
@@ -521,3 +522,9 @@ class OverrideQueueAdapterTest < ActiveJob::TestCase
assert_instance_of CustomQueueAdapter, HelloJob.queue_adapter
end
end
+
+class InheritedJobTest < ActiveJob::TestCase
+ def test_queue_adapter_is_test_adapter
+ assert_instance_of ActiveJob::QueueAdapters::TestAdapter, InheritedJob.queue_adapter
+ end
+end
diff --git a/activejob/test/jobs/application_job.rb b/activejob/test/jobs/application_job.rb
new file mode 100644
index 0000000000..4a78b890ec
--- /dev/null
+++ b/activejob/test/jobs/application_job.rb
@@ -0,0 +1,4 @@
+require_relative "../support/job_buffer"
+
+class ApplicationJob < ActiveJob::Base
+end
diff --git a/activejob/test/jobs/inherited_job.rb b/activejob/test/jobs/inherited_job.rb
new file mode 100644
index 0000000000..60fca66f88
--- /dev/null
+++ b/activejob/test/jobs/inherited_job.rb
@@ -0,0 +1,5 @@
+require_relative "application_job"
+
+class InheritedJob < ApplicationJob
+ self.queue_adapter = :inline
+end
diff --git a/activemodel/Rakefile b/activemodel/Rakefile
index d62c7b46c8..c7f97a4258 100644
--- a/activemodel/Rakefile
+++ b/activemodel/Rakefile
@@ -18,6 +18,6 @@ namespace :test do
task :isolated do
Dir.glob("#{dir}/test/**/*_test.rb").all? do |file|
sh(Gem.ruby, "-w", "-I#{dir}/lib", "-I#{dir}/test", file)
- end or raise "Failures"
+ end || raise("Failures")
end
end
diff --git a/activemodel/lib/active_model/type/decimal.rb b/activemodel/lib/active_model/type/decimal.rb
index 6266933636..6c5c0451c6 100644
--- a/activemodel/lib/active_model/type/decimal.rb
+++ b/activemodel/lib/active_model/type/decimal.rb
@@ -16,18 +16,19 @@ module ActiveModel
private
def cast_value(value)
- casted_value = case value
- when ::Float
- convert_float_to_big_decimal(value)
- when ::Numeric, ::String
- BigDecimal(value, precision.to_i)
- else
- if value.respond_to?(:to_d)
- value.to_d
- else
- cast_value(value.to_s)
- end
- end
+ casted_value = \
+ case value
+ when ::Float
+ convert_float_to_big_decimal(value)
+ when ::Numeric, ::String
+ BigDecimal(value, precision.to_i)
+ else
+ if value.respond_to?(:to_d)
+ value.to_d
+ else
+ cast_value(value.to_s)
+ end
+ end
apply_scale(casted_value)
end
diff --git a/activemodel/lib/active_model/type/helpers/numeric.rb b/activemodel/lib/active_model/type/helpers/numeric.rb
index ec1d1daf1a..98533f8771 100644
--- a/activemodel/lib/active_model/type/helpers/numeric.rb
+++ b/activemodel/lib/active_model/type/helpers/numeric.rb
@@ -3,12 +3,13 @@ module ActiveModel
module Helpers
module Numeric # :nodoc:
def cast(value)
- value = case value
- when true then 1
- when false then 0
- when ::String then value.presence
- else value
- end
+ value = \
+ case value
+ when true then 1
+ when false then 0
+ when ::String then value.presence
+ else value
+ end
super(value)
end
diff --git a/activemodel/lib/active_model/type/immutable_string.rb b/activemodel/lib/active_model/type/immutable_string.rb
index 41e4a2a1ac..58268540e5 100644
--- a/activemodel/lib/active_model/type/immutable_string.rb
+++ b/activemodel/lib/active_model/type/immutable_string.rb
@@ -17,11 +17,12 @@ module ActiveModel
private
def cast_value(value)
- result = case value
- when true then "t"
- when false then "f"
- else value.to_s
- end
+ result = \
+ case value
+ when true then "t"
+ when false then "f"
+ else value.to_s
+ end
result.freeze
end
end
diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md
index 4aa1853bde..3eac34d65e 100644
--- a/activerecord/CHANGELOG.md
+++ b/activerecord/CHANGELOG.md
@@ -1,3 +1,22 @@
+* PostgreSQL array columns will now respect the encoding of strings contained
+ in the array.
+
+ Fixes #26326.
+
+ *Sean Griffin*
+
+* Inverse association instances will now be set before `after_find` or
+ `after_initialize` callbacks are run.
+
+ Fixes #26320.
+
+ *Sean Griffin*
+
+* Remove unnecessarily association load when a `belongs_to` association has already been
+ loaded then the foreign key is changed directly and the record saved.
+
+ *James Coleman*
+
* Remove standardized column types/arguments spaces in schema dump.
*Tim Petricola*
diff --git a/activerecord/Rakefile b/activerecord/Rakefile
index 543ab2eaba..e077d345d6 100644
--- a/activerecord/Rakefile
+++ b/activerecord/Rakefile
@@ -67,7 +67,7 @@ end
|x| x.include?("/adapters/")
} + Dir["test/cases/adapters/#{adapter_short}/**/*_test.rb"]).all? do |file|
sh(Gem.ruby, "-w" ,"-Itest", file)
- end or raise "Failures"
+ end || raise("Failures")
end
end
end
diff --git a/activerecord/lib/active_record/association_relation.rb b/activerecord/lib/active_record/association_relation.rb
index 2da2d968b9..de2d03cd0b 100644
--- a/activerecord/lib/active_record/association_relation.rb
+++ b/activerecord/lib/active_record/association_relation.rb
@@ -29,7 +29,10 @@ module ActiveRecord
private
def exec_queries
- super.each { |r| @association.set_inverse_instance r }
+ super do |r|
+ @association.set_inverse_instance r
+ yield r if block_given?
+ end
end
end
end
diff --git a/activerecord/lib/active_record/associations.rb b/activerecord/lib/active_record/associations.rb
index dc68b01386..dc6fe1640e 100644
--- a/activerecord/lib/active_record/associations.rb
+++ b/activerecord/lib/active_record/associations.rb
@@ -1792,12 +1792,7 @@ module ActiveRecord
# has_and_belongs_to_many :nations, class_name: "Country"
# has_and_belongs_to_many :categories, join_table: "prods_cats"
# has_and_belongs_to_many :categories, -> { readonly }
- def has_and_belongs_to_many(name, scope = nil, options = {}, &extension)
- if scope.is_a?(Hash)
- options = scope
- scope = nil
- end
-
+ def has_and_belongs_to_many(name, scope = nil, **options, &extension)
habtm_reflection = ActiveRecord::Reflection::HasAndBelongsToManyReflection.new(name, scope, options, self)
builder = Builder::HasAndBelongsToMany.new name, self, options
@@ -1815,12 +1810,12 @@ module ActiveRecord
include Module.new {
class_eval <<-RUBY, __FILE__, __LINE__ + 1
- def destroy_associations
- association(:#{middle_reflection.name}).delete_all(:delete_all)
- association(:#{name}).reset
- super
- end
- RUBY
+ def destroy_associations
+ association(:#{middle_reflection.name}).delete_all(:delete_all)
+ association(:#{name}).reset
+ super
+ end
+ RUBY
}
hm_options = {}
diff --git a/activerecord/lib/active_record/associations/association.rb b/activerecord/lib/active_record/associations/association.rb
index 8328286805..f506614591 100644
--- a/activerecord/lib/active_record/associations/association.rb
+++ b/activerecord/lib/active_record/associations/association.rb
@@ -173,6 +173,14 @@ module ActiveRecord
set_inverse_instance(record)
end
+ def create(attributes = {}, &block)
+ _create_record(attributes, &block)
+ end
+
+ def create!(attributes = {}, &block)
+ _create_record(attributes, true, &block)
+ end
+
private
def find_target?
diff --git a/activerecord/lib/active_record/associations/collection_association.rb b/activerecord/lib/active_record/associations/collection_association.rb
index 0f51b35164..08bd532fb0 100644
--- a/activerecord/lib/active_record/associations/collection_association.rb
+++ b/activerecord/lib/active_record/associations/collection_association.rb
@@ -113,14 +113,6 @@ module ActiveRecord
end
end
- def create(attributes = {}, &block)
- _create_record(attributes, &block)
- end
-
- def create!(attributes = {}, &block)
- _create_record(attributes, true, &block)
- end
-
# Add +records+ to this association. Returns +self+ so method calls may
# be chained. Since << flattens its argument list and inserts each record,
# +push+ and +concat+ behave identically.
@@ -191,31 +183,6 @@ module ActiveRecord
end
end
- # Returns the number of records. If no arguments are given, it counts all
- # columns using SQL. If one argument is given, it counts only the passed
- # column using SQL. If a block is given, it counts the number of records
- # yielding a true value.
- def count(column_name = nil)
- return super if block_given?
- relation = scope
- if association_scope.distinct_value
- # This is needed because 'SELECT count(DISTINCT *)..' is not valid SQL.
- column_name ||= reflection.klass.primary_key
- relation = relation.distinct
- end
-
- value = relation.count(column_name)
-
- limit = options[:limit]
- offset = options[:offset]
-
- if limit || offset
- [ [value - offset.to_i, 0].max, limit.to_i ].min
- else
- value
- end
- end
-
# Removes +records+ from this association calling +before_remove+ and
# +after_remove+ callbacks.
#
@@ -260,9 +227,9 @@ module ActiveRecord
else
target.size
end
- elsif !loaded? && !association_scope.group_values.empty?
+ elsif !association_scope.group_values.empty?
load_target.size
- elsif !loaded? && !association_scope.distinct_value && target.is_a?(Array)
+ elsif !association_scope.distinct_value && target.is_a?(Array)
unsaved_records = target.select(&:new_record?)
unsaved_records.size + count_records
else
@@ -390,9 +357,9 @@ module ActiveRecord
end
binds = AssociationScope.get_bind_values(owner, reflection.chain)
- records = sc.execute(binds, klass, conn)
- records.each { |record| set_inverse_instance(record) }
- records
+ sc.execute(binds, klass, conn) do |record|
+ set_inverse_instance(record)
+ end
end
# We have some records loaded from the database (persisted) and some that are
diff --git a/activerecord/lib/active_record/associations/collection_proxy.rb b/activerecord/lib/active_record/associations/collection_proxy.rb
index 48436155ce..dda240585e 100644
--- a/activerecord/lib/active_record/associations/collection_proxy.rb
+++ b/activerecord/lib/active_record/associations/collection_proxy.rb
@@ -743,6 +743,20 @@ module ActiveRecord
end
alias uniq distinct
+ def calculate(operation, column_name)
+ null_scope? ? scope.calculate(operation, column_name) : super
+ end
+
+ def pluck(*column_names)
+ null_scope? ? scope.pluck(*column_names) : super
+ end
+
+ ##
+ # :method: count
+ #
+ # :call-seq:
+ # count(column_name = nil, &block)
+ #
# Count all records.
#
# class Person < ActiveRecord::Base
@@ -762,17 +776,6 @@ module ActiveRecord
# perform the count using Ruby.
#
# person.pets.count { |pet| pet.name.include?('-') } # => 2
- def count(column_name = nil, &block)
- @association.count(column_name, &block)
- end
-
- def calculate(operation, column_name)
- null_scope? ? scope.calculate(operation, column_name) : super
- end
-
- def pluck(*column_names)
- null_scope? ? scope.pluck(*column_names) : super
- end
# Returns the size of the collection. If the collection hasn't been loaded,
# it executes a <tt>SELECT COUNT(*)</tt> query. Else it calls <tt>collection.size</tt>.
diff --git a/activerecord/lib/active_record/associations/has_many_association.rb b/activerecord/lib/active_record/associations/has_many_association.rb
index 6720578b2c..d1d0cc4c49 100644
--- a/activerecord/lib/active_record/associations/has_many_association.rb
+++ b/activerecord/lib/active_record/associations/has_many_association.rb
@@ -80,7 +80,7 @@ module ActiveRecord
# If there's nothing in the database and @target has no new records
# we are certain the current target is an empty array. This is a
# documented side-effect of the method that may avoid an extra SELECT.
- @target ||= [] and loaded! if count == 0
+ (@target ||= []) && loaded! if count == 0
[association_scope.limit_value, count].compact.min
end
diff --git a/activerecord/lib/active_record/associations/join_dependency.rb b/activerecord/lib/active_record/associations/join_dependency.rb
index 62acad0eda..c26c469c1e 100644
--- a/activerecord/lib/active_record/associations/join_dependency.rb
+++ b/activerecord/lib/active_record/associations/join_dependency.rb
@@ -228,8 +228,8 @@ module ActiveRecord
end
def find_reflection(klass, name)
- klass._reflect_on_association(name) or
- raise ConfigurationError, "Can't join '#{ klass.name }' to association named '#{ name }'; perhaps you misspelled it?"
+ klass._reflect_on_association(name) ||
+ raise(ConfigurationError, "Can't join '#{klass.name}' to association named '#{name}'; perhaps you misspelled it?")
end
def build(associations, base_klass)
@@ -286,17 +286,19 @@ module ActiveRecord
end
def construct_model(record, node, row, model_cache, id, aliases)
- model = model_cache[node][id] ||= node.instantiate(row,
- aliases.column_aliases(node))
other = record.association(node.reflection.name)
+ model = model_cache[node][id] ||=
+ node.instantiate(row, aliases.column_aliases(node)) do |m|
+ other.set_inverse_instance(m)
+ end
+
if node.reflection.collection?
other.target.push(model)
else
other.target = model
end
- other.set_inverse_instance(model)
model
end
end
diff --git a/activerecord/lib/active_record/associations/join_dependency/join_part.rb b/activerecord/lib/active_record/associations/join_dependency/join_part.rb
index 551087f822..61cec5403a 100644
--- a/activerecord/lib/active_record/associations/join_dependency/join_part.rb
+++ b/activerecord/lib/active_record/associations/join_dependency/join_part.rb
@@ -62,8 +62,8 @@ module ActiveRecord
hash
end
- def instantiate(row, aliases)
- base_klass.instantiate(extract_record(row, aliases))
+ def instantiate(row, aliases, &block)
+ base_klass.instantiate(extract_record(row, aliases), &block)
end
end
end
diff --git a/activerecord/lib/active_record/associations/preloader/association.rb b/activerecord/lib/active_record/associations/preloader/association.rb
index 4bb627f399..c79efca920 100644
--- a/activerecord/lib/active_record/associations/preloader/association.rb
+++ b/activerecord/lib/active_record/associations/preloader/association.rb
@@ -28,10 +28,6 @@ module ActiveRecord
end
def records_for(ids)
- query_scope(ids)
- end
-
- def query_scope(ids)
scope.where(association_key_name => ids)
end
@@ -62,7 +58,12 @@ module ActiveRecord
private
def associated_records_by_owner(preloader)
- records = load_records
+ records = load_records do |record|
+ owner = owners_by_key[convert_key(record[association_key_name])]
+ association = owner.association(reflection.name)
+ association.set_inverse_instance(record)
+ end
+
owners.each_with_object({}) do |owner, result|
result[owner] = records[convert_key(owner[owner_key_name])] || []
end
@@ -79,6 +80,15 @@ module ActiveRecord
@owner_keys
end
+ def owners_by_key
+ unless defined?(@owners_by_key)
+ @owners_by_key = owners.each_with_object({}) do |owner, h|
+ h[convert_key(owner[owner_key_name])] = owner
+ end
+ end
+ @owners_by_key
+ end
+
def key_conversion_required?
@key_conversion_required ||= association_key_type != owner_key_type
end
@@ -99,13 +109,13 @@ module ActiveRecord
@model.type_for_attribute(owner_key_name.to_s).type
end
- def load_records
+ def load_records(&block)
return {} if owner_keys.empty?
# Some databases impose a limit on the number of ids in a list (in Oracle it's 1000)
# Make several smaller queries if necessary or make one query if the adapter supports it
slices = owner_keys.each_slice(klass.connection.in_clause_length || owner_keys.size)
@preloaded_records = slices.flat_map do |slice|
- records_for(slice)
+ records_for(slice).load(&block)
end
@preloaded_records.group_by do |record|
convert_key(record[association_key_name])
diff --git a/activerecord/lib/active_record/associations/preloader/collection_association.rb b/activerecord/lib/active_record/associations/preloader/collection_association.rb
index 24b8e01029..26690bf16d 100644
--- a/activerecord/lib/active_record/associations/preloader/collection_association.rb
+++ b/activerecord/lib/active_record/associations/preloader/collection_association.rb
@@ -9,7 +9,6 @@ module ActiveRecord
association = owner.association(reflection.name)
association.loaded!
association.target.concat(records)
- records.each { |record| association.set_inverse_instance(record) }
end
end
end
diff --git a/activerecord/lib/active_record/associations/preloader/singular_association.rb b/activerecord/lib/active_record/associations/preloader/singular_association.rb
index 0888d383a6..5c5828262e 100644
--- a/activerecord/lib/active_record/associations/preloader/singular_association.rb
+++ b/activerecord/lib/active_record/associations/preloader/singular_association.rb
@@ -10,7 +10,6 @@ module ActiveRecord
association = owner.association(reflection.name)
association.target = record
- association.set_inverse_instance(record) if record
end
end
end
diff --git a/activerecord/lib/active_record/associations/singular_association.rb b/activerecord/lib/active_record/associations/singular_association.rb
index 1fe9a23263..e386cc0e4c 100644
--- a/activerecord/lib/active_record/associations/singular_association.rb
+++ b/activerecord/lib/active_record/associations/singular_association.rb
@@ -23,14 +23,6 @@ module ActiveRecord
replace(record)
end
- def create(attributes = {}, &block)
- _create_record(attributes, &block)
- end
-
- def create!(attributes = {}, &block)
- _create_record(attributes, true, &block)
- end
-
def build(attributes = {})
record = build_record(attributes)
yield(record) if block_given?
@@ -56,9 +48,9 @@ module ActiveRecord
end
binds = AssociationScope.get_bind_values(owner, reflection.chain)
- if record = sc.execute(binds, klass, conn).first
+ sc.execute(binds, klass, conn) do |record|
set_inverse_instance record
- end
+ end.first
end
def replace(record)
diff --git a/activerecord/lib/active_record/attribute.rb b/activerecord/lib/active_record/attribute.rb
index 380593e809..0b08c2a39b 100644
--- a/activerecord/lib/active_record/attribute.rb
+++ b/activerecord/lib/active_record/attribute.rb
@@ -187,7 +187,7 @@ module ActiveRecord
class Null < Attribute # :nodoc:
def initialize(name)
- super(name, nil, Type::Value.new)
+ super(name, nil, Type.default_value)
end
def type_cast(*)
diff --git a/activerecord/lib/active_record/attribute_methods/primary_key.rb b/activerecord/lib/active_record/attribute_methods/primary_key.rb
index 9e99ed8ac1..6243398a52 100644
--- a/activerecord/lib/active_record/attribute_methods/primary_key.rb
+++ b/activerecord/lib/active_record/attribute_methods/primary_key.rb
@@ -130,10 +130,10 @@ module ActiveRecord
return pk unless pk.is_a?(Array)
warn <<-WARNING.strip_heredoc
- WARNING: Active Record does not support composite primary key.
+ WARNING: Active Record does not support composite primary key.
- #{table_name} has composite primary key. Composite primary key is ignored.
- WARNING
+ #{table_name} has composite primary key. Composite primary key is ignored.
+ WARNING
end
end
end
diff --git a/activerecord/lib/active_record/attribute_methods/read.rb b/activerecord/lib/active_record/attribute_methods/read.rb
index 58f82cfd30..131ed8740b 100644
--- a/activerecord/lib/active_record/attribute_methods/read.rb
+++ b/activerecord/lib/active_record/attribute_methods/read.rb
@@ -31,11 +31,11 @@ module ActiveRecord
ActiveRecord::AttributeMethods::AttrNames.set_name_cache safe_name, name
generated_attribute_methods.module_eval <<-STR, __FILE__, __LINE__ + 1
- def #{temp_method}
- name = ::ActiveRecord::AttributeMethods::AttrNames::ATTR_#{safe_name}
- _read_attribute(name) { |n| missing_attribute(n, caller) }
- end
- STR
+ def #{temp_method}
+ name = ::ActiveRecord::AttributeMethods::AttrNames::ATTR_#{safe_name}
+ _read_attribute(name) { |n| missing_attribute(n, caller) }
+ end
+ STR
generated_attribute_methods.module_eval do
alias_method name, temp_method
diff --git a/activerecord/lib/active_record/attribute_methods/time_zone_conversion.rb b/activerecord/lib/active_record/attribute_methods/time_zone_conversion.rb
index 2c8e86fbb2..bea1514cdf 100644
--- a/activerecord/lib/active_record/attribute_methods/time_zone_conversion.rb
+++ b/activerecord/lib/active_record/attribute_methods/time_zone_conversion.rb
@@ -94,18 +94,18 @@ module ActiveRecord
cast_type.type == :time &&
time_zone_aware_types.include?(:not_explicitly_configured)
ActiveSupport::Deprecation.warn(<<-MESSAGE.strip_heredoc)
- Time columns will become time zone aware in Rails 5.1. This
- still causes `String`s to be parsed as if they were in `Time.zone`,
- and `Time`s to be converted to `Time.zone`.
+ Time columns will become time zone aware in Rails 5.1. This
+ still causes `String`s to be parsed as if they were in `Time.zone`,
+ and `Time`s to be converted to `Time.zone`.
- To keep the old behavior, you must add the following to your initializer:
+ To keep the old behavior, you must add the following to your initializer:
- config.active_record.time_zone_aware_types = [:datetime]
+ config.active_record.time_zone_aware_types = [:datetime]
- To silence this deprecation warning, add the following:
+ To silence this deprecation warning, add the following:
- config.active_record.time_zone_aware_types = [:datetime, :time]
- MESSAGE
+ config.active_record.time_zone_aware_types = [:datetime, :time]
+ MESSAGE
end
result
diff --git a/activerecord/lib/active_record/attribute_methods/write.rb b/activerecord/lib/active_record/attribute_methods/write.rb
index 5822414129..e9d044ef13 100644
--- a/activerecord/lib/active_record/attribute_methods/write.rb
+++ b/activerecord/lib/active_record/attribute_methods/write.rb
@@ -15,13 +15,13 @@ module ActiveRecord
ActiveRecord::AttributeMethods::AttrNames.set_name_cache safe_name, name
generated_attribute_methods.module_eval <<-STR, __FILE__, __LINE__ + 1
- def __temp__#{safe_name}=(value)
- name = ::ActiveRecord::AttributeMethods::AttrNames::ATTR_#{safe_name}
- write_attribute(name, value)
- end
- alias_method #{(name + '=').inspect}, :__temp__#{safe_name}=
- undef_method :__temp__#{safe_name}=
- STR
+ def __temp__#{safe_name}=(value)
+ name = ::ActiveRecord::AttributeMethods::AttrNames::ATTR_#{safe_name}
+ write_attribute(name, value)
+ end
+ alias_method #{(name + '=').inspect}, :__temp__#{safe_name}=
+ undef_method :__temp__#{safe_name}=
+ STR
end
end
diff --git a/activerecord/lib/active_record/autosave_association.rb b/activerecord/lib/active_record/autosave_association.rb
index 6e6620aad5..db84876b0a 100644
--- a/activerecord/lib/active_record/autosave_association.rb
+++ b/activerecord/lib/active_record/autosave_association.rb
@@ -457,7 +457,9 @@ module ActiveRecord
# In addition, it will destroy the association if it was marked for destruction.
def save_belongs_to_association(reflection)
association = association_instance_get(reflection.name)
- record = association && association.load_target
+ return unless association && association.loaded? && !association.stale_target?
+
+ record = association.load_target
if record && !record.destroyed?
autosave = reflection.options[:autosave]
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 45d782e45e..0bd5ec4b26 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb
@@ -970,8 +970,8 @@ module ActiveRecord
end
def foreign_key_for!(from_table, options_or_to_table = {}) # :nodoc:
- foreign_key_for(from_table, options_or_to_table) or \
- raise ArgumentError, "Table '#{from_table}' has no foreign key for #{options_or_to_table}"
+ foreign_key_for(from_table, options_or_to_table) || \
+ raise(ArgumentError, "Table '#{from_table}' has no foreign key for #{options_or_to_table}")
end
def foreign_key_column_for(table_name) # :nodoc:
diff --git a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb
index 4dde525ebc..0c7197a002 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb
@@ -433,16 +433,16 @@ module ActiveRecord
@connection
end
- def case_sensitive_comparison(attribute, column, value) # :nodoc:
- attribute.eq(value)
+ def case_sensitive_comparison(table, attribute, column, value)
+ table[attribute].eq(Arel::Nodes::BindParam.new)
end
- def case_insensitive_comparison(attribute, column, value) # :nodoc:
+ def case_insensitive_comparison(table, attribute, column, value)
if can_perform_case_insensitive_comparison_for?(column)
- value = attribute.relation.lower(value)
- attribute = attribute.lower
+ table[attribute].lower.eq(table.lower(Arel::Nodes::BindParam.new))
+ else
+ table[attribute].eq(Arel::Nodes::BindParam.new)
end
- attribute.eq(value)
end
def can_perform_case_insensitive_comparison_for?(column)
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 3a28879c15..d0ea1ce0cf 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb
@@ -570,22 +570,23 @@ module ActiveRecord
# Maps logical Rails types to MySQL-specific data types.
def type_to_sql(type, limit = nil, precision = nil, scale = nil, unsigned = nil)
- sql = case type.to_s
- when "integer"
- integer_to_sql(limit)
- when "text"
- text_to_sql(limit)
- when "blob"
- binary_to_sql(limit)
- when "binary"
- if (0..0xfff) === limit
- "varbinary(#{limit})"
- else
- binary_to_sql(limit)
- end
- else
- super(type, limit, precision, scale)
- end
+ sql = \
+ case type.to_s
+ when "integer"
+ integer_to_sql(limit)
+ when "text"
+ text_to_sql(limit)
+ when "blob"
+ binary_to_sql(limit)
+ when "binary"
+ if (0..0xfff) === limit
+ "varbinary(#{limit})"
+ else
+ binary_to_sql(limit)
+ end
+ else
+ super(type, limit, precision, scale)
+ end
sql << " unsigned" if unsigned && type != :primary_key
sql
@@ -613,11 +614,12 @@ module ActiveRecord
SQL
end
- def case_sensitive_comparison(attribute, column, value) # :nodoc:
+ def case_sensitive_comparison(table, attribute, column, value)
if column.collation && !column.case_sensitive?
- value = Arel::Nodes::Bin.new(value)
+ table[attribute].eq(Arel::Nodes::Bin.new(Arel::Nodes::BindParam.new))
+ else
+ super
end
- attribute.eq(value)
end
def can_perform_case_insensitive_comparison_for?(column)
diff --git a/activerecord/lib/active_record/connection_adapters/mysql/database_statements.rb b/activerecord/lib/active_record/connection_adapters/mysql/database_statements.rb
index c8238eb266..56800f7590 100644
--- a/activerecord/lib/active_record/connection_adapters/mysql/database_statements.rb
+++ b/activerecord/lib/active_record/connection_adapters/mysql/database_statements.rb
@@ -24,11 +24,9 @@ module ActiveRecord
# Executes the SQL statement in the context of this connection.
def execute(sql, name = nil)
- if @connection
- # make sure we carry over any changes to ActiveRecord::Base.default_timezone that have been
- # made since we established the connection
- @connection.query_options[:database_timezone] = ActiveRecord::Base.default_timezone
- end
+ # make sure we carry over any changes to ActiveRecord::Base.default_timezone that have been
+ # made since we established the connection
+ @connection.query_options[:database_timezone] = ActiveRecord::Base.default_timezone
super
end
@@ -71,11 +69,9 @@ module ActiveRecord
end
def exec_stmt_and_free(sql, name, binds, cache_stmt: false)
- if @connection
- # make sure we carry over any changes to ActiveRecord::Base.default_timezone that have been
- # made since we established the connection
- @connection.query_options[:database_timezone] = ActiveRecord::Base.default_timezone
- end
+ # make sure we carry over any changes to ActiveRecord::Base.default_timezone that have been
+ # made since we established the connection
+ @connection.query_options[:database_timezone] = ActiveRecord::Base.default_timezone
type_casted_binds = type_casted_binds(binds)
diff --git a/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb b/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb
index 0130b4ef62..a3e2c913c5 100644
--- a/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb
@@ -90,7 +90,6 @@ module ActiveRecord
#++
def active?
- return false unless @connection
@connection.ping
end
@@ -105,10 +104,7 @@ module ActiveRecord
# Otherwise, this method does nothing.
def disconnect!
super
- unless @connection.nil?
- @connection.close
- @connection = nil
- end
+ @connection.close
end
private
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/oid.rb b/activerecord/lib/active_record/connection_adapters/postgresql/oid.rb
index 8c318886cf..0e526f6201 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql/oid.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql/oid.rb
@@ -12,7 +12,7 @@ require "active_record/connection_adapters/postgresql/oid/json"
require "active_record/connection_adapters/postgresql/oid/jsonb"
require "active_record/connection_adapters/postgresql/oid/money"
require "active_record/connection_adapters/postgresql/oid/point"
-require "active_record/connection_adapters/postgresql/oid/rails_5_1_point"
+require "active_record/connection_adapters/postgresql/oid/legacy_point"
require "active_record/connection_adapters/postgresql/oid/range"
require "active_record/connection_adapters/postgresql/oid/specialized_string"
require "active_record/connection_adapters/postgresql/oid/uuid"
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/oid/array.rb b/activerecord/lib/active_record/connection_adapters/postgresql/oid/array.rb
index 1a66afb23a..b969503178 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql/oid/array.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql/oid/array.rb
@@ -33,7 +33,11 @@ module ActiveRecord
def serialize(value)
if value.is_a?(::Array)
- @pg_encoder.encode(type_cast_array(value, :serialize))
+ result = @pg_encoder.encode(type_cast_array(value, :serialize))
+ if encoding = determine_encoding_of_strings(value)
+ result.encode!(encoding)
+ end
+ result
else
super
end
@@ -63,6 +67,13 @@ module ActiveRecord
@subtype.public_send(method, value)
end
end
+
+ def determine_encoding_of_strings(value)
+ case value
+ when ::Array then determine_encoding_of_strings(value.first)
+ when ::String then value.encoding
+ end
+ end
end
end
end
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/oid/rails_5_1_point.rb b/activerecord/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb
index 845ff5b6a9..775eecaf85 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql/oid/rails_5_1_point.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb
@@ -1,10 +1,8 @@
module ActiveRecord
- Point = Struct.new(:x, :y)
-
module ConnectionAdapters
module PostgreSQL
module OID # :nodoc:
- class Rails51Point < Type::Value # :nodoc:
+ class LegacyPoint < Type::Value # :nodoc:
include Type::Helpers::Mutable
def type
@@ -14,23 +12,20 @@ module ActiveRecord
def cast(value)
case value
when ::String
- return if value.blank?
-
if value[0] == "(" && value[-1] == ")"
value = value[1...-1]
end
- x, y = value.split(",")
- build_point(x, y)
+ cast(value.split(","))
when ::Array
- build_point(*value)
+ value.map { |v| Float(v) }
else
value
end
end
def serialize(value)
- if value.is_a?(ActiveRecord::Point)
- "(#{number_for_point(value.x)},#{number_for_point(value.y)})"
+ if value.is_a?(::Array)
+ "(#{number_for_point(value[0])},#{number_for_point(value[1])})"
else
super
end
@@ -41,10 +36,6 @@ module ActiveRecord
def number_for_point(number)
number.to_s.gsub(/\.0$/, "")
end
-
- def build_point(x, y)
- ActiveRecord::Point.new(Float(x), Float(y))
- end
end
end
end
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/oid/point.rb b/activerecord/lib/active_record/connection_adapters/postgresql/oid/point.rb
index bb4db2564c..7c764e7287 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql/oid/point.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql/oid/point.rb
@@ -1,4 +1,6 @@
module ActiveRecord
+ Point = Struct.new(:x, :y)
+
module ConnectionAdapters
module PostgreSQL
module OID # :nodoc:
@@ -12,20 +14,34 @@ module ActiveRecord
def cast(value)
case value
when ::String
+ return if value.blank?
+
if value[0] == "(" && value[-1] == ")"
value = value[1...-1]
end
- cast(value.split(","))
+ x, y = value.split(",")
+ build_point(x, y)
when ::Array
- value.map { |v| Float(v) }
+ build_point(*value)
else
value
end
end
def serialize(value)
- if value.is_a?(::Array)
- "(#{number_for_point(value[0])},#{number_for_point(value[1])})"
+ case value
+ when ActiveRecord::Point
+ "(#{number_for_point(value.x)},#{number_for_point(value.y)})"
+ when ::Array
+ serialize(build_point(*value))
+ else
+ super
+ end
+ end
+
+ def type_cast_for_schema(value)
+ if ActiveRecord::Point === value
+ [value.x, value.y]
else
super
end
@@ -36,6 +52,10 @@ module ActiveRecord
def number_for_point(number)
number.to_s.gsub(/\.0$/, "")
end
+
+ def build_point(x, y)
+ ActiveRecord::Point.new(Float(x), Float(y))
+ end
end
end
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 696f2cd703..29a77580f5 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb
@@ -360,7 +360,7 @@ module ActiveRecord
# 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
+ unless pk && sequence
default_pk, default_sequence = pk_and_sequence_for(table)
pk ||= default_pk
@@ -403,7 +403,7 @@ module ActiveRecord
AND dep.refobjid = '#{quote_table_name(table)}'::regclass
end_sql
- if result.nil? or result.empty?
+ if result.nil? || result.empty?
result = query(<<-end_sql, "SCHEMA")[0]
SELECT attr.attname, nsp.nspname,
CASE
@@ -625,31 +625,32 @@ module ActiveRecord
# Maps logical Rails types to PostgreSQL-specific data types.
def type_to_sql(type, limit = nil, precision = nil, scale = nil, array = nil)
- sql = case type.to_s
- when "binary"
- # PostgreSQL doesn't support limits on binary (bytea) columns.
- # The hard limit is 1GB, because of a 32-bit size field, and TOAST.
- case limit
- when nil, 0..0x3fffffff; super(type)
- else raise(ActiveRecordError, "No binary type has byte size #{limit}.")
- end
- when "text"
- # PostgreSQL doesn't support limits on text columns.
- # The hard limit is 1GB, according to section 8.3 in the manual.
- case limit
- when nil, 0..0x3fffffff; super(type)
- else raise(ActiveRecordError, "The limit on text can be at most 1GB - 1byte.")
- end
- when "integer"
- case limit
- when 1, 2; "smallint"
- when nil, 3, 4; "integer"
- when 5..8; "bigint"
- else raise(ActiveRecordError, "No integer type has byte size #{limit}. Use a numeric with scale 0 instead.")
- end
- else
- super(type, limit, precision, scale)
- end
+ sql = \
+ case type.to_s
+ when "binary"
+ # PostgreSQL doesn't support limits on binary (bytea) columns.
+ # The hard limit is 1GB, because of a 32-bit size field, and TOAST.
+ case limit
+ when nil, 0..0x3fffffff; super(type)
+ else raise(ActiveRecordError, "No binary type has byte size #{limit}.")
+ end
+ when "text"
+ # PostgreSQL doesn't support limits on text columns.
+ # The hard limit is 1GB, according to section 8.3 in the manual.
+ case limit
+ when nil, 0..0x3fffffff; super(type)
+ else raise(ActiveRecordError, "The limit on text can be at most 1GB - 1byte.")
+ end
+ when "integer"
+ case limit
+ when 1, 2; "smallint"
+ when nil, 3, 4; "integer"
+ when 5..8; "bigint"
+ else raise(ActiveRecordError, "No integer type has byte size #{limit}. Use a numeric with scale 0 instead.")
+ end
+ else
+ super(type, limit, precision, scale)
+ end
sql << "[]" if array && type != :primary_key
sql
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
index bd53123511..03ee0eec5b 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
@@ -437,7 +437,7 @@ module ActiveRecord
type_map.fetch(oid, fmod, sql_type) {
warn "unknown OID #{oid}: failed to recognize type of '#{column_name}'. It will be treated as String."
- Type::Value.new.tap do |cast_type|
+ Type.default_value.tap do |cast_type|
type_map.register_type(oid, cast_type)
end
}
@@ -838,8 +838,8 @@ module ActiveRecord
ActiveRecord::Type.register(:json, OID::Json, adapter: :postgresql)
ActiveRecord::Type.register(:jsonb, OID::Jsonb, adapter: :postgresql)
ActiveRecord::Type.register(:money, OID::Money, adapter: :postgresql)
- ActiveRecord::Type.register(:point, OID::Rails51Point, adapter: :postgresql)
- ActiveRecord::Type.register(:legacy_point, OID::Point, adapter: :postgresql)
+ ActiveRecord::Type.register(:point, OID::Point, adapter: :postgresql)
+ ActiveRecord::Type.register(:legacy_point, OID::LegacyPoint, adapter: :postgresql)
ActiveRecord::Type.register(:uuid, OID::Uuid, adapter: :postgresql)
ActiveRecord::Type.register(:vector, OID::Vector, adapter: :postgresql)
ActiveRecord::Type.register(:xml, OID::Xml, adapter: :postgresql)
diff --git a/activerecord/lib/active_record/connection_handling.rb b/activerecord/lib/active_record/connection_handling.rb
index b4cd6cdd38..2ede92feff 100644
--- a/activerecord/lib/active_record/connection_handling.rb
+++ b/activerecord/lib/active_record/connection_handling.rb
@@ -109,7 +109,7 @@ module ActiveRecord
end
def connection_pool
- connection_handler.retrieve_connection_pool(connection_specification_name) or raise ConnectionNotEstablished
+ connection_handler.retrieve_connection_pool(connection_specification_name) || raise(ConnectionNotEstablished)
end
def retrieve_connection
diff --git a/activerecord/lib/active_record/core.rb b/activerecord/lib/active_record/core.rb
index aef4761be4..3465b68ac6 100644
--- a/activerecord/lib/active_record/core.rb
+++ b/activerecord/lib/active_record/core.rb
@@ -229,7 +229,7 @@ module ActiveRecord
end
def find_by!(*args) # :nodoc:
- find_by(*args) or raise RecordNotFound.new("Couldn't find #{name}", name)
+ find_by(*args) || raise(RecordNotFound.new("Couldn't find #{name}", name))
end
def initialize_generated_modules # :nodoc:
@@ -366,6 +366,8 @@ module ActiveRecord
self.class.define_attribute_methods
+ yield self if block_given?
+
_run_find_callbacks
_run_initialize_callbacks
@@ -498,7 +500,7 @@ module ActiveRecord
# We check defined?(@attributes) not to issue warnings if the object is
# allocated but not initialized.
inspection = if defined?(@attributes) && @attributes
- self.class.column_names.collect do |name|
+ self.class.attribute_names.collect do |name|
if has_attribute?(name)
"#{name}: #{attribute_for_inspect(name)}"
end
diff --git a/activerecord/lib/active_record/dynamic_matchers.rb b/activerecord/lib/active_record/dynamic_matchers.rb
index fd2fa7410a..bbd8ca2377 100644
--- a/activerecord/lib/active_record/dynamic_matchers.rb
+++ b/activerecord/lib/active_record/dynamic_matchers.rb
@@ -2,7 +2,7 @@ require "active_support/core_ext/regexp"
module ActiveRecord
module DynamicMatchers #:nodoc:
- def respond_to?(name, include_private = false)
+ def respond_to_missing?(name, include_private = false)
if self == Base
super
else
@@ -63,10 +63,10 @@ module ActiveRecord
def define
model.class_eval <<-CODE, __FILE__, __LINE__ + 1
- def self.#{name}(#{signature})
- #{body}
- end
- CODE
+ def self.#{name}(#{signature})
+ #{body}
+ end
+ CODE
end
private
diff --git a/activerecord/lib/active_record/fixtures.rb b/activerecord/lib/active_record/fixtures.rb
index 40a9aa2783..8b47fbdbe4 100644
--- a/activerecord/lib/active_record/fixtures.rb
+++ b/activerecord/lib/active_record/fixtures.rb
@@ -902,7 +902,7 @@ module ActiveRecord
def fixtures(*fixture_set_names)
if fixture_set_names.first == :all
- fixture_set_names = Dir["#{fixture_path}/{**,*}/*.{yml}"]
+ fixture_set_names = Dir["#{fixture_path}/{**,*}/*.{yml}"].uniq
fixture_set_names.map! { |f| f[(fixture_path.to_s.size + 1)..-5] }
else
fixture_set_names = fixture_set_names.flatten.map(&:to_s)
diff --git a/activerecord/lib/active_record/migration/command_recorder.rb b/activerecord/lib/active_record/migration/command_recorder.rb
index 6b2c5d8da5..44ea756028 100644
--- a/activerecord/lib/active_record/migration/command_recorder.rb
+++ b/activerecord/lib/active_record/migration/command_recorder.rb
@@ -92,7 +92,7 @@ module ActiveRecord
send(method, args, &block)
end
- def respond_to?(*args) # :nodoc:
+ def respond_to_missing?(*args) # :nodoc:
super || delegate.respond_to?(*args)
end
@@ -125,10 +125,10 @@ module ActiveRecord
}.each do |cmd, inv|
[[inv, cmd], [cmd, inv]].uniq.each do |method, inverse|
class_eval <<-EOV, __FILE__, __LINE__ + 1
- def invert_#{method}(args, &block) # def invert_create_table(args, &block)
- [:#{inverse}, args, block] # [:drop_table, args, block]
- end # end
- EOV
+ def invert_#{method}(args, &block) # def invert_create_table(args, &block)
+ [:#{inverse}, args, block] # [:drop_table, args, block]
+ end # end
+ EOV
end
end
end
diff --git a/activerecord/lib/active_record/model_schema.rb b/activerecord/lib/active_record/model_schema.rb
index 5718e7fdd0..f49f8da2ed 100644
--- a/activerecord/lib/active_record/model_schema.rb
+++ b/activerecord/lib/active_record/model_schema.rb
@@ -268,7 +268,7 @@ module ActiveRecord
def attribute_types # :nodoc:
load_schema
- @attribute_types ||= Hash.new(Type::Value.new)
+ @attribute_types ||= Hash.new(Type.default_value)
end
def yaml_encoder # :nodoc:
@@ -370,7 +370,6 @@ module ActiveRecord
def load_schema!
@columns_hash = connection.schema_cache.columns_hash(table_name).except(*ignored_columns)
@columns_hash.each do |name, column|
- warn_if_deprecated_type(column)
define_attribute(
name,
connection.lookup_cast_type_from_column(column),
@@ -421,28 +420,6 @@ module ActiveRecord
base.table_name
end
end
-
- def warn_if_deprecated_type(column)
- return if attributes_to_define_after_schema_loads.key?(column.name)
- if column.respond_to?(:oid) && column.sql_type.start_with?("point")
- if column.array?
- array_arguments = ", array: true"
- else
- array_arguments = ""
- end
- ActiveSupport::Deprecation.warn(<<-WARNING.strip_heredoc)
- The behavior of the `:point` type will be changing in Rails 5.1 to
- return a `Point` object, rather than an `Array`. If you'd like to
- keep the old behavior, you can add this line to #{name}:
-
- attribute :#{column.name}, :legacy_point#{array_arguments}
-
- If you'd like the new behavior today, you can add this line:
-
- attribute :#{column.name}, :point#{array_arguments}
- WARNING
- end
- end
end
end
end
diff --git a/activerecord/lib/active_record/nested_attributes.rb b/activerecord/lib/active_record/nested_attributes.rb
index 86f8cb5d26..f0f88b120a 100644
--- a/activerecord/lib/active_record/nested_attributes.rb
+++ b/activerecord/lib/active_record/nested_attributes.rb
@@ -354,13 +354,13 @@ module ActiveRecord
# associations are just regular associations.
def generate_association_writer(association_name, type)
generated_association_methods.module_eval <<-eoruby, __FILE__, __LINE__ + 1
- if method_defined?(:#{association_name}_attributes=)
- remove_method(:#{association_name}_attributes=)
- end
- def #{association_name}_attributes=(attributes)
- assign_nested_attributes_for_#{type}_association(:#{association_name}, attributes)
- end
- eoruby
+ if method_defined?(:#{association_name}_attributes=)
+ remove_method(:#{association_name}_attributes=)
+ end
+ def #{association_name}_attributes=(attributes)
+ assign_nested_attributes_for_#{type}_association(:#{association_name}, attributes)
+ end
+ eoruby
end
end
@@ -519,14 +519,15 @@ module ActiveRecord
# larger than the limit.
def check_record_limit!(limit, attributes_collection)
if limit
- limit = case limit
- when Symbol
- send(limit)
- when Proc
- limit.call
- else
- limit
- end
+ limit = \
+ case limit
+ when Symbol
+ send(limit)
+ when Proc
+ limit.call
+ else
+ limit
+ end
if limit && attributes_collection.size > limit
raise TooManyRecords, "Maximum #{limit} records are allowed. Got #{attributes_collection.size} records instead."
diff --git a/activerecord/lib/active_record/persistence.rb b/activerecord/lib/active_record/persistence.rb
index dc4af4f390..a04ef2e263 100644
--- a/activerecord/lib/active_record/persistence.rb
+++ b/activerecord/lib/active_record/persistence.rb
@@ -63,10 +63,10 @@ module ActiveRecord
#
# See <tt>ActiveRecord::Inheritance#discriminate_class_for_record</tt> to see
# how this "single-table" inheritance mapping is implemented.
- def instantiate(attributes, column_types = {})
+ def instantiate(attributes, column_types = {}, &block)
klass = discriminate_class_for_record(attributes)
attributes = klass.attributes_builder.build_from_database(attributes, column_types)
- klass.allocate.init_with("attributes" => attributes, "new_record" => false)
+ klass.allocate.init_with("attributes" => attributes, "new_record" => false, &block)
end
private
@@ -178,7 +178,7 @@ module ActiveRecord
# and #destroy returns +false+.
# See ActiveRecord::Callbacks for further details.
def destroy
- raise ReadOnlyRecord, "#{self.class} is marked as readonly" if readonly?
+ _raise_readonly_record_error if readonly?
destroy_associations
self.class.connection.add_transaction_record(self)
destroy_row if persisted?
@@ -535,7 +535,7 @@ module ActiveRecord
end
def create_or_update(*args)
- raise ReadOnlyRecord, "#{self.class} is marked as readonly" if readonly?
+ _raise_readonly_record_error if readonly?
result = new_record? ? _create_record : _update_record(*args)
result != false
end
@@ -577,5 +577,9 @@ module ActiveRecord
def belongs_to_touch_method
:touch
end
+
+ def _raise_readonly_record_error
+ raise ReadOnlyRecord, "#{self.class} is marked as readonly"
+ end
end
end
diff --git a/activerecord/lib/active_record/querying.rb b/activerecord/lib/active_record/querying.rb
index dd7d650207..36689f6559 100644
--- a/activerecord/lib/active_record/querying.rb
+++ b/activerecord/lib/active_record/querying.rb
@@ -35,7 +35,7 @@ module ActiveRecord
#
# Post.find_by_sql ["SELECT title FROM posts WHERE author = ? AND created > ?", author_id, start_date]
# Post.find_by_sql ["SELECT body FROM comments WHERE author = :user_id OR approved_by = :user_id", { :user_id => user_id }]
- def find_by_sql(sql, binds = [], preparable: nil)
+ def find_by_sql(sql, binds = [], preparable: nil, &block)
result_set = connection.select_all(sanitize_sql(sql), "#{name} Load", binds, preparable: preparable)
column_types = result_set.column_types.dup
columns_hash.each_key { |k| column_types.delete k }
@@ -47,7 +47,7 @@ module ActiveRecord
}
message_bus.instrument("instantiation.active_record", payload) do
- result_set.map { |record| instantiate(record, column_types) }
+ result_set.map { |record| instantiate(record, column_types, &block) }
end
end
diff --git a/activerecord/lib/active_record/reflection.rb b/activerecord/lib/active_record/reflection.rb
index 8c5e4d042e..9b692f55d2 100644
--- a/activerecord/lib/active_record/reflection.rb
+++ b/activerecord/lib/active_record/reflection.rb
@@ -14,18 +14,19 @@ module ActiveRecord
end
def self.create(macro, name, scope, options, ar)
- klass = case macro
- when :composed_of
- AggregateReflection
- when :has_many
- HasManyReflection
- when :has_one
- HasOneReflection
- when :belongs_to
- BelongsToReflection
- else
- raise "Unsupported Macro: #{macro}"
- end
+ klass = \
+ case macro
+ when :composed_of
+ AggregateReflection
+ when :has_many
+ HasManyReflection
+ when :has_one
+ HasOneReflection
+ when :belongs_to
+ BelongsToReflection
+ else
+ raise "Unsupported Macro: #{macro}"
+ end
reflection = klass.new(name, scope, options, ar)
options[:through] ? ThroughReflection.new(reflection) : reflection
diff --git a/activerecord/lib/active_record/relation.rb b/activerecord/lib/active_record/relation.rb
index d7de1032b6..ef629dcb3b 100644
--- a/activerecord/lib/active_record/relation.rb
+++ b/activerecord/lib/active_record/relation.rb
@@ -243,7 +243,6 @@ module ActiveRecord
# Please see further details in the
# {Active Record Query Interface guide}[http://guides.rubyonrails.org/active_record_querying.html#running-explain].
def explain
- #TODO: Fix for binds.
exec_explain(collecting_queries_for_explain { exec_queries })
end
@@ -562,8 +561,8 @@ module ActiveRecord
# return value is the relation itself, not the records.
#
# Post.where(published: true).load # => #<ActiveRecord::Relation>
- def load
- exec_queries unless loaded?
+ def load(&block)
+ exec_queries(&block) unless loaded?
self
end
@@ -678,8 +677,8 @@ module ActiveRecord
private
- def exec_queries
- @records = eager_loading? ? find_with_associations.freeze : @klass.find_by_sql(arel, bound_attributes).freeze
+ def exec_queries(&block)
+ @records = eager_loading? ? find_with_associations.freeze : @klass.find_by_sql(arel, bound_attributes, &block).freeze
preload = preload_values
preload += includes_values unless eager_loading?
diff --git a/activerecord/lib/active_record/relation/calculations.rb b/activerecord/lib/active_record/relation/calculations.rb
index b569abc7a8..a796e35261 100644
--- a/activerecord/lib/active_record/relation/calculations.rb
+++ b/activerecord/lib/active_record/relation/calculations.rb
@@ -312,7 +312,7 @@ module ActiveRecord
key = group_columns.map { |aliaz, col_name|
column = type_for(col_name) do
calculated_data.column_types.fetch(aliaz) do
- Type::Value.new
+ Type.default_value
end
end
type_cast_calculated_value(row[aliaz], column)
diff --git a/activerecord/lib/active_record/relation/delegation.rb b/activerecord/lib/active_record/relation/delegation.rb
index e1c36982dd..d16de4b06c 100644
--- a/activerecord/lib/active_record/relation/delegation.rb
+++ b/activerecord/lib/active_record/relation/delegation.rb
@@ -108,7 +108,7 @@ module ActiveRecord
end
end
- def respond_to?(method, include_private = false)
+ def respond_to_missing?(method, include_private = false)
super || @klass.respond_to?(method, include_private) ||
arel.respond_to?(method, include_private)
end
diff --git a/activerecord/lib/active_record/relation/finder_methods.rb b/activerecord/lib/active_record/relation/finder_methods.rb
index 376867675b..5e580ac865 100644
--- a/activerecord/lib/active_record/relation/finder_methods.rb
+++ b/activerecord/lib/active_record/relation/finder_methods.rb
@@ -466,9 +466,9 @@ module ActiveRecord
if ActiveRecord::Base === id
id = id.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
+ You are passing an instance of ActiveRecord::Base to `find`.
+ Please pass the id of the object by calling `.id`.
+ MSG
end
relation = where(primary_key => id)
diff --git a/activerecord/lib/active_record/relation/predicate_builder.rb b/activerecord/lib/active_record/relation/predicate_builder.rb
index 29422bf131..780a1ee422 100644
--- a/activerecord/lib/active_record/relation/predicate_builder.rb
+++ b/activerecord/lib/active_record/relation/predicate_builder.rb
@@ -4,7 +4,6 @@ module ActiveRecord
require "active_record/relation/predicate_builder/association_query_handler"
require "active_record/relation/predicate_builder/base_handler"
require "active_record/relation/predicate_builder/basic_object_handler"
- require "active_record/relation/predicate_builder/case_sensitive_handler"
require "active_record/relation/predicate_builder/class_handler"
require "active_record/relation/predicate_builder/polymorphic_array_handler"
require "active_record/relation/predicate_builder/range_handler"
@@ -17,7 +16,6 @@ module ActiveRecord
@handlers = []
register_handler(BasicObject, BasicObjectHandler.new)
- register_handler(CaseSensitiveHandler::Value, CaseSensitiveHandler.new)
register_handler(Class, ClassHandler.new(self))
register_handler(Base, BaseHandler.new(self))
register_handler(Range, RangeHandler.new)
@@ -33,9 +31,9 @@ module ActiveRecord
expand_from_hash(attributes)
end
- def create_binds(attributes, options)
+ def create_binds(attributes)
attributes = convert_dot_notation_to_hash(attributes)
- create_binds_for_hash(attributes, options)
+ create_binds_for_hash(attributes)
end
def self.references(attributes)
@@ -84,14 +82,14 @@ module ActiveRecord
end
end
- def create_binds_for_hash(attributes, options)
+ def create_binds_for_hash(attributes)
result = attributes.dup
binds = []
attributes.each do |column_name, value|
case
when value.is_a?(Hash) && !table.has_column?(column_name)
- attrs, bvs = associated_predicate_builder(column_name).create_binds_for_hash(value, options)
+ attrs, bvs = associated_predicate_builder(column_name).create_binds_for_hash(value)
result[column_name] = attrs
binds += bvs
next
@@ -110,15 +108,11 @@ module ActiveRecord
end
result[column_name] = RangeHandler::RangeWithBinds.new(first, last, value.exclude_end?)
- when can_be_bound?(column_name, value)
- result[column_name] =
- if perform_case_sensitive?(options)
- CaseSensitiveHandler::Value.new(
- Arel::Nodes::BindParam.new, table, options[:case_sensitive])
- else
- Arel::Nodes::BindParam.new
- end
- binds << build_bind_param(column_name, value)
+ else
+ if can_be_bound?(column_name, value)
+ result[column_name] = Arel::Nodes::BindParam.new
+ binds << build_bind_param(column_name, value)
+ end
end
# Find the foreign key when using queries such as:
@@ -170,10 +164,6 @@ module ActiveRecord
end
end
- def perform_case_sensitive?(options)
- options.key?(:case_sensitive)
- end
-
def build_bind_param(column_name, value)
Relation::QueryAttribute.new(column_name.to_s, value, table.type(column_name))
end
diff --git a/activerecord/lib/active_record/relation/predicate_builder/case_sensitive_handler.rb b/activerecord/lib/active_record/relation/predicate_builder/case_sensitive_handler.rb
deleted file mode 100644
index acf0bbd829..0000000000
--- a/activerecord/lib/active_record/relation/predicate_builder/case_sensitive_handler.rb
+++ /dev/null
@@ -1,21 +0,0 @@
-module ActiveRecord
- class PredicateBuilder
- class CaseSensitiveHandler # :nodoc:
- def call(attribute, value)
- value.call(attribute)
- end
-
- class Value < Struct.new(:value, :table, :case_sensitive?) # :nodoc:
- def call(attribute)
- klass = table.send(:klass)
- column = klass.column_for_attribute(attribute.name)
- if case_sensitive?
- klass.connection.case_sensitive_comparison(attribute, column, value)
- else
- klass.connection.case_insensitive_comparison(attribute, column, value)
- end
- end
- end
- end
- end
-end
diff --git a/activerecord/lib/active_record/relation/predicate_builder/class_handler.rb b/activerecord/lib/active_record/relation/predicate_builder/class_handler.rb
index 73ad864765..0a6574fcf1 100644
--- a/activerecord/lib/active_record/relation/predicate_builder/class_handler.rb
+++ b/activerecord/lib/active_record/relation/predicate_builder/class_handler.rb
@@ -18,9 +18,9 @@ module ActiveRecord
def print_deprecation_warning
ActiveSupport::Deprecation.warn(<<-MSG.squish)
- Passing a class as a value in an Active Record query is deprecated and
- will be removed. Pass a string instead.
- MSG
+ Passing a class as a value in an Active Record query is deprecated and
+ will be removed. Pass a string instead.
+ MSG
end
end
end
diff --git a/activerecord/lib/active_record/relation/query_methods.rb b/activerecord/lib/active_record/relation/query_methods.rb
index bd41653df0..78570140e5 100644
--- a/activerecord/lib/active_record/relation/query_methods.rb
+++ b/activerecord/lib/active_record/relation/query_methods.rb
@@ -59,11 +59,12 @@ module ActiveRecord
FROZEN_EMPTY_HASH = {}.freeze
Relation::VALUE_METHODS.each do |name|
- method_name = case name
- when *Relation::MULTI_VALUE_METHODS then "#{name}_values"
- when *Relation::SINGLE_VALUE_METHODS then "#{name}_value"
- when *Relation::CLAUSE_METHODS then "#{name}_clause"
- end
+ method_name = \
+ case name
+ when *Relation::MULTI_VALUE_METHODS then "#{name}_values"
+ when *Relation::SINGLE_VALUE_METHODS then "#{name}_value"
+ when *Relation::CLAUSE_METHODS then "#{name}_clause"
+ end
class_eval <<-CODE, __FILE__, __LINE__ + 1
def #{method_name} # def includes_values
get_value(#{name.inspect}) # get_value(:includes)
@@ -80,14 +81,14 @@ module ActiveRecord
limit_bind = Attribute.with_cast_value(
"LIMIT".freeze,
connection.sanitize_limit(limit_value),
- Type::Value.new,
+ Type.default_value,
)
end
if offset_value
offset_bind = Attribute.with_cast_value(
"OFFSET".freeze,
offset_value.to_i,
- Type::Value.new,
+ Type.default_value,
)
end
connection.combine_bind_parameters(
@@ -470,7 +471,6 @@ module ActiveRecord
self.left_outer_joins_values += args
self
end
- alias :left_joins! :left_outer_joins!
# Returns a new relation, which is the result of filtering the current relation
# according to the conditions in the arguments.
diff --git a/activerecord/lib/active_record/relation/where_clause_factory.rb b/activerecord/lib/active_record/relation/where_clause_factory.rb
index 122ab04c00..dc00149130 100644
--- a/activerecord/lib/active_record/relation/where_clause_factory.rb
+++ b/activerecord/lib/active_record/relation/where_clause_factory.rb
@@ -17,7 +17,7 @@ module ActiveRecord
attributes = klass.send(:expand_hash_conditions_for_aggregates, attributes)
attributes.stringify_keys!
- attributes, binds = predicate_builder.create_binds(attributes, other.last || {})
+ attributes, binds = predicate_builder.create_binds(attributes)
parts = predicate_builder.build_from_hash(attributes)
when Arel::Nodes::Node
diff --git a/activerecord/lib/active_record/result.rb b/activerecord/lib/active_record/result.rb
index f5383f4c14..9ed70a9c2b 100644
--- a/activerecord/lib/active_record/result.rb
+++ b/activerecord/lib/active_record/result.rb
@@ -32,8 +32,6 @@ module ActiveRecord
class Result
include Enumerable
- IDENTITY_TYPE = Type::Value.new # :nodoc:
-
attr_reader :columns, :rows, :column_types
def initialize(columns, rows, column_types = {})
@@ -105,7 +103,7 @@ module ActiveRecord
def column_type(name, type_overrides = {})
type_overrides.fetch(name) do
- column_types.fetch(name, IDENTITY_TYPE)
+ column_types.fetch(name, Type.default_value)
end
end
diff --git a/activerecord/lib/active_record/statement_cache.rb b/activerecord/lib/active_record/statement_cache.rb
index fd67032235..d19bb96ede 100644
--- a/activerecord/lib/active_record/statement_cache.rb
+++ b/activerecord/lib/active_record/statement_cache.rb
@@ -99,12 +99,12 @@ module ActiveRecord
@bind_map = bind_map
end
- def execute(params, klass, connection)
+ def execute(params, klass, connection, &block)
bind_values = bind_map.bind params
sql = query_builder.sql_for bind_values, connection
- klass.find_by_sql(sql, bind_values, preparable: true)
+ klass.find_by_sql(sql, bind_values, preparable: true, &block)
end
alias :call :execute
end
diff --git a/activerecord/lib/active_record/table_metadata.rb b/activerecord/lib/active_record/table_metadata.rb
index a2cb3ea1be..58184f3872 100644
--- a/activerecord/lib/active_record/table_metadata.rb
+++ b/activerecord/lib/active_record/table_metadata.rb
@@ -31,7 +31,7 @@ module ActiveRecord
if klass
klass.type_for_attribute(column_name.to_s)
else
- Type::Value.new
+ Type.default_value
end
end
diff --git a/activerecord/lib/active_record/tasks/mysql_database_tasks.rb b/activerecord/lib/active_record/tasks/mysql_database_tasks.rb
index c8b89f1fdf..3a5e0b8dfe 100644
--- a/activerecord/lib/active_record/tasks/mysql_database_tasks.rb
+++ b/activerecord/lib/active_record/tasks/mysql_database_tasks.rb
@@ -105,7 +105,7 @@ module ActiveRecord
GRANT ALL PRIVILEGES ON #{configuration['database']}.*
TO '#{configuration['username']}'@'localhost'
IDENTIFIED BY '#{configuration['password']}' WITH GRANT OPTION;
- SQL
+ SQL
end
def root_configuration_without_database
diff --git a/activerecord/lib/active_record/tasks/postgresql_database_tasks.rb b/activerecord/lib/active_record/tasks/postgresql_database_tasks.rb
index 6eac9af236..a3a9430c03 100644
--- a/activerecord/lib/active_record/tasks/postgresql_database_tasks.rb
+++ b/activerecord/lib/active_record/tasks/postgresql_database_tasks.rb
@@ -46,14 +46,15 @@ module ActiveRecord
def structure_dump(filename)
set_psql_env
- search_path = case ActiveRecord::Base.dump_schemas
- when :schema_search_path
- configuration["schema_search_path"]
- when :all
- nil
- when String
- ActiveRecord::Base.dump_schemas
- end
+ search_path = \
+ case ActiveRecord::Base.dump_schemas
+ when :schema_search_path
+ configuration["schema_search_path"]
+ when :all
+ nil
+ when String
+ ActiveRecord::Base.dump_schemas
+ end
args = ["-s", "-x", "-O", "-f", filename]
unless search_path.blank?
diff --git a/activerecord/lib/active_record/type.rb b/activerecord/lib/active_record/type.rb
index 1b2fc1b034..0b48d2186a 100644
--- a/activerecord/lib/active_record/type.rb
+++ b/activerecord/lib/active_record/type.rb
@@ -37,6 +37,10 @@ module ActiveRecord
registry.lookup(*args, adapter: adapter, **kwargs)
end
+ def default_value # :nodoc:
+ @default_value ||= Value.new
+ end
+
private
def current_adapter_name
diff --git a/activerecord/lib/active_record/type/type_map.rb b/activerecord/lib/active_record/type/type_map.rb
index 9618ff8787..7bce82a1ff 100644
--- a/activerecord/lib/active_record/type/type_map.rb
+++ b/activerecord/lib/active_record/type/type_map.rb
@@ -11,7 +11,7 @@ module ActiveRecord
end
def lookup(lookup_key, *args)
- fetch(lookup_key, *args) { default_value }
+ fetch(lookup_key, *args) { Type.default_value }
end
def fetch(lookup_key, *args, &block)
@@ -55,10 +55,6 @@ module ActiveRecord
yield lookup_key, *args
end
end
-
- def default_value
- @default_value ||= ActiveModel::Type::Value.new
- end
end
end
end
diff --git a/activerecord/lib/active_record/validations/uniqueness.rb b/activerecord/lib/active_record/validations/uniqueness.rb
index 08c4b01439..8c4930a81d 100644
--- a/activerecord/lib/active_record/validations/uniqueness.rb
+++ b/activerecord/lib/active_record/validations/uniqueness.rb
@@ -50,7 +50,37 @@ module ActiveRecord
end
def build_relation(klass, attribute, value) # :nodoc:
- klass.unscoped.where!({ attribute => value }, options)
+ if reflection = klass._reflect_on_association(attribute)
+ attribute = reflection.foreign_key
+ value = value.attributes[reflection.klass.primary_key] unless value.nil?
+ end
+
+ if value.nil?
+ return klass.unscoped.where!(attribute => value)
+ end
+
+ # the attribute may be an aliased attribute
+ if klass.attribute_alias?(attribute)
+ attribute = klass.attribute_alias(attribute)
+ end
+
+ attribute_name = attribute.to_s
+
+ table = klass.arel_table
+ column = klass.columns_hash[attribute_name]
+ cast_type = klass.type_for_attribute(attribute_name)
+
+ comparison = if !options[:case_sensitive]
+ # will use SQL LOWER function before comparison, unless it detects a case insensitive collation
+ klass.connection.case_insensitive_comparison(table, attribute, column, value)
+ else
+ klass.connection.case_sensitive_comparison(table, attribute, column, value)
+ end
+ klass.unscoped.tap do |scope|
+ parts = [comparison]
+ binds = [Relation::QueryAttribute.new(attribute_name, value, cast_type)]
+ scope.where_clause += Relation::WhereClause.new(parts, binds)
+ end
end
def scope_relation(record, relation)
diff --git a/activerecord/test/cases/adapters/mysql2/connection_test.rb b/activerecord/test/cases/adapters/mysql2/connection_test.rb
index 9ede57d395..e014229650 100644
--- a/activerecord/test/cases/adapters/mysql2/connection_test.rb
+++ b/activerecord/test/cases/adapters/mysql2/connection_test.rb
@@ -63,6 +63,27 @@ class Mysql2ConnectionTest < ActiveRecord::Mysql2TestCase
assert @connection.active?
end
+ def test_execute_after_disconnect
+ @connection.disconnect!
+ error = assert_raise(ActiveRecord::StatementInvalid) do
+ @connection.execute("SELECT 1")
+ end
+ assert_match /closed MySQL connection/, error.message
+ end
+
+ def test_quote_after_disconnect
+ @connection.disconnect!
+ error = assert_raise(Mysql2::Error) do
+ @connection.quote("string")
+ end
+ assert_match /closed MySQL connection/, error.message
+ end
+
+ def test_active_after_disconnect
+ @connection.disconnect!
+ assert_equal false, @connection.active?
+ end
+
def test_mysql_connection_collation_is_configured
assert_equal "utf8_unicode_ci", @connection.show_variable("collation_connection")
assert_equal "utf8_general_ci", ARUnit2Model.connection.show_variable("collation_connection")
diff --git a/activerecord/test/cases/adapters/postgresql/array_test.rb b/activerecord/test/cases/adapters/postgresql/array_test.rb
index 60da9d8859..97960b6c51 100644
--- a/activerecord/test/cases/adapters/postgresql/array_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/array_test.rb
@@ -311,6 +311,12 @@ class PostgresqlArrayTest < ActiveRecord::PostgreSQLTestCase
assert_equal ["has already been taken"], e2.errors[:tags], "Should have uniqueness message for tags"
end
+ def test_encoding_arrays_of_utf8_strings
+ string_with_utf8 = "nový"
+ assert_equal [string_with_utf8], @type.deserialize(@type.serialize([string_with_utf8]))
+ assert_equal [[string_with_utf8]], @type.deserialize(@type.serialize([[string_with_utf8]]))
+ end
+
private
def assert_cycle(field, array)
# test creation
diff --git a/activerecord/test/cases/adapters/postgresql/geometric_test.rb b/activerecord/test/cases/adapters/postgresql/geometric_test.rb
index 27a7467326..a65d4d1ad9 100644
--- a/activerecord/test/cases/adapters/postgresql/geometric_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/geometric_test.rb
@@ -27,22 +27,10 @@ class PostgresqlPointTest < ActiveRecord::PostgreSQLTestCase
t.point :legacy_y, default: [12.2, 13.3]
t.point :legacy_z, default: "(14.4,15.5)"
end
- @connection.create_table("deprecated_points") do |t|
- t.point :x
- end
end
teardown do
@connection.drop_table "postgresql_points", if_exists: true
- @connection.drop_table "deprecated_points", if_exists: true
- end
-
- class DeprecatedPoint < ActiveRecord::Base; end
-
- def test_deprecated_legacy_type
- assert_deprecated do
- DeprecatedPoint.new
- end
end
def test_column
diff --git a/activerecord/test/cases/adapters/postgresql/rename_table_test.rb b/activerecord/test/cases/adapters/postgresql/rename_table_test.rb
index 461353d239..e9e7f717ac 100644
--- a/activerecord/test/cases/adapters/postgresql/rename_table_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/rename_table_test.rb
@@ -26,9 +26,9 @@ class PostgresqlRenameTableTest < ActiveRecord::PostgreSQLTestCase
def num_indices_named(name)
@connection.execute(<<-SQL).values.length
- SELECT 1 FROM "pg_index"
- JOIN "pg_class" ON "pg_index"."indexrelid" = "pg_class"."oid"
- WHERE "pg_class"."relname" = '#{name}'
- SQL
+ SELECT 1 FROM "pg_index"
+ JOIN "pg_class" ON "pg_index"."indexrelid" = "pg_class"."oid"
+ WHERE "pg_class"."relname" = '#{name}'
+ SQL
end
end
diff --git a/activerecord/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb b/activerecord/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb
index d2f0710cb2..66f9349111 100644
--- a/activerecord/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb
+++ b/activerecord/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb
@@ -431,9 +431,9 @@ module ActiveRecord
def with_example_table(definition = nil, table_name = "ex", &block)
definition ||= <<-SQL
- id integer PRIMARY KEY AUTOINCREMENT,
- number integer
- SQL
+ id integer PRIMARY KEY AUTOINCREMENT,
+ number integer
+ SQL
super(@conn, table_name, definition, &block)
end
end
diff --git a/activerecord/test/cases/associations/belongs_to_associations_test.rb b/activerecord/test/cases/associations/belongs_to_associations_test.rb
index 3f42cb9b9d..2418346d1b 100644
--- a/activerecord/test/cases/associations/belongs_to_associations_test.rb
+++ b/activerecord/test/cases/associations/belongs_to_associations_test.rb
@@ -626,6 +626,12 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase
assert_queries(0) { tagging.super_tag }
end
+ def test_dont_find_target_when_saving_foreign_key_after_stale_association_loaded
+ client = Client.create!(name: "Test client", firm_with_basic_id: Firm.find(1))
+ client.firm_id = Firm.create!(name: "Test firm").id
+ assert_queries(1) { client.save! }
+ end
+
def test_field_name_same_as_foreign_key
computer = Computer.find(1)
assert_not_nil computer.developer, ":foreign key == attribute didn't lock up" # '
diff --git a/activerecord/test/cases/associations/inverse_associations_test.rb b/activerecord/test/cases/associations/inverse_associations_test.rb
index 0b23cea420..6fe6ee6783 100644
--- a/activerecord/test/cases/associations/inverse_associations_test.rb
+++ b/activerecord/test/cases/associations/inverse_associations_test.rb
@@ -494,6 +494,33 @@ class InverseHasManyTests < ActiveRecord::TestCase
assert !man.persisted?
end
+
+ def test_inverse_instance_should_be_set_before_find_callbacks_are_run
+ reset_callbacks(Interest, :find) do
+ Interest.after_find { raise unless association(:man).loaded? && man.present? }
+
+ assert Man.first.interests.reload.any?
+ assert Man.includes(:interests).first.interests.any?
+ assert Man.joins(:interests).includes(:interests).first.interests.any?
+ end
+ end
+
+ def test_inverse_instance_should_be_set_before_initialize_callbacks_are_run
+ reset_callbacks(Interest, :initialize) do
+ Interest.after_initialize { raise unless association(:man).loaded? && man.present? }
+
+ assert Man.first.interests.reload.any?
+ assert Man.includes(:interests).first.interests.any?
+ assert Man.joins(:interests).includes(:interests).first.interests.any?
+ end
+ end
+
+ def reset_callbacks(target, type)
+ old_callbacks = target.send(:get_callbacks, type).deep_dup
+ yield
+ ensure
+ target.send(:set_callbacks, type, old_callbacks) if old_callbacks
+ end
end
class InverseBelongsToTests < ActiveRecord::TestCase
diff --git a/activerecord/test/cases/attribute_methods/read_test.rb b/activerecord/test/cases/attribute_methods/read_test.rb
index 2d2ecb4079..074cfe7ffb 100644
--- a/activerecord/test/cases/attribute_methods/read_test.rb
+++ b/activerecord/test/cases/attribute_methods/read_test.rb
@@ -1,5 +1,4 @@
require "cases/helper"
-require "thread"
module ActiveRecord
module AttributeMethods
diff --git a/activerecord/test/cases/attribute_methods_test.rb b/activerecord/test/cases/attribute_methods_test.rb
index 7a2041937d..993d9f8b94 100644
--- a/activerecord/test/cases/attribute_methods_test.rb
+++ b/activerecord/test/cases/attribute_methods_test.rb
@@ -1003,10 +1003,10 @@ class AttributeMethodsTest < ActiveRecord::TestCase
def privatize(method_signature)
@target.class_eval(<<-private_method, __FILE__, __LINE__ + 1)
- private
- def #{method_signature}
- "I'm private"
- end
- private_method
+ private
+ def #{method_signature}
+ "I'm private"
+ end
+ private_method
end
end
diff --git a/activerecord/test/cases/attributes_test.rb b/activerecord/test/cases/attributes_test.rb
index 7ec1f6f18c..c18851257e 100644
--- a/activerecord/test/cases/attributes_test.rb
+++ b/activerecord/test/cases/attributes_test.rb
@@ -249,5 +249,11 @@ module ActiveRecord
model.foo = "lol"
refute model.changed?
end
+
+ test "attributes not backed by database columns appear in inspect" do
+ inspection = OverloadedType.new.inspect
+
+ assert inspection.include?("non_existent_decimal")
+ end
end
end
diff --git a/activerecord/test/cases/autosave_association_test.rb b/activerecord/test/cases/autosave_association_test.rb
index 7eae2363f8..08df945063 100644
--- a/activerecord/test/cases/autosave_association_test.rb
+++ b/activerecord/test/cases/autosave_association_test.rb
@@ -1,5 +1,6 @@
require "cases/helper"
require "models/bird"
+require "models/post"
require "models/comment"
require "models/company"
require "models/customer"
@@ -11,7 +12,6 @@ require "models/order"
require "models/parrot"
require "models/person"
require "models/pirate"
-require "models/post"
require "models/reader"
require "models/ship"
require "models/ship_part"
diff --git a/activerecord/test/cases/enum_test.rb b/activerecord/test/cases/enum_test.rb
index c2009843f0..b7641fcf32 100644
--- a/activerecord/test/cases/enum_test.rb
+++ b/activerecord/test/cases/enum_test.rb
@@ -18,6 +18,7 @@ class EnumTest < ActiveRecord::TestCase
assert @book.author_visibility_visible?
assert @book.illustrator_visibility_visible?
assert @book.with_medium_font_size?
+ assert @book.medium_to_read?
end
test "query state with strings" do
@@ -26,6 +27,7 @@ class EnumTest < ActiveRecord::TestCase
assert_equal "english", @book.language
assert_equal "visible", @book.author_visibility
assert_equal "visible", @book.illustrator_visibility
+ assert_equal "medium", @book.difficulty
end
test "find via scope" do
@@ -34,6 +36,7 @@ class EnumTest < ActiveRecord::TestCase
assert_equal @book, Book.in_english.first
assert_equal @book, Book.author_visibility_visible.first
assert_equal @book, Book.illustrator_visibility_visible.first
+ assert_equal @book, Book.medium_to_read.first
end
test "find via where with values" do
@@ -422,6 +425,43 @@ class EnumTest < ActiveRecord::TestCase
assert_not @book.in_french?
end
+ test "query state by predicate with custom suffix" do
+ assert @book.medium_to_read?
+ assert_not @book.easy_to_read?
+ assert_not @book.hard_to_read?
+ end
+
+ test "enum methods with custom suffix defined" do
+ assert @book.class.respond_to?(:easy_to_read)
+ assert @book.class.respond_to?(:medium_to_read)
+ assert @book.class.respond_to?(:hard_to_read)
+
+ assert @book.respond_to?(:easy_to_read?)
+ assert @book.respond_to?(:medium_to_read?)
+ assert @book.respond_to?(:hard_to_read?)
+
+ assert @book.respond_to?(:easy_to_read!)
+ assert @book.respond_to?(:medium_to_read!)
+ assert @book.respond_to?(:hard_to_read!)
+ end
+
+ test "update enum attributes with custom suffix" do
+ @book.medium_to_read!
+ assert_not @book.easy_to_read?
+ assert @book.medium_to_read?
+ assert_not @book.hard_to_read?
+
+ @book.easy_to_read!
+ assert @book.easy_to_read?
+ assert_not @book.medium_to_read?
+ assert_not @book.hard_to_read?
+
+ @book.hard_to_read!
+ assert_not @book.easy_to_read?
+ assert_not @book.medium_to_read?
+ assert @book.hard_to_read?
+ end
+
test "uses default status when no status is provided in fixtures" do
book = books(:tlg)
assert book.proposed?, "expected fixture to default to proposed status"
diff --git a/activerecord/test/cases/fixtures_test.rb b/activerecord/test/cases/fixtures_test.rb
index 24a9894f19..66b230d9d2 100644
--- a/activerecord/test/cases/fixtures_test.rb
+++ b/activerecord/test/cases/fixtures_test.rb
@@ -728,7 +728,7 @@ class LoadAllFixturesTest < ActiveRecord::TestCase
self.class.fixtures :all
if File.symlink? FIXTURES_ROOT + "/all/admin"
- assert_equal %w(admin/accounts admin/users developers people tasks), fixture_table_names.sort
+ assert_equal %w(admin/accounts admin/users developers namespaced/accounts people tasks), fixture_table_names.sort
end
ensure
ActiveRecord::FixtureSet.reset_cache
@@ -741,7 +741,7 @@ class LoadAllFixturesWithPathnameTest < ActiveRecord::TestCase
self.class.fixtures :all
if File.symlink? FIXTURES_ROOT + "/all/admin"
- assert_equal %w(admin/accounts admin/users developers people tasks), fixture_table_names.sort
+ assert_equal %w(admin/accounts admin/users developers namespaced/accounts people tasks), fixture_table_names.sort
end
ensure
ActiveRecord::FixtureSet.reset_cache
diff --git a/activerecord/test/cases/migration/column_attributes_test.rb b/activerecord/test/cases/migration/column_attributes_test.rb
index ab8229dbae..03d781d3d2 100644
--- a/activerecord/test/cases/migration/column_attributes_test.rb
+++ b/activerecord/test/cases/migration/column_attributes_test.rb
@@ -63,8 +63,6 @@ module ActiveRecord
# Do a manual insertion
if current_adapter?(:OracleAdapter)
connection.execute "insert into test_models (id, wealth) values (people_seq.nextval, 12345678901234567890.0123456789)"
- elsif current_adapter?(:PostgreSQLAdapter)
- connection.execute "insert into test_models (wealth) values (12345678901234567890.0123456789)"
else
connection.execute "insert into test_models (wealth) values (12345678901234567890.0123456789)"
end
diff --git a/activerecord/test/cases/migration/columns_test.rb b/activerecord/test/cases/migration/columns_test.rb
index 70d40ed87a..870a7f4fa7 100644
--- a/activerecord/test/cases/migration/columns_test.rb
+++ b/activerecord/test/cases/migration/columns_test.rb
@@ -192,8 +192,8 @@ module ActiveRecord
new_columns = connection.columns(TestModel.table_name)
- assert_not new_columns.find { |c| c.name == "age" and c.type == :integer }
- assert new_columns.find { |c| c.name == "age" and c.type == :string }
+ assert_not new_columns.find { |c| c.name == "age" && c.type == :integer }
+ assert new_columns.find { |c| c.name == "age" && c.type == :string }
old_columns = connection.columns(TestModel.table_name)
assert old_columns.find { |c|
@@ -206,11 +206,11 @@ module ActiveRecord
assert_not new_columns.find { |c|
default = connection.lookup_cast_type_from_column(c).deserialize(c.default)
- c.name == "approved" and c.type == :boolean and default == true
+ c.name == "approved" && c.type == :boolean && default == true
}
assert new_columns.find { |c|
default = connection.lookup_cast_type_from_column(c).deserialize(c.default)
- c.name == "approved" and c.type == :boolean and default == false
+ c.name == "approved" && c.type == :boolean && default == false
}
change_column :test_models, :approved, :boolean, default: true
end
diff --git a/activerecord/test/cases/quoting_test.rb b/activerecord/test/cases/quoting_test.rb
index 1c276aa765..296dafacc2 100644
--- a/activerecord/test/cases/quoting_test.rb
+++ b/activerecord/test/cases/quoting_test.rb
@@ -133,16 +133,12 @@ module ActiveRecord
end
def test_quote_string_no_column
- assert_equal "'lo\\\\l'", @quoter.quote('lo\l', nil)
+ assert_equal "'lo\\\\l'", @quoter.quote('lo\l')
end
def test_quote_as_mb_chars_no_column
string = ActiveSupport::Multibyte::Chars.new('lo\l')
- assert_equal "'lo\\\\l'", @quoter.quote(string, nil)
- end
-
- def test_string_with_crazy_column
- assert_equal "'lo\\\\l'", @quoter.quote('lo\l')
+ assert_equal "'lo\\\\l'", @quoter.quote(string)
end
def test_quote_duration
diff --git a/activerecord/test/cases/relation/where_test.rb b/activerecord/test/cases/relation/where_test.rb
index ce4e041793..925af49ffe 100644
--- a/activerecord/test/cases/relation/where_test.rb
+++ b/activerecord/test/cases/relation/where_test.rb
@@ -4,10 +4,10 @@ require "models/binary"
require "models/cake_designer"
require "models/car"
require "models/chef"
+require "models/post"
require "models/comment"
require "models/edge"
require "models/essay"
-require "models/post"
require "models/price_estimate"
require "models/topic"
require "models/treasure"
diff --git a/activerecord/test/cases/relation_test.rb b/activerecord/test/cases/relation_test.rb
index 32b8781a6b..23d27ab90a 100644
--- a/activerecord/test/cases/relation_test.rb
+++ b/activerecord/test/cases/relation_test.rb
@@ -310,10 +310,10 @@ module ActiveRecord
def skip_if_sqlite3_version_includes_quoting_bug
if sqlite3_version_includes_quoting_bug?
skip <<-ERROR.squish
- You are using an outdated version of SQLite3 which has a bug in
- quoted column names. Please update SQLite3 and rebuild the sqlite3
- ruby gem
- ERROR
+ You are using an outdated version of SQLite3 which has a bug in
+ quoted column names. Please update SQLite3 and rebuild the sqlite3
+ ruby gem
+ ERROR
end
end
diff --git a/activerecord/test/cases/view_test.rb b/activerecord/test/cases/view_test.rb
index aa3ff6160c..3cbfbc22c6 100644
--- a/activerecord/test/cases/view_test.rb
+++ b/activerecord/test/cases/view_test.rb
@@ -100,9 +100,9 @@ if ActiveRecord::Base.connection.supports_views?
setup do
@connection = ActiveRecord::Base.connection
@connection.execute <<-SQL
- CREATE VIEW paperbacks
- AS SELECT name, status FROM books WHERE format = 'paperback'
- SQL
+ CREATE VIEW paperbacks
+ AS SELECT name, status FROM books WHERE format = 'paperback'
+ SQL
end
teardown do
@@ -162,9 +162,9 @@ if ActiveRecord::Base.connection.supports_views?
setup do
@connection = ActiveRecord::Base.connection
@connection.execute <<-SQL
- CREATE VIEW printed_books
- AS SELECT id, name, status, format FROM books WHERE format = 'paperback'
- SQL
+ CREATE VIEW printed_books
+ AS SELECT id, name, status, format FROM books WHERE format = 'paperback'
+ SQL
end
teardown do
diff --git a/activerecord/test/fixtures/all/namespaced/accounts.yml b/activerecord/test/fixtures/all/namespaced/accounts.yml
new file mode 100644
index 0000000000..9e341a15af
--- /dev/null
+++ b/activerecord/test/fixtures/all/namespaced/accounts.yml
@@ -0,0 +1,2 @@
+signals37:
+ name: 37signals
diff --git a/activerecord/test/fixtures/books.yml b/activerecord/test/fixtures/books.yml
index a304fba399..b3625ee72e 100644
--- a/activerecord/test/fixtures/books.yml
+++ b/activerecord/test/fixtures/books.yml
@@ -9,6 +9,7 @@ awdr:
author_visibility: :visible
illustrator_visibility: :visible
font_size: :medium
+ difficulty: :medium
rfr:
author_id: 1
diff --git a/activerecord/test/models/book.rb b/activerecord/test/models/book.rb
index 4c275fdebb..17bf3fbcb4 100644
--- a/activerecord/test/models/book.rb
+++ b/activerecord/test/models/book.rb
@@ -14,6 +14,7 @@ class Book < ActiveRecord::Base
enum author_visibility: [:visible, :invisible], _prefix: true
enum illustrator_visibility: [:visible, :invisible], _prefix: true
enum font_size: [:small, :medium, :large], _prefix: :with, _suffix: true
+ enum difficulty: [:easy, :medium, :hard], _suffix: :to_read
enum cover: { hard: "hard", soft: "soft" }
def published!
diff --git a/activerecord/test/schema/schema.rb b/activerecord/test/schema/schema.rb
index 9997ddee77..a4756ec75a 100644
--- a/activerecord/test/schema/schema.rb
+++ b/activerecord/test/schema/schema.rb
@@ -98,6 +98,7 @@ ActiveRecord::Schema.define do
t.column :author_visibility, :integer, default: 0
t.column :illustrator_visibility, :integer, default: 0
t.column :font_size, :integer, default: 0
+ t.column :difficulty, :integer, default: 0
t.column :cover, :string, default: "hard"
end
diff --git a/activesupport/Rakefile b/activesupport/Rakefile
index 54d7a5c6f3..2e1c50cc3d 100644
--- a/activesupport/Rakefile
+++ b/activesupport/Rakefile
@@ -16,6 +16,6 @@ namespace :test do
task :isolated do
Dir.glob("test/**/*_test.rb").all? do |file|
sh(Gem.ruby, "-w", "-Ilib:test", file)
- end or raise "Failures"
+ end || raise("Failures")
end
end
diff --git a/activesupport/bin/generate_tables b/activesupport/bin/generate_tables
index 06dcff4e87..ef220e0329 100755
--- a/activesupport/bin/generate_tables
+++ b/activesupport/bin/generate_tables
@@ -84,7 +84,7 @@ module ActiveSupport
def create_composition_map
@ucd.codepoints.each do |_, cp|
- if !cp.nil? and cp.combining_class == 0 and cp.decomp_type.nil? and !cp.decomp_mapping.nil? and cp.decomp_mapping.length == 2 and @ucd.codepoints[cp.decomp_mapping[0]].combining_class == 0 and !@ucd.composition_exclusion.include?(cp.code)
+ if !cp.nil? && cp.combining_class == 0 && cp.decomp_type.nil? && !cp.decomp_mapping.nil? && cp.decomp_mapping.length == 2 && @ucd.codepoints[cp.decomp_mapping[0]].combining_class == 0 && !@ucd.composition_exclusion.include?(cp.code)
@ucd.composition_map[cp.decomp_mapping[0]] ||= {}
@ucd.composition_map[cp.decomp_mapping[0]][cp.decomp_mapping[1]] = cp.code
end
diff --git a/activesupport/lib/active_support/backtrace_cleaner.rb b/activesupport/lib/active_support/backtrace_cleaner.rb
index e161ec4cca..169a58ecd1 100644
--- a/activesupport/lib/active_support/backtrace_cleaner.rb
+++ b/activesupport/lib/active_support/backtrace_cleaner.rb
@@ -14,7 +14,7 @@ module ActiveSupport
#
# bc = BacktraceCleaner.new
# bc.add_filter { |line| line.gsub(Rails.root.to_s, '') } # strip the Rails.root prefix
- # bc.add_silencer { |line| line =~ /mongrel|rubygems/ } # skip any lines from mongrel or rubygems
+ # bc.add_silencer { |line| line =~ /puma|rubygems/ } # skip any lines from puma or rubygems
# bc.clean(exception.backtrace) # perform the cleanup
#
# To reconfigure an existing BacktraceCleaner (like the default one in Rails)
@@ -59,8 +59,8 @@ module ActiveSupport
# Adds a silencer from the block provided. If the silencer returns +true+
# for a given line, it will be excluded from the clean backtrace.
#
- # # Will reject all lines that include the word "mongrel", like "/gems/mongrel/server.rb" or "/app/my_mongrel_server/rb"
- # backtrace_cleaner.add_silencer { |line| line =~ /mongrel/ }
+ # # Will reject all lines that include the word "puma", like "/gems/puma/server.rb" or "/app/my_puma_server/rb"
+ # backtrace_cleaner.add_silencer { |line| line =~ /puma/ }
def add_silencer(&block)
@silencers << block
end
diff --git a/activesupport/lib/active_support/cache/memory_store.rb b/activesupport/lib/active_support/cache/memory_store.rb
index dbe55d7ce1..1a8477f9fe 100644
--- a/activesupport/lib/active_support/cache/memory_store.rb
+++ b/activesupport/lib/active_support/cache/memory_store.rb
@@ -4,7 +4,7 @@ module ActiveSupport
module Cache
# A cache store implementation which stores everything into memory in the
# same process. If you're running multiple Ruby on Rails server processes
- # (which is the case if you're using mongrel_cluster or Phusion Passenger),
+ # (which is the case if you're using Phusion Passenger or puma clustered mode),
# then this means that Rails server process instances won't be able
# to share cache data with each other and this may not be the most
# appropriate cache in that scenario.
diff --git a/activesupport/lib/active_support/callbacks.rb b/activesupport/lib/active_support/callbacks.rb
index a33cab0504..ecf0c0eec7 100644
--- a/activesupport/lib/active_support/callbacks.rb
+++ b/activesupport/lib/active_support/callbacks.rb
@@ -297,9 +297,9 @@ module ActiveSupport
def self.build(chain, filter, kind, options)
if filter.is_a?(String)
ActiveSupport::Deprecation.warn(<<-MSG.squish)
- Passing string to define callback is deprecated and will be removed
- in Rails 5.1 without replacement.
- MSG
+ Passing string to define callback is deprecated and will be removed
+ in Rails 5.1 without replacement.
+ MSG
end
new chain.name, filter, kind, options, chain.config
@@ -751,10 +751,10 @@ module ActiveSupport
set_callbacks name, CallbackChain.new(name, options)
module_eval <<-RUBY, __FILE__, __LINE__ + 1
- def _run_#{name}_callbacks(&block)
- __run_callbacks__(_#{name}_callbacks, &block)
- end
- RUBY
+ def _run_#{name}_callbacks(&block)
+ __run_callbacks__(_#{name}_callbacks, &block)
+ end
+ RUBY
end
end
@@ -787,9 +787,9 @@ module ActiveSupport
def display_deprecation_warning_for_false_terminator
ActiveSupport::Deprecation.warn(<<-MSG.squish)
- Returning `false` in Active Record and Active Model callbacks will not implicitly halt a callback chain in Rails 5.1.
- To explicitly halt the callback chain, please use `throw :abort` instead.
- MSG
+ Returning `false` in Active Record and Active Model callbacks will not implicitly halt a callback chain in Rails 5.1.
+ To explicitly halt the callback chain, please use `throw :abort` instead.
+ MSG
end
end
end
diff --git a/activesupport/lib/active_support/core_ext/class/subclasses.rb b/activesupport/lib/active_support/core_ext/class/subclasses.rb
index 8a21c71a42..10a7c787f6 100644
--- a/activesupport/lib/active_support/core_ext/class/subclasses.rb
+++ b/activesupport/lib/active_support/core_ext/class/subclasses.rb
@@ -6,7 +6,20 @@ class Class
# Test if this Ruby supports each_object against singleton_class
ObjectSpace.each_object(Numeric.singleton_class) {}
- def descendants # :nodoc:
+ # Returns an array with all classes that are < than its receiver.
+ #
+ # class C; end
+ # C.descendants # => []
+ #
+ # class B < C; end
+ # C.descendants # => [B]
+ #
+ # class A < B; end
+ # C.descendants # => [B, A]
+ #
+ # class D < C; end
+ # C.descendants # => [B, A, D]
+ def descendants
descendants = []
ObjectSpace.each_object(singleton_class) do |k|
descendants.unshift k unless k == self
@@ -14,7 +27,7 @@ class Class
descendants
end
rescue StandardError # JRuby 9.0.4.0 and earlier
- def descendants # :nodoc:
+ def descendants
descendants = []
ObjectSpace.each_object(Class) do |k|
descendants.unshift k if k < self
diff --git a/activesupport/lib/active_support/dependencies.rb b/activesupport/lib/active_support/dependencies.rb
index 158bb402bd..216d52164e 100644
--- a/activesupport/lib/active_support/dependencies.rb
+++ b/activesupport/lib/active_support/dependencies.rb
@@ -371,7 +371,7 @@ module ActiveSupport #:nodoc:
load_args = ["#{file_name}.rb"]
load_args << const_path unless const_path.nil?
- if !warnings_on_first_load or history.include?(expanded)
+ if !warnings_on_first_load || history.include?(expanded)
result = load_file(*load_args)
else
enable_warnings { result = load_file(*load_args) }
diff --git a/activesupport/lib/active_support/i18n_railtie.rb b/activesupport/lib/active_support/i18n_railtie.rb
index 4749147ef4..08c9ef8f02 100644
--- a/activesupport/lib/active_support/i18n_railtie.rb
+++ b/activesupport/lib/active_support/i18n_railtie.rb
@@ -83,14 +83,15 @@ module I18n
def self.init_fallbacks(fallbacks)
include_fallbacks_module
- args = case fallbacks
- when ActiveSupport::OrderedOptions
- [*(fallbacks[:defaults] || []) << fallbacks[:map]].compact
- when Hash, Array
- Array.wrap(fallbacks)
- else # TrueClass
- []
- end
+ args = \
+ case fallbacks
+ when ActiveSupport::OrderedOptions
+ [*(fallbacks[:defaults] || []) << fallbacks[:map]].compact
+ when Hash, Array
+ Array.wrap(fallbacks)
+ else # TrueClass
+ []
+ end
I18n.fallbacks = I18n::Locale::Fallbacks.new(*args)
end
diff --git a/activesupport/lib/active_support/message_encryptor.rb b/activesupport/lib/active_support/message_encryptor.rb
index ab8b2f8ded..7b33dc3481 100644
--- a/activesupport/lib/active_support/message_encryptor.rb
+++ b/activesupport/lib/active_support/message_encryptor.rb
@@ -19,6 +19,8 @@ module ActiveSupport
# encrypted_data = crypt.encrypt_and_sign('my secret data') # => "NlFBTTMwOUV5UlA1QlNEN2xkY2d6eThYWWh..."
# crypt.decrypt_and_verify(encrypted_data) # => "my secret data"
class MessageEncryptor
+ DEFAULT_CIPHER = "aes-256-cbc"
+
module NullSerializer #:nodoc:
def self.load(value)
value
@@ -77,6 +79,11 @@ module ActiveSupport
_decrypt(verifier.verify(value))
end
+ # Given a cipher, returns the key length of the cipher to help generate the key of desired size
+ def self.key_len(cipher = DEFAULT_CIPHER)
+ OpenSSL::Cipher.new(cipher).key_len
+ end
+
private
def _encrypt(value)
diff --git a/activesupport/lib/active_support/multibyte/unicode.rb b/activesupport/lib/active_support/multibyte/unicode.rb
index ee657080b2..2159abef14 100644
--- a/activesupport/lib/active_support/multibyte/unicode.rb
+++ b/activesupport/lib/active_support/multibyte/unicode.rb
@@ -89,25 +89,25 @@ module ActiveSupport
should_break =
# GB3. CR X LF
- if previous == database.boundary[:cr] and current == database.boundary[:lf]
+ if previous == database.boundary[:cr] && current == database.boundary[:lf]
false
# GB4. (Control|CR|LF) ÷
- elsif previous and in_char_class?(previous, [:control,:cr,:lf])
+ elsif previous && in_char_class?(previous, [:control,:cr,:lf])
true
# GB5. ÷ (Control|CR|LF)
elsif in_char_class?(current, [:control,:cr,:lf])
true
# GB6. L X (L|V|LV|LVT)
- elsif database.boundary[:l] === previous and in_char_class?(current, [:l,:v,:lv,:lvt])
+ elsif database.boundary[:l] === previous && in_char_class?(current, [:l,:v,:lv,:lvt])
false
# GB7. (LV|V) X (V|T)
- elsif in_char_class?(previous, [:lv,:v]) and in_char_class?(current, [:v,:t])
+ elsif in_char_class?(previous, [:lv,:v]) && in_char_class?(current, [:v,:t])
false
# GB8. (LVT|T) X (T)
- elsif in_char_class?(previous, [:lvt,:t]) and database.boundary[:t] === current
+ elsif in_char_class?(previous, [:lvt,:t]) && database.boundary[:t] === current
false
# GB8a. Regional_Indicator X Regional_Indicator
- elsif database.boundary[:regional_indicator] === previous and database.boundary[:regional_indicator] === current
+ elsif database.boundary[:regional_indicator] === previous && database.boundary[:regional_indicator] === current
false
# GB9. X Extend
elsif database.boundary[:extend] === current
@@ -158,7 +158,7 @@ module ActiveSupport
def decompose(type, codepoints)
codepoints.inject([]) do |decomposed, cp|
# if it's a hangul syllable starter character
- if HANGUL_SBASE <= cp and cp < HANGUL_SLAST
+ if HANGUL_SBASE <= cp && cp < HANGUL_SLAST
sindex = cp - HANGUL_SBASE
ncp = [] # new codepoints
ncp << HANGUL_LBASE + sindex / HANGUL_NCOUNT
@@ -167,7 +167,7 @@ module ActiveSupport
ncp << (HANGUL_TBASE + tindex) unless tindex == 0
decomposed.concat ncp
# if the codepoint is decomposable in with the current decomposition type
- elsif (ncp = database.codepoints[cp].decomp_mapping) and (!database.codepoints[cp].decomp_type || type == :compatibility)
+ elsif (ncp = database.codepoints[cp].decomp_mapping) && (!database.codepoints[cp].decomp_type || type == :compatibility)
decomposed.concat decompose(type, ncp.dup)
else
decomposed << cp
@@ -186,11 +186,11 @@ module ActiveSupport
pos += 1
lindex = starter_char - HANGUL_LBASE
# -- Hangul
- if 0 <= lindex and lindex < HANGUL_LCOUNT
+ if 0 <= lindex && lindex < HANGUL_LCOUNT
vindex = codepoints[starter_pos+1] - HANGUL_VBASE rescue vindex = -1
- if 0 <= vindex and vindex < HANGUL_VCOUNT
+ if 0 <= vindex && vindex < HANGUL_VCOUNT
tindex = codepoints[starter_pos+2] - HANGUL_TBASE rescue tindex = -1
- if 0 <= tindex and tindex < HANGUL_TCOUNT
+ if 0 <= tindex && tindex < HANGUL_TCOUNT
j = starter_pos + 2
eoa -= 2
else
@@ -392,7 +392,7 @@ module ActiveSupport
database.codepoints
string.each_codepoint.map do |codepoint|
cp = database.codepoints[codepoint]
- if cp and (ncp = cp.send(mapping)) and ncp > 0
+ if cp && (ncp = cp.send(mapping)) && ncp > 0
ncp
else
codepoint
diff --git a/activesupport/lib/active_support/notifications/fanout.rb b/activesupport/lib/active_support/notifications/fanout.rb
index 055ff6e211..9da115f552 100644
--- a/activesupport/lib/active_support/notifications/fanout.rb
+++ b/activesupport/lib/active_support/notifications/fanout.rb
@@ -68,7 +68,7 @@ module ActiveSupport
module Subscribers # :nodoc:
def self.new(pattern, listener)
- if listener.respond_to?(:start) and listener.respond_to?(:finish)
+ if listener.respond_to?(:start) && listener.respond_to?(:finish)
subscriber = Evented.new pattern, listener
else
subscriber = Timed.new pattern, listener
diff --git a/activesupport/lib/active_support/testing/assertions.rb b/activesupport/lib/active_support/testing/assertions.rb
index 8c9ea2c0e8..28cf2953bf 100644
--- a/activesupport/lib/active_support/testing/assertions.rb
+++ b/activesupport/lib/active_support/testing/assertions.rb
@@ -159,7 +159,7 @@ module ActiveSupport
error = "#{message}.\n#{error}" if message
assert_not_equal before, after, error
else
- message = "#{expression.inspect} didn't change to #{to}"
+ error = "#{expression.inspect} didn't change to #{to}"
error = "#{message}.\n#{error}" if message
assert to === after, error
end
diff --git a/activesupport/lib/active_support/time_with_zone.rb b/activesupport/lib/active_support/time_with_zone.rb
index 9d1147620c..be2fceb123 100644
--- a/activesupport/lib/active_support/time_with_zone.rb
+++ b/activesupport/lib/active_support/time_with_zone.rb
@@ -80,7 +80,7 @@ module ActiveSupport
# Returns a <tt>Time</tt> instance of the simultaneous time in the system timezone.
def localtime(utc_offset = nil)
- utc.getlocal(utc_offset)
+ @localtime ||= utc.getlocal(utc_offset)
end
alias_method :getlocal, :localtime
@@ -406,7 +406,7 @@ module ActiveSupport
# Time.zone.now.to_datetime # => Tue, 18 Aug 2015 02:32:20 +0000
# Time.current.in_time_zone('Hawaii').to_datetime # => Mon, 17 Aug 2015 16:32:20 -1000
def to_datetime
- utc.to_datetime.new_offset(Rational(utc_offset, 86_400))
+ @to_datetime ||= utc.to_datetime.new_offset(Rational(utc_offset, 86_400))
end
# So that +self+ <tt>acts_like?(:time)</tt>.
diff --git a/activesupport/test/core_ext/duration_test.rb b/activesupport/test/core_ext/duration_test.rb
index 1a2dcba760..a881768470 100644
--- a/activesupport/test/core_ext/duration_test.rb
+++ b/activesupport/test/core_ext/duration_test.rb
@@ -208,7 +208,11 @@ class DurationTest < ActiveSupport::TestCase
end
def test_case_when
- cased = case 1.day when 1.day then "ok" end
+ cased = \
+ case 1.day
+ when 1.day
+ "ok"
+ end
assert_equal cased, "ok"
end
diff --git a/activesupport/test/message_encryptor_test.rb b/activesupport/test/message_encryptor_test.rb
index fb0b1e377d..f8282c89ca 100644
--- a/activesupport/test/message_encryptor_test.rb
+++ b/activesupport/test/message_encryptor_test.rb
@@ -48,6 +48,16 @@ class MessageEncryptorTest < ActiveSupport::TestCase
assert_equal @data, @encryptor.decrypt_and_verify(message)
end
+ def test_backwards_compat_for_64_bytes_key
+ # 64 bit key
+ secret = ["3942b1bf81e622559ed509e3ff274a780784fe9e75b065866bd270438c74da822219de3156473cc27df1fd590e4baf68c95eeb537b6e4d4c5a10f41635b5597e"].pack("H*")
+ # Encryptor with 32 bit key, 64 bit secret for verifier
+ encryptor = ActiveSupport::MessageEncryptor.new(secret[0..31], secret)
+ # Message generated with 64 bit key
+ message = "eHdGeExnZEwvMSt3U3dKaFl1WFo0TjVvYzA0eGpjbm5WSkt5MXlsNzhpZ0ZnbWhBWFlQZTRwaXE1bVJCS2oxMDZhYVp2dVN3V0lNZUlWQ3c2eVhQbnhnVjFmeVVubmhRKzF3WnZyWHVNMDg9LS1HSisyakJVSFlPb05ISzRMaXRzcFdBPT0=--831a1d54a3cda8a0658dc668a03dedcbce13b5ca"
+ assert_equal "data", encryptor.decrypt_and_verify(message)[:some]
+ end
+
def test_alternative_serialization_method
prev = ActiveSupport.use_standard_json_time_format
ActiveSupport.use_standard_json_time_format = true
diff --git a/activesupport/test/multibyte_grapheme_break_conformance_test.rb b/activesupport/test/multibyte_grapheme_break_conformance_test.rb
index 5dc42df08d..04a7d290d9 100644
--- a/activesupport/test/multibyte_grapheme_break_conformance_test.rb
+++ b/activesupport/test/multibyte_grapheme_break_conformance_test.rb
@@ -33,7 +33,7 @@ class MultibyteGraphemeBreakConformanceTest < ActiveSupport::TestCase
lines = 0
max_test_lines = 0 # Don't limit below 21, because that's the header of the testfile
File.open(File.join(CACHE_DIR, UNIDATA_FILE), "r") do | f |
- until f.eof? || (max_test_lines > 21 and lines > max_test_lines)
+ until f.eof? || (max_test_lines > 21 && lines > max_test_lines)
lines += 1
line = f.gets.chomp!
next if line.empty? || line.start_with?("#")
diff --git a/activesupport/test/multibyte_normalization_conformance_test.rb b/activesupport/test/multibyte_normalization_conformance_test.rb
index 716e6487aa..e013bd578f 100644
--- a/activesupport/test/multibyte_normalization_conformance_test.rb
+++ b/activesupport/test/multibyte_normalization_conformance_test.rb
@@ -88,7 +88,7 @@ class MultibyteNormalizationConformanceTest < ActiveSupport::TestCase
lines = 0
max_test_lines = 0 # Don't limit below 38, because that's the header of the testfile
File.open(File.join(CACHE_DIR, UNIDATA_FILE), "r") do | f |
- until f.eof? || (max_test_lines > 38 and lines > max_test_lines)
+ until f.eof? || (max_test_lines > 38 && lines > max_test_lines)
lines += 1
line = f.gets.chomp!
next if line.empty? || line.start_with?("#")
diff --git a/activesupport/test/test_case_test.rb b/activesupport/test/test_case_test.rb
index dfbb8aa41d..d769a8c145 100644
--- a/activesupport/test/test_case_test.rb
+++ b/activesupport/test/test_case_test.rb
@@ -211,6 +211,15 @@ class AssertDifferenceTest < ActiveSupport::TestCase
end
end
+ def test_assert_changes_with_message
+ error = assert_raises Minitest::Assertion do
+ assert_changes "@object.num", "@object.num should 1", to: 1 do
+ end
+ end
+
+ assert_equal "@object.num should 1.\n\"@object.num\" didn't change to 1", error.message
+ end
+
def test_assert_no_changes_pass
assert_no_changes "@object.num" do
# ...
diff --git a/activesupport/test/xml_mini/jdom_engine_test.rb b/activesupport/test/xml_mini/jdom_engine_test.rb
index a776ad25c4..816d57972c 100644
--- a/activesupport/test/xml_mini/jdom_engine_test.rb
+++ b/activesupport/test/xml_mini/jdom_engine_test.rb
@@ -180,7 +180,4 @@ if RUBY_PLATFORM.include?("java")
assert_equal(hash, parsed_xml)
end
end
-
-else
- # don't run these test because we aren't running in JRuby
end
diff --git a/guides/assets/stylesheets/main.css b/guides/assets/stylesheets/main.css
index ed558e4793..b56699a0d0 100644
--- a/guides/assets/stylesheets/main.css
+++ b/guides/assets/stylesheets/main.css
@@ -16,7 +16,6 @@
.large {font-size: larger;}
.hide {display: none;}
-li ul, li ol { margin:0 1.5em; }
ul, ol { margin: 0 1.5em 1.5em 1.5em; }
ul { list-style-type: disc; }
@@ -602,6 +601,8 @@ h6 {
font-weight: normal;
}
+#subCol li ul, li ol { margin:0 1.5em; }
+
div.code_container {
background: #EEE url(../images/tab_grey.gif) no-repeat left top;
padding: 0.25em 1em 0.5em 48px;
diff --git a/guides/bug_report_templates/active_job_gem.rb b/guides/bug_report_templates/active_job_gem.rb
new file mode 100644
index 0000000000..debc46ad54
--- /dev/null
+++ b/guides/bug_report_templates/active_job_gem.rb
@@ -0,0 +1,32 @@
+begin
+ require "bundler/inline"
+rescue LoadError => e
+ $stderr.puts "Bundler version 1.10 or later is required. Please update your Bundler"
+ raise e
+end
+
+gemfile(true) do
+ source "https://rubygems.org"
+ # Activate the gem you are reporting the issue against.
+ gem "activejob", "5.0.0"
+end
+
+require "minitest/autorun"
+require "active_job"
+
+# Ensure backward compatibility with Minitest 4
+Minitest::Test = MiniTest::Unit::TestCase unless defined?(Minitest::Test)
+
+class BuggyJob < ActiveJob::Base
+ def perform
+ puts "performed"
+ end
+end
+
+class BuggyJobTest < ActiveJob::TestCase
+ def test_stuff
+ assert_enqueued_with(job: BuggyJob) do
+ BuggyJob.perform_later
+ end
+ end
+end
diff --git a/guides/bug_report_templates/active_job_master.rb b/guides/bug_report_templates/active_job_master.rb
new file mode 100644
index 0000000000..f61518713f
--- /dev/null
+++ b/guides/bug_report_templates/active_job_master.rb
@@ -0,0 +1,31 @@
+begin
+ require "bundler/inline"
+rescue LoadError => e
+ $stderr.puts "Bundler version 1.10 or later is required. Please update your Bundler"
+ raise e
+end
+
+gemfile(true) do
+ source "https://rubygems.org"
+ gem "rails", github: "rails/rails"
+end
+
+require "active_job"
+require "minitest/autorun"
+
+# Ensure backward compatibility with Minitest 4
+Minitest::Test = MiniTest::Unit::TestCase unless defined?(Minitest::Test)
+
+class BuggyJob < ActiveJob::Base
+ def perform
+ puts "performed"
+ end
+end
+
+class BuggyJobTest < ActiveJob::TestCase
+ def test_stuff
+ assert_enqueued_with(job: BuggyJob) do
+ BuggyJob.perform_later
+ end
+ end
+end
diff --git a/guides/rails_guides/levenshtein.rb b/guides/rails_guides/levenshtein.rb
index a3e7620444..e947150364 100644
--- a/guides/rails_guides/levenshtein.rb
+++ b/guides/rails_guides/levenshtein.rb
@@ -1,6 +1,8 @@
module RailsGuides
module Levenshtein
- # This code is based directly on the Text gem implementation
+ # This code is based directly on the Text gem implementation.
+ # Copyright (c) 2006-2013 Paul Battley, Michael Neumann, Tim Fletcher.
+ #
# Returns a value representing the "cost" of transforming str1 into str2
def self.distance(str1, str2)
s = str1
diff --git a/guides/rails_guides/markdown/renderer.rb b/guides/rails_guides/markdown/renderer.rb
index 4ff76c519b..f8e32fc498 100644
--- a/guides/rails_guides/markdown/renderer.rb
+++ b/guides/rails_guides/markdown/renderer.rb
@@ -67,14 +67,15 @@ HTML
# as a list item, but as a paragraph starting with a plain
# asterisk.
body.gsub(/^(TIP|IMPORTANT|CAUTION|WARNING|NOTE|INFO|TODO)[.:](.*?)(\n(?=\n)|\Z)/m) do
- css_class = case $1
- when "CAUTION", "IMPORTANT"
- "warning"
- when "TIP"
- "info"
- else
- $1.downcase
- end
+ css_class = \
+ case $1
+ when "CAUTION", "IMPORTANT"
+ "warning"
+ when "TIP"
+ "info"
+ else
+ $1.downcase
+ end
%(<div class="#{css_class}"><p>#{$2.strip}</p></div>)
end
end
diff --git a/guides/source/5_0_release_notes.md b/guides/source/5_0_release_notes.md
index 9c5ffb1d94..6538629972 100644
--- a/guides/source/5_0_release_notes.md
+++ b/guides/source/5_0_release_notes.md
@@ -797,6 +797,14 @@ Please refer to the [Changelog][active-record] for detailed changes.
than the current time.
([Pull Request](https://github.com/rails/rails/pull/18956))
+* Change transaction callbacks to not swallow errors.
+ Before this change any errors raised inside a transaction callback
+ were getting rescued and printed in the logs, unless you used
+ the (newly deprecated) `raise_in_transactional_callbacks = true` option.
+
+ Now these errors are not rescued anymore and just bubble up, as the other callbacks.
+ ([commit](https://github.com/rails/rails/commit/07d3d402341e81ada0214f2cb2be1da69eadfe72))
+
Active Model
------------
diff --git a/guides/source/action_view_overview.md b/guides/source/action_view_overview.md
index e11466e79f..ff0127522b 100644
--- a/guides/source/action_view_overview.md
+++ b/guides/source/action_view_overview.md
@@ -254,12 +254,6 @@ as if we had written:
<%= render partial: "product", locals: { product: @product } %>
```
-With the `as` option we can specify a different name for the local variable. For example, if we wanted it to be `item` instead of `product` we would do:
-
-```erb
-<%= render partial: "product", as: "item" %>
-```
-
The `object` option can be used to directly specify which object is rendered into the partial; useful when the template's object is elsewhere (e.g. in a different instance variable or in a local variable).
For example, instead of:
@@ -274,12 +268,18 @@ we would do:
<%= render partial: "product", object: @item %>
```
-The `object` and `as` options can also be used together:
+With the `as` option we can specify a different name for the said local variable. For example, if we wanted it to be `item` instead of `product` we would do:
```erb
<%= render partial: "product", object: @item, as: "item" %>
```
+This is equivalent to
+
+```erb
+<%= render partial: "product", locals: { item: @item } %>
+```
+
#### Rendering Collections
It is very common that a template will need to iterate over a collection and render a sub-template for each of the elements. This pattern has been implemented as a single method that accepts an array and renders a partial for each one of the elements in the array.
diff --git a/guides/source/active_record_callbacks.md b/guides/source/active_record_callbacks.md
index a7975c7772..2a1c960887 100644
--- a/guides/source/active_record_callbacks.md
+++ b/guides/source/active_record_callbacks.md
@@ -431,4 +431,4 @@ class PictureFile < ApplicationRecord
end
```
-WARNING. The `after_commit` and `after_rollback` callbacks are guaranteed to be called for all models created, updated, or destroyed within a transaction block. If any exceptions are raised within one of these callbacks, they will be ignored so that they don't interfere with the other callbacks. As such, if your callback code could raise an exception, you'll need to rescue it and handle it appropriately within the callback.
+WARNING. The `after_commit` and `after_rollback` callbacks are called for all models created, updated, or destroyed within a transaction block. However, if an exception is raised within one of these callbacks, the exception will bubble up and any remaining `after_commit` or `after_rollback` methods will _not_ be executed. As such, if your callback code could raise an exception, you'll need to rescue it and handle it within the callback in order to allow other callbacks to run.
diff --git a/guides/source/active_record_querying.md b/guides/source/active_record_querying.md
index 493fd526fb..644756906a 100644
--- a/guides/source/active_record_querying.md
+++ b/guides/source/active_record_querying.md
@@ -1020,7 +1020,7 @@ Author.joins("INNER JOIN posts ON posts.author_id = authors.id AND posts.publish
This will result in the following SQL:
```sql
-SELECT clients.* FROM clients INNER JOIN posts ON posts.author_id = authors.id AND posts.published = 't'
+SELECT authors.* FROM authors INNER JOIN posts ON posts.author_id = authors.id AND posts.published = 't'
```
#### Using Array/Hash of Named Associations
diff --git a/guides/source/active_support_core_extensions.md b/guides/source/active_support_core_extensions.md
index aba4c6a97b..60a6c37f82 100644
--- a/guides/source/active_support_core_extensions.md
+++ b/guides/source/active_support_core_extensions.md
@@ -2036,7 +2036,7 @@ Addition only assumes the elements respond to `+`:
```ruby
[[1, 2], [2, 3], [3, 4]].sum # => [1, 2, 2, 3, 3, 4]
%w(foo bar baz).sum # => "foobarbaz"
-{a: 1, b: 2, c: 3}.sum # => [:b, 2, :c, 3, :a, 1]
+{a: 1, b: 2, c: 3}.sum # => [:b, 2, :c, 3, :a, 1]
```
The sum of an empty collection is zero by default, but this is customizable:
diff --git a/guides/source/asset_pipeline.md b/guides/source/asset_pipeline.md
index 701304acde..41dfeea84d 100644
--- a/guides/source/asset_pipeline.md
+++ b/guides/source/asset_pipeline.md
@@ -586,6 +586,19 @@ in your application are included in the `config.assets.precompile` list.
If `config.assets.digest` is also true, the asset pipeline will require that
all requests for assets include digests.
+### Raise an Error When an Asset is Not Found
+
+If you are using sprockets-rails >= 3.2.0 you can configure what happens
+when an asset lookup is performed and nothing is found. If you turn off "asset fallback"
+then an error will be raised when an asset cannot be found.
+
+```ruby
+config.assets.unknown_asset_fallback = false
+```
+
+If "asset fallback" is enabled then when an asset cannot be found the path will be
+output instead and no error raised. The asset fallback behavior is enabled by default.
+
### Turning Digests Off
You can turn off digests by updating `config/environments/development.rb` to
diff --git a/guides/source/association_basics.md b/guides/source/association_basics.md
index 3993fdb1dd..3837cda553 100644
--- a/guides/source/association_basics.md
+++ b/guides/source/association_basics.md
@@ -387,7 +387,7 @@ The corresponding migration might look like this:
class CreateSuppliers < ActiveRecord::Migration[5.0]
def change
create_table :suppliers do |t|
- t.string :name
+ t.string :name
t.timestamps
end
@@ -550,8 +550,8 @@ But what if you want to reload the cache, because data might have been changed b
```ruby
author.books # retrieves books from the database
author.books.size # uses the cached copy of books
-author.books.reload.empty? # discards the cached copy of books
- # and goes back to the database
+author.books.reload.empty? # discards the cached copy of books
+ # and goes back to the database
```
### Avoiding Name Collisions
@@ -1007,7 +1007,7 @@ class Author < ApplicationRecord
end
```
-In this case, saving or destroying an book will update the timestamp on the associated author. You can also specify a particular timestamp attribute to update:
+In this case, saving or destroying a book will update the timestamp on the associated author. You can also specify a particular timestamp attribute to update:
```ruby
class Book < ApplicationRecord
@@ -1841,7 +1841,7 @@ article = Article.create(name: 'a1')
person.articles << article
person.articles << article
person.articles.inspect # => [#<Article id: 5, name: "a1">, #<Article id: 5, name: "a1">]
-Reading.all.inspect # => [#<Reading id: 12, person_id: 5, article_id: 5>, #<Reading id: 13, person_id: 5, article_id: 5>]
+Reading.all.inspect # => [#<Reading id: 12, person_id: 5, article_id: 5>, #<Reading id: 13, person_id: 5, article_id: 5>]
```
In the above case there are two readings and `person.articles` brings out both of
@@ -1860,7 +1860,7 @@ article = Article.create(name: 'a1')
person.articles << article
person.articles << article
person.articles.inspect # => [#<Article id: 7, name: "a1">]
-Reading.all.inspect # => [#<Reading id: 16, person_id: 7, article_id: 7>, #<Reading id: 17, person_id: 7, article_id: 7>]
+Reading.all.inspect # => [#<Reading id: 16, person_id: 7, article_id: 7>, #<Reading id: 17, person_id: 7, article_id: 7>]
```
In the above case there are still two readings. However `person.articles` shows
diff --git a/guides/source/caching_with_rails.md b/guides/source/caching_with_rails.md
index a1b0029c47..fd7626250c 100644
--- a/guides/source/caching_with_rails.md
+++ b/guides/source/caching_with_rails.md
@@ -381,7 +381,7 @@ config.cache_store = :memory_store, { size: 64.megabytes }
```
If you're running multiple Ruby on Rails server processes (which is the case
-if you're using mongrel_cluster or Phusion Passenger), then your Rails server
+if you're using Phusion Passenger or puma clustered mode), then your Rails server
process instances won't be able to share cache data with each other. This cache
store is not appropriate for large application deployments. However, it can
work well for small, low traffic sites with only a couple of server processes,
diff --git a/guides/source/configuring.md b/guides/source/configuring.md
index c938edd8f7..fbf3c27957 100644
--- a/guides/source/configuring.md
+++ b/guides/source/configuring.md
@@ -71,7 +71,7 @@ These configuration methods are to be called on a `Rails::Railtie` object, such
* `config.beginning_of_week` sets the default beginning of week for the
application. Accepts a valid week day symbol (e.g. `:monday`).
-* `config.cache_store` configures which cache store to use for Rails caching. Options include one of the symbols `:memory_store`, `:file_store`, `:mem_cache_store`, `:null_store`, or an object that implements the cache API. Defaults to `:file_store` if the directory `tmp/cache` exists, and to `:memory_store` otherwise.
+* `config.cache_store` configures which cache store to use for Rails caching. Options include one of the symbols `:memory_store`, `:file_store`, `:mem_cache_store`, `:null_store`, or an object that implements the cache API. Defaults to `:file_store`.
* `config.colorize_logging` specifies whether or not to use ANSI color codes when logging information. Defaults to `true`.
@@ -131,7 +131,7 @@ defaults to `:debug` for all environments. The available log levels are: `:debug
mylogger = MyLogger.new(STDOUT)
mylogger.formatter = config.log_formatter
- config.logger = ActiveSupport::TaggedLogging.new(mylogger)
+ config.logger = ActiveSupport::TaggedLogging.new(mylogger)
```
* `config.middleware` allows you to configure the application's middleware. This is covered in depth in the [Configuring Middleware](#configuring-middleware) section below.
@@ -169,6 +169,8 @@ pipeline is enabled. It is set to `true` by default.
* `config.assets.precompile` allows you to specify additional assets (other than `application.css` and `application.js`) which are to be precompiled when `rake assets:precompile` is run.
+* `config.assets.unknown_asset_fallback` allows you to modify the behavior of the asset pipeline when an asset is not in the pipeline, if you use sprockets-rails 3.2.0 or newer. Defaults to `true`.
+
* `config.assets.prefix` defines the prefix where assets are served from. Defaults to `/assets`.
* `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.
@@ -1196,7 +1198,7 @@ development:
timeout: 5000
```
-Since the connection pooling is handled inside of Active Record by default, all application servers (Thin, mongrel, Unicorn etc.) should behave the same. The database connection pool is initially empty. As demand for connections increases it will create them until it reaches the connection pool limit.
+Since the connection pooling is handled inside of Active Record by default, all application servers (Thin, Puma, Unicorn etc.) should behave the same. The database connection pool is initially empty. As demand for connections increases it will create them until it reaches the connection pool limit.
Any one request will check out a connection the first time it requires access to the database. At the end of the request it will check the connection back in. This means that the additional connection slot will be available again for the next request in the queue.
diff --git a/guides/source/contributing_to_ruby_on_rails.md b/guides/source/contributing_to_ruby_on_rails.md
index ba8d085f79..5df16e68c9 100644
--- a/guides/source/contributing_to_ruby_on_rails.md
+++ b/guides/source/contributing_to_ruby_on_rails.md
@@ -41,6 +41,7 @@ Having a way to reproduce your issue will be very helpful for others to help con
* Template for Active Record (models, database) issues: [gem](https://github.com/rails/rails/blob/master/guides/bug_report_templates/active_record_gem.rb) / [master](https://github.com/rails/rails/blob/master/guides/bug_report_templates/active_record_master.rb)
* Template for Action Pack (controllers, routing) issues: [gem](https://github.com/rails/rails/blob/master/guides/bug_report_templates/action_controller_gem.rb) / [master](https://github.com/rails/rails/blob/master/guides/bug_report_templates/action_controller_master.rb)
+* Template for Active Job issues: [gem](https://github.com/rails/rails/blob/master/guides/bug_report_templates/active_job_gem.rb) / [master](https://github.com/rails/rails/blob/master/guides/bug_report_templates/active_job_master.rb)
* Generic template for other issues: [gem](https://github.com/rails/rails/blob/master/guides/bug_report_templates/generic_gem.rb) / [master](https://github.com/rails/rails/blob/master/guides/bug_report_templates/generic_master.rb)
These templates include the boilerplate code to set up a test case against either a released version of Rails (`*_gem.rb`) or edge Rails (`*_master.rb`).
@@ -677,7 +678,7 @@ $ git format-patch master --stdout > ~/my_changes.patch
Switch over to the target branch and apply your changes:
```bash
-$ git checkout -b my_backport_branch 3-2-stable
+$ git checkout -b my_backport_branch 4-2-stable
$ git apply ~/my_changes.patch
```
diff --git a/guides/source/credits.html.erb b/guides/source/credits.html.erb
index 511d76041b..5adbd12ac0 100644
--- a/guides/source/credits.html.erb
+++ b/guides/source/credits.html.erb
@@ -22,7 +22,7 @@ Ruby on Rails Guides: Credits
<h3 class="section">Rails Guides Designers</h3>
<%= author('Jason Zimdars', 'jz') do %>
- Jason Zimdars is an experienced creative director and web designer who has lead UI and UX design for numerous websites and web applications. You can see more of his design and writing at <a href="http://www.thinkcage.com/">Thinkcage.com</a> or follow him on <a href="http://twitter.com/JZ">Twitter</a>.
+ Jason Zimdars is an experienced creative director and web designer who has lead UI and UX design for numerous websites and web applications. You can see more of his design and writing at <a href="http://www.thinkcage.com/">Thinkcage.com</a> or follow him on <a href="https://twitter.com/jasonzimdars">Twitter</a>.
<% end %>
<h3 class="section">Rails Guides Authors</h3>
@@ -32,7 +32,7 @@ Ruby on Rails Guides: Credits
<% end %>
<%= author('Oscar Del Ben', 'oscardelben', 'oscardelben.jpg') do %>
-Oscar Del Ben is a software engineer at <a href="http://www.wildfireapp.com/">Wildfire</a>. He's a regular open source contributor (<a href="https://github.com/oscardelben">GitHub account</a>) and tweets regularly at <a href="https://twitter.com/oscardelben">@oscardelben</a>.
+Oscar Del Ben is a software engineer at <a href="http://www.businessinsider.com/google-buys-wildfire-2012-8">Wildfire</a>. He's a regular open source contributor (<a href="https://github.com/oscardelben">GitHub account</a>) and tweets regularly at <a href="https://twitter.com/oscardelben">@oscardelben</a>.
<% end %>
<%= author('Frederick Cheung', 'fcheung') do %>
diff --git a/guides/source/engines.md b/guides/source/engines.md
index d6118c014f..83c0a7f337 100644
--- a/guides/source/engines.md
+++ b/guides/source/engines.md
@@ -46,7 +46,7 @@ see how to hook it into an application.
Engines can also be isolated from their host applications. This means that an
application is able to have a path provided by a routing helper such as
-`articles_path` and use an engine also that provides a path also called
+`articles_path` and use an engine that also provides a path also called
`articles_path`, and the two would not clash. Along with this, controllers, models
and table names are also namespaced. You'll see how to do this later in this
guide.
diff --git a/guides/source/getting_started.md b/guides/source/getting_started.md
index c4a8eacc57..31d5c4f71d 100644
--- a/guides/source/getting_started.md
+++ b/guides/source/getting_started.md
@@ -633,8 +633,7 @@ this situation, the only parameters that matter are the ones from the form.
TIP: Ensure you have a firm grasp of the `params` method, as you'll use it fairly regularly. Let's consider an example URL: **http://www.example.com/?username=dhh&email=dhh@email.com**. In this URL, `params[:username]` would equal "dhh" and `params[:email]` would equal "dhh@email.com".
-If you re-submit the form one more time you'll now no longer get the missing
-template error. Instead, you'll see something that looks like the following:
+If you re-submit the form one more time, you'll see something that looks like the following:
```ruby
<ActionController::Parameters {"title"=>"First Article!", "text"=>"This is my first article."} permitted: false>
diff --git a/guides/source/i18n.md b/guides/source/i18n.md
index 1565008a69..887774961a 100644
--- a/guides/source/i18n.md
+++ b/guides/source/i18n.md
@@ -1123,7 +1123,7 @@ I18n support in Ruby on Rails was introduced in the release 2.2 and is still evo
Thus we encourage everybody to experiment with new ideas and features in gems or other libraries and make them available to the community. (Don't forget to announce your work on our [mailing list](http://groups.google.com/group/rails-i18n)!)
-If you find your own locale (language) missing from our [example translations data](https://github.com/svenfuchs/rails-i18n/tree/master/rails/locale) repository for Ruby on Rails, please [_fork_](https://github.com/guides/fork-a-project-and-submit-your-modifications) the repository, add your data and send a [pull request](https://github.com/guides/pull-requests).
+If you find your own locale (language) missing from our [example translations data](https://github.com/svenfuchs/rails-i18n/tree/master/rails/locale) repository for Ruby on Rails, please [_fork_](https://github.com/guides/fork-a-project-and-submit-your-modifications) the repository, add your data and send a [pull request](https://help.github.com/articles/about-pull-requests/).
Resources
diff --git a/guides/source/initialization.md b/guides/source/initialization.md
index a2eec03eba..57ed35d0d8 100644
--- a/guides/source/initialization.md
+++ b/guides/source/initialization.md
@@ -318,7 +318,7 @@ def parse!(args)
args, options = args.dup, {}
opt_parser = OptionParser.new do |opts|
- opts.banner = "Usage: rails server [mongrel, thin, etc] [options]"
+ opts.banner = "Usage: rails server [puma, thin, etc] [options]"
opts.on("-p", "--port=port", Integer,
"Runs Rails on the specified port.", "Default: 3000") { |v| options[:Port] = v }
...
@@ -663,7 +663,7 @@ DEFAULT_OPTIONS = {
}
def self.run(app, options = {})
- options = DEFAULT_OPTIONS.merge(options)
+ options = DEFAULT_OPTIONS.merge(options)
if options[:Verbose]
app = Rack::CommonLogger.new(app, STDOUT)
diff --git a/guides/source/security.md b/guides/source/security.md
index 36eb61be8b..aea9728c10 100644
--- a/guides/source/security.md
+++ b/guides/source/security.md
@@ -131,7 +131,7 @@ It works like this:
* The user takes the cookie from the first step (which they previously copied) and replaces the current cookie in the browser.
* The user has their original credit back.
-Including a nonce (a random value) in the session solves replay attacks. A nonce is valid only once, and the server has to keep track of all the valid nonces. It gets even more complicated if you have several application servers (mongrels). Storing nonces in a database table would defeat the entire purpose of CookieStore (avoiding accessing the database).
+Including a nonce (a random value) in the session solves replay attacks. A nonce is valid only once, and the server has to keep track of all the valid nonces. It gets even more complicated if you have several application servers. Storing nonces in a database table would defeat the entire purpose of CookieStore (avoiding accessing the database).
The best _solution against it is not to store this kind of data in a session, but in the database_. In this case store the credit in the database and the logged_in_user_id in the session.
@@ -287,7 +287,7 @@ Another class of security vulnerabilities surrounds the use of redirection and f
WARNING: _Redirection in a web application is an underestimated cracker tool: Not only can the attacker forward the user to a trap web site, they may also create a self-contained attack._
-Whenever the user is allowed to pass (parts of) the URL for redirection, it is possibly vulnerable. The most obvious attack would be to redirect users to a fake web application which looks and feels exactly as the original one. This so-called phishing attack works by sending an unsuspicious link in an email to the users, injecting the link by XSS in the web application or putting the link into an external site. It is unsuspicious, because the link starts with the URL to the web application and the URL to the malicious site is hidden in the redirection parameter: http://www.example.com/site/redirect?to= www.attacker.com. Here is an example of a legacy action:
+Whenever the user is allowed to pass (parts of) the URL for redirection, it is possibly vulnerable. The most obvious attack would be to redirect users to a fake web application which looks and feels exactly as the original one. This so-called phishing attack works by sending an unsuspicious link in an email to the users, injecting the link by XSS in the web application or putting the link into an external site. It is unsuspicious, because the link starts with the URL to the web application and the URL to the malicious site is hidden in the redirection parameter: http://www.example.com/site/redirect?to=www.attacker.com. Here is an example of a legacy action:
```ruby
def legacy
diff --git a/guides/source/testing.md b/guides/source/testing.md
index 4de32d9d77..8f9246dea2 100644
--- a/guides/source/testing.md
+++ b/guides/source/testing.md
@@ -239,8 +239,8 @@ Run options: --seed 1808
Error:
ArticleTest#test_should_report_error:
-NameError: undefined local variable or method `some_undefined_variable' for #<ArticleTest:0x007fee3aa71798>
- test/models/article_test.rb:11:in `block in <class:ArticleTest>'
+NameError: undefined local variable or method 'some_undefined_variable' for #<ArticleTest:0x007fee3aa71798>
+ test/models/article_test.rb:11:in 'block in <class:ArticleTest>'
bin/rails test test/models/article_test.rb:9
@@ -369,7 +369,7 @@ documentation](http://docs.seattlerb.org/minitest).
We can run all of our tests at once by using the `bin/rails test` command.
-Or we can run a single test by passing the `bin/rails test` command the filename containing the test cases.
+Or we can run a single test file by passing the `bin/rails test` command the filename containing the test cases.
```bash
$ bin/rails test test/models/article_test.rb
@@ -763,16 +763,11 @@ The `get` method kicks off the web request and populates the results into the `@
* The action of the controller you are requesting.
This can be in the form of a string or a route (i.e. `articles_url`).
-
* `params`: option with a hash of request parameters to pass into the action
(e.g. query string parameters or article variables).
-
* `headers`: for setting the headers that will be passed with the request.
-
* `env`: for customizing the request environment as needed.
-
* `xhr`: whether the request is Ajax request or not. Can be set to true for marking the request as Ajax.
-
* `as`: for encoding the request with different content type. Supports `:json` by default.
All of these keyword arguments are optional.
@@ -865,8 +860,8 @@ class ArticlesControllerTest < ActionDispatch::IntegrationTest
test "should get index" do
get articles_url
- assert_equal "index", @controller.action_name
- assert_equal "application/x-www-form-urlencoded", @request.media_type
+ assert_equal "index", @controller.action_name
+ assert_equal "application/x-www-form-urlencoded", @request.media_type
assert_match "Articles", @response.body
end
end
@@ -1056,7 +1051,7 @@ To avoid code duplication, you can add your own test helpers.
Sign in helper can be a good example:
```ruby
-#test/test_helper.rb
+# test/test_helper.rb
module SignInHelper
def sign_in_as(user)
@@ -1362,7 +1357,7 @@ Here is an example using the [`travel_to`](http://api.rubyonrails.org/classes/Ac
user = User.create(name: 'Gaurish', activation_date: Date.new(2004, 10, 24))
assert_not user.applicable_for_gifting?
travel_to Date.new(2004, 11, 24) do
- assert_equal Date.new(2004, 10, 24), user.activation_date # inside the travel_to block `Date.current` is mocked
+ assert_equal Date.new(2004, 10, 24), user.activation_date # inside the `travel_to` block `Date.current` is mocked
assert user.applicable_for_gifting?
end
assert_equal Date.new(2004, 10, 24), user.activation_date # The change was visible only inside the `travel_to` block.
diff --git a/railties/lib/rails/app_loader.rb b/railties/lib/rails/app_loader.rb
index 107e47de55..525d5f0161 100644
--- a/railties/lib/rails/app_loader.rb
+++ b/railties/lib/rails/app_loader.rb
@@ -50,7 +50,7 @@ EOS
# If we exhaust the search there is no executable, this could be a
# call to generate a new application, so restore the original cwd.
- Dir.chdir(original_cwd) and return if Pathname.new(Dir.pwd).root?
+ Dir.chdir(original_cwd) && return if Pathname.new(Dir.pwd).root?
# Otherwise keep moving upwards in search of an executable.
Dir.chdir("..")
diff --git a/railties/lib/rails/commands/server.rb b/railties/lib/rails/commands/server.rb
index 0339849bfe..1eabf3fef3 100644
--- a/railties/lib/rails/commands/server.rb
+++ b/railties/lib/rails/commands/server.rb
@@ -23,7 +23,7 @@ module Rails
def option_parser(options)
OptionParser.new do |opts|
- opts.banner = "Usage: rails server [mongrel, thin etc] [options]"
+ opts.banner = "Usage: rails server [puma, thin etc] [options]"
opts.on("-p", "--port=port", Integer,
"Runs Rails on the specified port.", "Default: 3000") { |v| options[:Port] = v }
opts.on("-b", "--binding=IP", String,
diff --git a/railties/lib/rails/generators.rb b/railties/lib/rails/generators.rb
index 6a112fc710..fd35dfd1a2 100644
--- a/railties/lib/rails/generators.rb
+++ b/railties/lib/rails/generators.rb
@@ -277,7 +277,9 @@ module Rails
protected
- # This code is based directly on the Text gem implementation
+ # This code is based directly on the Text gem implementation.
+ # Copyright (c) 2006-2013 Paul Battley, Michael Neumann, Tim Fletcher.
+ #
# Returns a value representing the "cost" of transforming str1 into str2
def self.levenshtein_distance(str1, str2)
s = str1
diff --git a/railties/lib/rails/generators/app_base.rb b/railties/lib/rails/generators/app_base.rb
index 7d061ed27c..d76acbdafc 100644
--- a/railties/lib/rails/generators/app_base.rb
+++ b/railties/lib/rails/generators/app_base.rb
@@ -162,14 +162,15 @@ module Rails
def set_default_accessors!
self.destination_root = File.expand_path(app_path, destination_root)
- self.rails_template = case options[:template]
- when /^https?:\/\//
- options[:template]
- when String
- File.expand_path(options[:template], Dir.pwd)
+ self.rails_template = \
+ case options[:template]
+ when /^https?:\/\//
+ options[:template]
+ when String
+ File.expand_path(options[:template], Dir.pwd)
else
- options[:template]
- end
+ options[:template]
+ end
end
def database_gemfile_entry
diff --git a/railties/lib/rails/generators/base.rb b/railties/lib/rails/generators/base.rb
index c0e34c20e7..1a0420c769 100644
--- a/railties/lib/rails/generators/base.rb
+++ b/railties/lib/rails/generators/base.rb
@@ -310,9 +310,9 @@ module Rails
# Returns default for the option name given doing a lookup in config.
def self.default_for_option(config, name, options, default)
- if generator_name and c = config[generator_name.to_sym] and c.key?(name)
+ if generator_name && (c = config[generator_name.to_sym]) && c.key?(name)
c[name]
- elsif base_name and c = config[base_name.to_sym] and c.key?(name)
+ elsif base_name && (c = config[base_name.to_sym]) && c.key?(name)
c[name]
elsif config[:rails].key?(name)
config[:rails][name]
diff --git a/railties/lib/rails/generators/rails/app/templates/config/initializers/new_framework_defaults.rb.tt b/railties/lib/rails/generators/rails/app/templates/config/initializers/new_framework_defaults.rb.tt
index e539f4c457..5ad18cc5ad 100644
--- a/railties/lib/rails/generators/rails/app/templates/config/initializers/new_framework_defaults.rb.tt
+++ b/railties/lib/rails/generators/rails/app/templates/config/initializers/new_framework_defaults.rb.tt
@@ -32,3 +32,7 @@ ActiveSupport.halt_callback_chains_on_return_false = <%= options[:update] ? true
# Configure SSL options to enable HSTS with subdomains. Previous versions had false.
Rails.application.config.ssl_options = { hsts: { subdomains: true } }
<%- end -%>
+
+# Unknown asset fallback will return the path passed in when the given
+# asset is not present in the asset pipeline.
+Rails.application.config.assets.unknown_asset_fallback = <%= options[:update] ? true : false %>
diff --git a/railties/lib/rails/templates/rails/mailers/email.html.erb b/railties/lib/rails/templates/rails/mailers/email.html.erb
index fed96fbc85..c63781ed0c 100644
--- a/railties/lib/rails/templates/rails/mailers/email.html.erb
+++ b/railties/lib/rails/templates/rails/mailers/email.html.erb
@@ -88,7 +88,10 @@
<% unless @email.attachments.nil? || @email.attachments.empty? %>
<dt>Attachments:</dt>
<dd>
- <%= @email.attachments.map { |a| a.respond_to?(:original_filename) ? a.original_filename : a.filename }.join(', ') %>
+ <% @email.attachments.each do |a| %>
+ <% filename = a.respond_to?(:original_filename) ? a.original_filename : a.filename %>
+ <%= link_to filename, "data:application/octet-stream;charset=utf-8;base64,#{Base64.encode64(a.body.to_s)}", download: filename %>
+ <% end %>
</dd>
<% end %>
diff --git a/railties/test/application/asset_debugging_test.rb b/railties/test/application/asset_debugging_test.rb
index a732869d62..3e17a1efa5 100644
--- a/railties/test/application/asset_debugging_test.rb
+++ b/railties/test/application/asset_debugging_test.rb
@@ -68,5 +68,102 @@ module ApplicationTests
assert_match(/<script src="\/assets\/application(\.self)?-([0-z]+)\.js\?body=1"><\/script>/, last_response.body)
assert_match(/<script src="\/assets\/xmlhr(\.self)?-([0-z]+)\.js\?body=1"><\/script>/, last_response.body)
end
+
+ test "public path and tag methods are not over-written by the asset pipeline" do
+ contents = "doesnotexist"
+ cases = {
+ asset_path: %r{/#{contents}},
+ image_path: %r{/images/#{contents}},
+ video_path: %r{/videos/#{contents}},
+ audio_path: %r{/audios/#{contents}},
+ font_path: %r{/fonts/#{contents}},
+ javascript_path: %r{/javascripts/#{contents}},
+ stylesheet_path: %r{/stylesheets/#{contents}},
+ image_tag: %r{<img src="/images/#{contents}"},
+ favicon_link_tag: %r{<link rel="shortcut icon" type="image/x-icon" href="/images/#{contents}" />},
+ stylesheet_link_tag: %r{<link rel="stylesheet" media="screen" href="/stylesheets/#{contents}.css" />},
+ javascript_include_tag: %r{<script src="/javascripts/#{contents}.js">},
+ audio_tag: %r{<audio src="/audios/#{contents}"></audio>},
+ video_tag: %r{<video src="/videos/#{contents}"></video>}
+ }
+
+ cases.each do |(view_method, tag_match)|
+ app_file "app/views/posts/index.html.erb", "<%= #{view_method} '#{contents}', skip_pipeline: true %>"
+
+ app "development"
+
+ class ::PostsController < ActionController::Base ; end
+
+ get "/posts?debug_assets=true"
+
+ body = last_response.body
+ assert_match(tag_match, body, "Expected `#{view_method}` to produce a match to #{tag_match}, but did not: #{body}")
+ end
+ end
+
+ test "public url methods are not over-written by the asset pipeline" do
+ contents = "doesnotexist"
+ cases = {
+ asset_url: %r{http://example.org/#{contents}},
+ image_url: %r{http://example.org/images/#{contents}},
+ video_url: %r{http://example.org/videos/#{contents}},
+ audio_url: %r{http://example.org/audios/#{contents}},
+ font_url: %r{http://example.org/fonts/#{contents}},
+ javascript_url: %r{http://example.org/javascripts/#{contents}},
+ stylesheet_url: %r{http://example.org/stylesheets/#{contents}},
+ }
+
+ cases.each do |(view_method, tag_match)|
+ app_file "app/views/posts/index.html.erb", "<%= #{view_method} '#{contents}', skip_pipeline: true %>"
+
+ app "development"
+
+ class ::PostsController < ActionController::Base ; end
+
+ get "/posts?debug_assets=true"
+
+ body = last_response.body
+ assert_match(tag_match, body, "Expected `#{view_method}` to produce a match to #{tag_match}, but did not: #{body}")
+ end
+ end
+
+ test "{ skip_pipeline: true } does not use the asset pipeline" do
+ cases = {
+ /\/assets\/application-.*.\.js/ => {},
+ /application.js/ => { skip_pipeline: true },
+ }
+ cases.each do |(tag_match, options_hash)|
+ app_file "app/views/posts/index.html.erb", "<%= asset_path('application.js', #{options_hash}) %>"
+
+ app "development"
+
+ class ::PostsController < ActionController::Base ; end
+
+ get "/posts?debug_assets=true"
+
+ body = last_response.body.strip
+ assert_match(tag_match, body, "Expected `asset_path` with `#{options_hash}` to produce a match to #{tag_match}, but did not: #{body}")
+ end
+ end
+
+ test "public_compute_asset_path does not use the asset pipeline" do
+ cases = {
+ compute_asset_path: /\/assets\/application-.*.\.js/,
+ public_compute_asset_path: /application.js/,
+ }
+
+ cases.each do |(view_method, tag_match)|
+ app_file "app/views/posts/index.html.erb", "<%= #{ view_method } 'application.js' %>"
+
+ app "development"
+
+ class ::PostsController < ActionController::Base ; end
+
+ get "/posts?debug_assets=true"
+
+ body = last_response.body.strip
+ assert_match(tag_match, body, "Expected `#{view_method}` to produce a match to #{ tag_match }, but did not: #{ body }")
+ end
+ end
end
end
diff --git a/railties/test/application/bin_setup_test.rb b/railties/test/application/bin_setup_test.rb
index 2f076ea2f6..0bbd25db2b 100644
--- a/railties/test/application/bin_setup_test.rb
+++ b/railties/test/application/bin_setup_test.rb
@@ -6,10 +6,17 @@ module ApplicationTests
def setup
build_app
+
+ create_gemfile
+ update_boot_file_to_use_bundler
+ @old_gemfile_env = ENV["BUNDLE_GEMFILE"]
+ ENV["BUNDLE_GEMFILE"] = app_path + "/Gemfile"
end
def teardown
teardown_app
+
+ ENV["BUNDLE_GEMFILE"] = @old_gemfile_env
end
def test_bin_setup
@@ -52,5 +59,16 @@ Created database 'db/test.sqlite3'
OUTPUT
end
end
+
+ private
+ def create_gemfile
+ app_file("Gemfile", "source 'https://rubygems.org'")
+ app_file("Gemfile", "gem 'rails', path: '#{RAILS_FRAMEWORK_ROOT}'", "a")
+ app_file("Gemfile", "gem 'sqlite3'", "a")
+ end
+
+ def update_boot_file_to_use_bundler
+ app_file("config/boot.rb", "require 'bundler/setup'")
+ end
end
end
diff --git a/railties/test/json_params_parsing_test.rb b/railties/test/json_params_parsing_test.rb
index 104664c1ee..7fff3bb465 100644
--- a/railties/test/json_params_parsing_test.rb
+++ b/railties/test/json_params_parsing_test.rb
@@ -6,7 +6,7 @@ class JsonParamsParsingTest < ActionDispatch::IntegrationTest
def test_prevent_null_query
# Make sure we have data to find
klass = Class.new(ActiveRecord::Base) do
- def self.name; 'Foo'; end
+ def self.name; "Foo"; end
establish_connection adapter: "sqlite3", database: ":memory:"
connection.create_table "foos" do |t|
t.string :title
@@ -26,24 +26,24 @@ class JsonParamsParsingTest < ActionDispatch::IntegrationTest
end
}
- assert_nil app.call(make_env({ 't' => nil }))
- assert_nil app.call(make_env({ 't' => [nil] }))
+ assert_nil app.call(make_env("t" => nil))
+ assert_nil app.call(make_env("t" => [nil]))
[[[nil]], [[[nil]]]].each do |data|
- assert_nil app.call(make_env({ 't' => data }))
+ assert_nil app.call(make_env("t" => data))
end
ensure
klass.connection.drop_table("foos")
end
private
- def make_env json
+ def make_env(json)
data = JSON.dump json
content_length = data.length
{
- 'CONTENT_LENGTH' => content_length,
- 'CONTENT_TYPE' => 'application/json',
- 'rack.input' => StringIO.new(data)
+ "CONTENT_LENGTH" => content_length,
+ "CONTENT_TYPE" => "application/json",
+ "rack.input" => StringIO.new(data)
}
end
end
diff --git a/tools/profile b/tools/profile
index 124ed0f4be..f7d91e51cf 100755
--- a/tools/profile
+++ b/tools/profile
@@ -72,7 +72,7 @@ module CodeTools
fail Error.new("#{path} is a directory") if File.directory?(path)
ruby_extension = File.extname(path) == ".rb"
ruby_executable = File.open(path, "rb") { |f| f.readline } =~ [/\A#!.*ruby/]
- fail Error.new("Not a ruby file") unless ruby_extension or ruby_executable
+ fail Error.new("Not a ruby file") unless ruby_extension || ruby_executable
end
module RequireProfiler