aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitattributes2
-rw-r--r--Gemfile12
-rw-r--r--Gemfile.lock11
-rw-r--r--Rakefile10
-rw-r--r--actioncable/Rakefile8
-rw-r--r--actioncable/app/assets/javascripts/action_cable.coffee.erb5
-rw-r--r--actioncable/app/assets/javascripts/action_cable/connection.coffee36
-rw-r--r--actioncable/app/assets/javascripts/action_cable/connection_monitor.coffee81
-rw-r--r--actioncable/app/assets/javascripts/action_cable/consumer.coffee6
-rw-r--r--actioncable/app/assets/javascripts/action_cable/subscription.coffee22
-rw-r--r--actioncable/app/assets/javascripts/action_cable/subscriptions.coffee10
-rw-r--r--actioncable/lib/action_cable.rb3
-rw-r--r--actioncable/lib/action_cable/connection/client_socket.rb2
-rw-r--r--actioncable/lib/action_cable/connection/faye_client_socket.rb1
-rw-r--r--actioncable/lib/action_cable/connection/stream.rb2
-rw-r--r--actioncable/lib/action_cable/engine.rb2
-rw-r--r--actioncable/lib/action_cable/subscription_adapter/evented_redis.rb2
-rw-r--r--actioncable/lib/rails/generators/channel/channel_generator.rb2
-rw-r--r--actioncable/test/connection/client_socket_test.rb65
-rw-r--r--actioncable/test/connection/stream_test.rb67
-rw-r--r--actioncable/test/subscription_adapter/postgresql_test.rb7
-rw-r--r--actionmailer/lib/action_mailer/base.rb2
-rw-r--r--actionmailer/lib/action_mailer/railtie.rb4
-rw-r--r--actionmailer/lib/rails/generators/mailer/mailer_generator.rb8
-rw-r--r--actionmailer/lib/rails/generators/mailer/templates/application_mailer.rb4
-rw-r--r--actionpack/CHANGELOG.md40
-rw-r--r--actionpack/actionpack.gemspec2
-rw-r--r--actionpack/lib/abstract_controller/base.rb4
-rw-r--r--actionpack/lib/abstract_controller/error.rb4
-rw-r--r--actionpack/lib/abstract_controller/helpers.rb3
-rw-r--r--actionpack/lib/abstract_controller/rendering.rb1
-rw-r--r--actionpack/lib/action_controller/metal/conditional_get.rb6
-rw-r--r--actionpack/lib/action_controller/metal/instrumentation.rb1
-rw-r--r--actionpack/lib/action_controller/metal/mime_responds.rb2
-rw-r--r--actionpack/lib/action_controller/metal/redirecting.rb2
-rw-r--r--actionpack/lib/action_controller/metal/rescue.rb8
-rw-r--r--actionpack/lib/action_controller/metal/strong_parameters.rb20
-rw-r--r--actionpack/lib/action_dispatch/http/request.rb1
-rw-r--r--actionpack/lib/action_dispatch/middleware/flash.rb5
-rw-r--r--actionpack/lib/action_dispatch/routing.rb6
-rw-r--r--actionpack/lib/action_dispatch/testing/integration.rb57
-rw-r--r--actionpack/test/controller/log_subscriber_test.rb6
-rw-r--r--actionpack/test/controller/mime/respond_to_test.rb15
-rw-r--r--actionpack/test/controller/parameters/accessors_test.rb20
-rw-r--r--actionpack/test/controller/render_test.rb10
-rw-r--r--actionpack/test/controller/rescue_test.rb33
-rw-r--r--actionview/CHANGELOG.md2
-rw-r--r--actionview/actionview.gemspec8
-rw-r--r--actionview/lib/action_view/helpers/atom_feed_helper.rb2
-rw-r--r--actionview/lib/action_view/helpers/form_helper.rb2
-rw-r--r--actionview/lib/action_view/helpers/url_helper.rb22
-rw-r--r--actionview/lib/action_view/railtie.rb2
-rw-r--r--actionview/lib/action_view/renderer/partial_renderer.rb2
-rw-r--r--actionview/lib/action_view/tasks/cache_digests.rake (renamed from actionview/lib/action_view/tasks/dependencies.rake)0
-rw-r--r--actionview/lib/action_view/view_paths.rb2
-rw-r--r--actionview/test/abstract_unit.rb14
-rw-r--r--actionview/test/fixtures/test/_customer.mobile.erb1
-rw-r--r--actionview/test/lib/controller/fake_models.rb21
-rw-r--r--actionview/test/template/form_helper_test.rb24
-rw-r--r--actionview/test/template/render_test.rb5
-rw-r--r--actionview/test/template/url_helper_test.rb4
-rw-r--r--activejob/activejob.gemspec2
-rw-r--r--activejob/lib/active_job/core.rb4
-rw-r--r--activejob/test/cases/argument_serialization_test.rb13
-rw-r--r--activejob/test/cases/job_serialization_test.rb23
-rw-r--r--activemodel/activemodel.gemspec2
-rw-r--r--activemodel/lib/active_model/type.rb2
-rw-r--r--activerecord/CHANGELOG.md35
-rw-r--r--activerecord/activerecord.gemspec2
-rw-r--r--activerecord/lib/active_record/associations/association.rb2
-rw-r--r--activerecord/lib/active_record/associations/join_dependency.rb2
-rw-r--r--activerecord/lib/active_record/attributes.rb6
-rw-r--r--activerecord/lib/active_record/autosave_association.rb2
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/schema_dumper.rb14
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb4
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract_adapter.rb4
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb50
-rw-r--r--activerecord/lib/active_record/connection_adapters/column.rb8
-rw-r--r--activerecord/lib/active_record/connection_adapters/mysql/schema_dumper.rb21
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/column.rb1
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/schema_dumper.rb17
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb10
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb2
-rw-r--r--activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb5
-rw-r--r--activerecord/lib/active_record/enum.rb2
-rw-r--r--activerecord/lib/active_record/nested_attributes.rb2
-rw-r--r--activerecord/lib/active_record/railties/databases.rake4
-rw-r--r--activerecord/lib/active_record/reflection.rb21
-rw-r--r--activerecord/lib/active_record/relation/finder_methods.rb4
-rw-r--r--activerecord/lib/active_record/schema_dumper.rb7
-rw-r--r--activerecord/lib/active_record/scoping/default.rb3
-rw-r--r--activerecord/lib/active_record/tasks/database_tasks.rb3
-rw-r--r--activerecord/lib/active_record/tasks/mysql_database_tasks.rb2
-rw-r--r--activerecord/lib/active_record/type.rb2
-rw-r--r--activerecord/test/cases/adapters/mysql2/case_sensitivity_test.rb9
-rw-r--r--activerecord/test/cases/adapters/mysql2/connection_test.rb50
-rw-r--r--activerecord/test/cases/adapters/mysql2/unsigned_type_test.rb2
-rw-r--r--activerecord/test/cases/adapters/postgresql/bytea_test.rb9
-rw-r--r--activerecord/test/cases/adapters/postgresql/serial_test.rb30
-rw-r--r--activerecord/test/cases/associations/join_model_test.rb17
-rw-r--r--activerecord/test/cases/autosave_association_test.rb4
-rw-r--r--activerecord/test/cases/inheritance_test.rb5
-rw-r--r--activerecord/test/cases/primary_keys_test.rb4
-rw-r--r--activerecord/test/cases/schema_dumper_test.rb12
-rw-r--r--activerecord/test/cases/scoping/default_scoping_test.rb12
-rw-r--r--activerecord/test/cases/tasks/database_tasks_test.rb20
-rw-r--r--activerecord/test/cases/validations/i18n_validation_test.rb6
-rw-r--r--activerecord/test/models/cat.rb10
-rw-r--r--activerecord/test/schema/mysql2_specific_schema.rb1
-rw-r--r--activerecord/test/schema/schema.rb5
-rw-r--r--activesupport/CHANGELOG.md9
-rw-r--r--activesupport/activesupport.gemspec2
-rw-r--r--activesupport/lib/active_support/core_ext/date_and_time/calculations.rb2
-rw-r--r--activesupport/lib/active_support/core_ext/marshal.rb5
-rw-r--r--activesupport/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb4
-rw-r--r--activesupport/lib/active_support/dependencies.rb57
-rw-r--r--activesupport/lib/active_support/evented_file_update_checker.rb8
-rw-r--r--activesupport/lib/active_support/file_update_checker.rb2
-rw-r--r--activesupport/lib/active_support/rescuable.rb10
-rw-r--r--activesupport/lib/active_support/values/time_zone.rb1
-rw-r--r--activesupport/test/autoloading_fixtures/raises_arbitrary_exception.rb4
-rw-r--r--activesupport/test/autoloading_fixtures/throws.rb4
-rw-r--r--activesupport/test/core_ext/marshal_test.rb11
-rw-r--r--activesupport/test/core_ext/module/attribute_accessor_per_thread_test.rb6
-rw-r--r--activesupport/test/dependencies_test.rb22
-rw-r--r--guides/assets/images/favicon.icobin5430 -> 16958 bytes
-rw-r--r--guides/source/5_0_release_notes.md81
-rw-r--r--guides/source/action_cable_overview.md2
-rw-r--r--guides/source/action_controller_overview.md2
-rw-r--r--guides/source/action_mailer_basics.md12
-rw-r--r--guides/source/action_view_overview.md2
-rw-r--r--guides/source/active_record_basics.md2
-rw-r--r--guides/source/active_record_migrations.md4
-rw-r--r--guides/source/active_support_core_extensions.md2
-rw-r--r--guides/source/active_support_instrumentation.md4
-rw-r--r--guides/source/asset_pipeline.md13
-rw-r--r--guides/source/association_basics.md56
-rw-r--r--guides/source/command_line.md7
-rw-r--r--guides/source/configuring.md23
-rw-r--r--guides/source/contributing_to_ruby_on_rails.md2
-rw-r--r--guides/source/debugging_rails_applications.md7
-rw-r--r--guides/source/documents.yaml2
-rw-r--r--guides/source/engines.md6
-rw-r--r--guides/source/getting_started.md6
-rw-r--r--guides/source/i18n.md8
-rw-r--r--guides/source/initialization.md6
-rw-r--r--guides/source/layouts_and_rendering.md19
-rw-r--r--guides/source/routing.md4
-rw-r--r--guides/source/security.md2
-rw-r--r--guides/source/upgrading_ruby_on_rails.md2
-rw-r--r--rails.gemspec2
-rw-r--r--railties/CHANGELOG.md4
-rw-r--r--railties/lib/rails/application.rb3
-rw-r--r--railties/lib/rails/code_statistics.rb1
-rw-r--r--railties/lib/rails/command.rb70
-rw-r--r--railties/lib/rails/commands.rb4
-rw-r--r--railties/lib/rails/commands/server.rb19
-rw-r--r--railties/lib/rails/dev_caching.rb40
-rw-r--r--railties/lib/rails/generators/actions.rb27
-rw-r--r--railties/lib/rails/generators/erb/mailer/mailer_generator.rb2
-rw-r--r--railties/lib/rails/generators/rails/app/app_generator.rb5
-rw-r--r--railties/lib/rails/generators/rails/app/templates/Gemfile4
-rw-r--r--railties/lib/rails/generators/rails/app/templates/Rakefile2
-rw-r--r--railties/lib/rails/generators/rails/app/templates/bin/rails2
-rw-r--r--railties/lib/rails/generators/rails/app/templates/bin/setup2
-rw-r--r--railties/lib/rails/generators/rails/app/templates/bin/update2
-rw-r--r--railties/lib/rails/generators/rails/app/templates/config.ru3
-rw-r--r--railties/lib/rails/generators/rails/app/templates/config/application.rb2
-rw-r--r--railties/lib/rails/generators/rails/app/templates/config/boot.rb2
-rw-r--r--railties/lib/rails/generators/rails/app/templates/config/environment.rb2
-rw-r--r--railties/lib/rails/generators/rails/app/templates/config/environments/development.rb.tt9
-rw-r--r--railties/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt22
-rw-r--r--railties/lib/rails/generators/rails/plugin/templates/rails/application.rb8
-rw-r--r--railties/lib/rails/generators/rails/plugin/templates/rails/boot.rb4
-rw-r--r--railties/lib/rails/generators/test_unit/mailer/mailer_generator.rb2
-rw-r--r--railties/lib/rails/tasks/dev.rake14
-rw-r--r--railties/lib/rails/tasks/framework.rake5
-rw-r--r--railties/lib/rails/test_unit/minitest_plugin.rb12
-rw-r--r--railties/railties.gemspec2
-rw-r--r--railties/test/application/configuration_test.rb4
-rw-r--r--railties/test/application/initializers/i18n_test.rb8
-rw-r--r--railties/test/application/middleware/session_test.rb28
-rw-r--r--railties/test/application/rake/dev_test.rb2
-rw-r--r--railties/test/application/rake_test.rb14
-rw-r--r--railties/test/commands/server_test.rb3
-rw-r--r--railties/test/generators/actions_test.rb10
-rw-r--r--railties/test/generators/app_generator_test.rb42
-rw-r--r--railties/test/generators/mailer_generator_test.rb6
188 files changed, 1293 insertions, 729 deletions
diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 0000000000..f6276855ce
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1,2 @@
+*.rb diff=ruby
+*.gemspec diff=ruby
diff --git a/Gemfile b/Gemfile
index f8779a3e49..dd09ddae68 100644
--- a/Gemfile
+++ b/Gemfile
@@ -5,7 +5,7 @@ gemspec
# We need a newish Rake since Active Job sets its test tasks' descriptions.
gem 'rake', '>= 10.3'
-# This needs to be with require false to ensure correct loading order, as has to
+# This needs to be with require false to ensure correct loading order, as it has to
# be loaded after loading the test library.
gem 'mocha', '~> 0.14', require: false
@@ -17,13 +17,7 @@ gem 'turbolinks', github: 'turbolinks/turbolinks-rails'
# require: false so bcrypt is loaded only when has_secure_password is used.
# This is to avoid Active Model (and by extension the entire framework)
# being dependent on a binary library.
-platforms :mingw, :x64_mingw, :mswin, :mswin64 do
- gem 'bcrypt-ruby', '~> 3.0.0', require: false
-end
-
-platforms :ruby, :jruby, :rbx do
- gem 'bcrypt', '~> 3.1.10', require: false
-end
+gem 'bcrypt', '~> 3.1.11', require: false
# This needs to be with require false to avoid it being automatically loaded by
# sprockets.
@@ -45,7 +39,7 @@ gem 'listen', '~> 3.0.5', require: false
# Active Job.
group :job do
- gem 'resque', require: false
+ gem 'resque', '< 1.26', require: false
gem 'resque-scheduler', require: false
gem 'sidekiq', require: false
gem 'sucker_punch', require: false
diff --git a/Gemfile.lock b/Gemfile.lock
index 90c15b4175..c76c4d7c2f 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -100,9 +100,9 @@ GEM
backburner (1.2.0)
beaneater (~> 1.0)
dante (> 0.1.5)
- bcrypt (3.1.10)
- bcrypt-ruby (3.0.1)
- bcrypt-ruby (3.0.1-x86-mingw32)
+ bcrypt (3.1.11)
+ bcrypt (3.1.11-x64-mingw32)
+ bcrypt (3.1.11-x86-mingw32)
beaneater (1.0.0)
benchmark-ips (2.3.0)
builder (3.2.2)
@@ -279,8 +279,7 @@ DEPENDENCIES
activerecord-jdbcpostgresql-adapter (>= 1.3.0)
activerecord-jdbcsqlite3-adapter (>= 1.3.0)
backburner
- bcrypt (~> 3.1.10)
- bcrypt-ruby (~> 3.0.0)
+ bcrypt (~> 3.1.11)
benchmark-ips
byebug
coffee-rails (~> 4.1.0)
@@ -310,7 +309,7 @@ DEPENDENCIES
rake (>= 10.3)
redcarpet (~> 3.2.3)
redis
- resque
+ resque (< 1.26)
resque-scheduler
sass!
sdoc (~> 0.4.0)
diff --git a/Rakefile b/Rakefile
index b4517e2545..1d70ce96ea 100644
--- a/Rakefile
+++ b/Rakefile
@@ -21,7 +21,10 @@ task :default => %w(test test:isolated)
task task_name do
errors = []
FRAMEWORKS.each do |project|
- system(%(cd #{project} && #{$0} #{task_name})) || errors << project
+ system(%(cd #{project} && #{$0} #{task_name} --trace)) || errors << project
+ end
+ if task_name =~ /test/
+ system(%(cd actioncable && env FAYE=1 #{$0} #{task_name} --trace)) || errors << 'actioncable-faye'
end
fail("Errors in #{errors.join(', ')}") unless errors.empty?
end
@@ -30,9 +33,10 @@ end
desc "Smoke-test all projects"
task :smoke do
(FRAMEWORKS - %w(activerecord)).each do |project|
- system %(cd #{project} && #{$0} test:isolated)
+ system %(cd #{project} && #{$0} test:isolated --trace)
end
- system %(cd activerecord && #{$0} sqlite3:isolated_test)
+ system %(cd activerecord && #{$0} sqlite3:isolated_test --trace)
+ system %(cd actioncable && env FAYE=1 #{$0} test:isolated --trace)
end
desc "Install gems for all projects."
diff --git a/actioncable/Rakefile b/actioncable/Rakefile
index 1d77fc7067..5ba7b7f7f6 100644
--- a/actioncable/Rakefile
+++ b/actioncable/Rakefile
@@ -19,6 +19,14 @@ Rake::TestTask.new do |t|
t.ruby_opts = ["--dev"] if defined?(JRUBY_VERSION)
end
+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
+end
+
namespace :assets do
root_path = Pathname.new(dir)
destination_path = root_path.join("lib/assets/compiled")
diff --git a/actioncable/app/assets/javascripts/action_cable.coffee.erb b/actioncable/app/assets/javascripts/action_cable.coffee.erb
index 6a8b4eeb85..f0422d9d9c 100644
--- a/actioncable/app/assets/javascripts/action_cable.coffee.erb
+++ b/actioncable/app/assets/javascripts/action_cable.coffee.erb
@@ -4,12 +4,13 @@
@ActionCable =
INTERNAL: <%= ActionCable::INTERNAL.to_json %>
- createConsumer: (url = @getConfig("url")) ->
+ createConsumer: (url) ->
+ url ?= @getConfig("url") ? @INTERNAL.default_mount_path
new ActionCable.Consumer @createWebSocketURL(url)
getConfig: (name) ->
element = document.head.querySelector("meta[name='action-cable-#{name}']")
- element?.getAttribute("content") ? '/cable'
+ element?.getAttribute("content")
createWebSocketURL: (url) ->
if url and not /^wss?:/i.test(url)
diff --git a/actioncable/app/assets/javascripts/action_cable/connection.coffee b/actioncable/app/assets/javascripts/action_cable/connection.coffee
index 25793ea3d3..3a139acf3a 100644
--- a/actioncable/app/assets/javascripts/action_cable/connection.coffee
+++ b/actioncable/app/assets/javascripts/action_cable/connection.coffee
@@ -1,3 +1,5 @@
+#= require ./connection_monitor
+
# Encapsulate the cable connection held by the consumer. This is an internal class not intended for direct user manipulation.
{message_types} = ActionCable.INTERNAL
@@ -6,11 +8,10 @@ class ActionCable.Connection
@reopenDelay: 500
constructor: (@consumer) ->
+ {@subscriptions} = @consumer
+ @monitor = new ActionCable.ConnectionMonitor this
send: (data) ->
- unless @isOpen()
- @open()
-
if @isOpen()
@webSocket.send(JSON.stringify(data))
true
@@ -18,14 +19,15 @@ class ActionCable.Connection
false
open: =>
- if @isAlive()
- ActionCable.log("Attemped to open WebSocket, but existing socket is #{@getState()}")
+ if @isActive()
+ ActionCable.log("Attempted to open WebSocket, but existing socket is #{@getState()}")
throw new Error("Existing connection must be closed before opening")
else
ActionCable.log("Opening WebSocket, current state is #{@getState()}")
@uninstallEventHandlers() if @webSocket?
@webSocket = new WebSocket(@consumer.url)
@installEventHandlers()
+ @monitor.start()
true
close: ->
@@ -33,7 +35,7 @@ class ActionCable.Connection
reopen: ->
ActionCable.log("Reopening WebSocket, current state is #{@getState()}")
- if @isAlive()
+ if @isActive()
try
@close()
catch error
@@ -47,10 +49,10 @@ class ActionCable.Connection
isOpen: ->
@isState("open")
- # Private
+ isActive: ->
+ @isState("open", "connecting")
- isAlive: ->
- @webSocket? and not @isState("closing", "closed")
+ # Private
isState: (states...) ->
@getState() in states
@@ -75,20 +77,20 @@ class ActionCable.Connection
{identifier, message, type} = JSON.parse(event.data)
switch type
when message_types.welcome
- @consumer.connectionMonitor.connected()
+ @monitor.recordConnect()
when message_types.ping
- @consumer.connectionMonitor.ping()
+ @monitor.recordPing()
when message_types.confirmation
- @consumer.subscriptions.notify(identifier, "connected")
+ @subscriptions.notify(identifier, "connected")
when message_types.rejection
- @consumer.subscriptions.reject(identifier)
+ @subscriptions.reject(identifier)
else
- @consumer.subscriptions.notify(identifier, "received", message)
+ @subscriptions.notify(identifier, "received", message)
open: ->
ActionCable.log("WebSocket onopen event")
@disconnected = false
- @consumer.subscriptions.reload()
+ @subscriptions.reload()
close: ->
ActionCable.log("WebSocket onclose event")
@@ -101,5 +103,5 @@ class ActionCable.Connection
disconnect: ->
return if @disconnected
@disconnected = true
- @consumer.connectionMonitor.disconnected()
- @consumer.subscriptions.notifyAll("disconnected")
+ @subscriptions.notifyAll("disconnected")
+ @monitor.recordDisconnect()
diff --git a/actioncable/app/assets/javascripts/action_cable/connection_monitor.coffee b/actioncable/app/assets/javascripts/action_cable/connection_monitor.coffee
index 904a426644..0cc675fa94 100644
--- a/actioncable/app/assets/javascripts/action_cable/connection_monitor.coffee
+++ b/actioncable/app/assets/javascripts/action_cable/connection_monitor.coffee
@@ -7,60 +7,69 @@ class ActionCable.ConnectionMonitor
@staleThreshold: 6 # Server::Connections::BEAT_INTERVAL * 2 (missed two pings)
- constructor: (@consumer) ->
- @start()
+ constructor: (@connection) ->
+ @reconnectAttempts = 0
- connected: ->
- @reset()
- @pingedAt = now()
- delete @disconnectedAt
- ActionCable.log("ConnectionMonitor connected")
+ start: ->
+ unless @isRunning()
+ @startedAt = now()
+ delete @stoppedAt
+ @startPolling()
+ document.addEventListener("visibilitychange", @visibilityDidChange)
+ ActionCable.log("ConnectionMonitor started. pollInterval = #{@getPollInterval()} ms")
- disconnected: ->
- @disconnectedAt = now()
- ActionCable.log("ConnectionMonitor disconnected")
+ stop: ->
+ if @isRunning()
+ @stoppedAt = now()
+ @stopPolling()
+ document.removeEventListener("visibilitychange", @visibilityDidChange)
+ ActionCable.log("ConnectionMonitor stopped")
+
+ isRunning: ->
+ @startedAt? and not @stoppedAt?
- ping: ->
+ recordPing: ->
@pingedAt = now()
- reset: ->
+ recordConnect: ->
@reconnectAttempts = 0
- @consumer.connection.isOpen()
+ @recordPing()
+ delete @disconnectedAt
+ ActionCable.log("ConnectionMonitor recorded connect")
- start: ->
- @reset()
- delete @stoppedAt
- @startedAt = now()
+ recordDisconnect: ->
+ @disconnectedAt = now()
+ ActionCable.log("ConnectionMonitor recorded disconnect")
+
+ # Private
+
+ startPolling: ->
+ @stopPolling()
@poll()
- document.addEventListener("visibilitychange", @visibilityDidChange)
- ActionCable.log("ConnectionMonitor started, pollInterval is #{@getInterval()}ms")
- stop: ->
- @stoppedAt = now()
- document.removeEventListener("visibilitychange", @visibilityDidChange)
- ActionCable.log("ConnectionMonitor stopped")
+ stopPolling: ->
+ clearTimeout(@pollTimeout)
poll: ->
- setTimeout =>
- unless @stoppedAt
- @reconnectIfStale()
- @poll()
- , @getInterval()
+ @pollTimeout = setTimeout =>
+ @reconnectIfStale()
+ @poll()
+ , @getPollInterval()
- getInterval: ->
+ getPollInterval: ->
{min, max} = @constructor.pollInterval
interval = 5 * Math.log(@reconnectAttempts + 1)
- clamp(interval, min, max) * 1000
+ Math.round(clamp(interval, min, max) * 1000)
reconnectIfStale: ->
if @connectionIsStale()
- ActionCable.log("ConnectionMonitor detected stale connection, reconnectAttempts = #{@reconnectAttempts}")
+ ActionCable.log("ConnectionMonitor detected stale connection. reconnectAttempts = #{@reconnectAttempts}, pollInterval = #{@getPollInterval()} ms, time disconnected = #{secondsSince(@disconnectedAt)} s, stale threshold = #{@constructor.staleThreshold} s")
@reconnectAttempts++
if @disconnectedRecently()
- ActionCable.log("ConnectionMonitor skipping reopen because recently disconnected at #{@disconnectedAt}")
+ ActionCable.log("ConnectionMonitor skipping reopening recent disconnect")
else
ActionCable.log("ConnectionMonitor reopening")
- @consumer.connection.reopen()
+ @connection.reopen()
connectionIsStale: ->
secondsSince(@pingedAt ? @startedAt) > @constructor.staleThreshold
@@ -71,9 +80,9 @@ class ActionCable.ConnectionMonitor
visibilityDidChange: =>
if document.visibilityState is "visible"
setTimeout =>
- if @connectionIsStale() or not @consumer.connection.isOpen()
- ActionCable.log("ConnectionMonitor reopening stale connection after visibilitychange to #{document.visibilityState}")
- @consumer.connection.reopen()
+ if @connectionIsStale() or not @connection.isOpen()
+ ActionCable.log("ConnectionMonitor reopening stale connection on visibilitychange. visbilityState = #{document.visibilityState}")
+ @connection.reopen()
, 200
now = ->
diff --git a/actioncable/app/assets/javascripts/action_cable/consumer.coffee b/actioncable/app/assets/javascripts/action_cable/consumer.coffee
index 717c0641a9..7aae1ed8ed 100644
--- a/actioncable/app/assets/javascripts/action_cable/consumer.coffee
+++ b/actioncable/app/assets/javascripts/action_cable/consumer.coffee
@@ -1,5 +1,4 @@
#= require ./connection
-#= require ./connection_monitor
#= require ./subscriptions
#= require ./subscription
@@ -19,7 +18,10 @@ class ActionCable.Consumer
constructor: (@url) ->
@subscriptions = new ActionCable.Subscriptions this
@connection = new ActionCable.Connection this
- @connectionMonitor = new ActionCable.ConnectionMonitor this
send: (data) ->
@connection.send(data)
+
+ ensureActiveConnection: ->
+ unless @connection.isActive()
+ @connection.open()
diff --git a/actioncable/app/assets/javascripts/action_cable/subscription.coffee b/actioncable/app/assets/javascripts/action_cable/subscription.coffee
index 339d676933..61a3fb1309 100644
--- a/actioncable/app/assets/javascripts/action_cable/subscription.coffee
+++ b/actioncable/app/assets/javascripts/action_cable/subscription.coffee
@@ -1,5 +1,5 @@
-# A new subscription is created through the ActionCable.Subscriptions instance available on the consumer.
-# It provides a number of callbacks and a method for calling remote procedure calls on the corresponding
+# A new subscription is created through the ActionCable.Subscriptions instance available on the consumer.
+# It provides a number of callbacks and a method for calling remote procedure calls on the corresponding
# Channel instance on the server side.
#
# An example demonstrates the basic functionality:
@@ -7,13 +7,13 @@
# App.appearance = App.cable.subscriptions.create "AppearanceChannel",
# connected: ->
# # Called once the subscription has been successfully completed
-#
+#
# appear: ->
# @perform 'appear', appearing_on: @appearingOn()
-#
+#
# away: ->
# @perform 'away'
-#
+#
# appearingOn: ->
# $('main').data 'appearing-on'
#
@@ -27,15 +27,15 @@
# def subscribed
# current_user.appear
# end
-#
+#
# def unsubscribed
# current_user.disappear
# end
-#
+#
# def appear(data)
# current_user.appear on: data['appearing_on']
# end
-#
+#
# def away
# current_user.away
# end
@@ -44,11 +44,9 @@
# The "AppearanceChannel" name is automatically mapped between the client-side subscription creation and the server-side Ruby class name.
# The AppearanceChannel#appear/away public methods are exposed automatically to client-side invocation through the @perform method.
class ActionCable.Subscription
- constructor: (@subscriptions, params = {}, mixin) ->
+ constructor: (@consumer, params = {}, mixin) ->
@identifier = JSON.stringify(params)
extend(this, mixin)
- @subscriptions.add(this)
- @consumer = @subscriptions.consumer
# Perform a channel action with the optional data passed as an attribute
perform: (action, data = {}) ->
@@ -59,7 +57,7 @@ class ActionCable.Subscription
@consumer.send(command: "message", identifier: @identifier, data: JSON.stringify(data))
unsubscribe: ->
- @subscriptions.remove(this)
+ @consumer.subscriptions.remove(this)
extend = (object, properties) ->
if properties?
diff --git a/actioncable/app/assets/javascripts/action_cable/subscriptions.coffee b/actioncable/app/assets/javascripts/action_cable/subscriptions.coffee
index 2443bca14a..aa052bf5d8 100644
--- a/actioncable/app/assets/javascripts/action_cable/subscriptions.coffee
+++ b/actioncable/app/assets/javascripts/action_cable/subscriptions.coffee
@@ -13,28 +13,33 @@ class ActionCable.Subscriptions
create: (channelName, mixin) ->
channel = channelName
params = if typeof channel is "object" then channel else {channel}
- new ActionCable.Subscription this, params, mixin
+ subscription = new ActionCable.Subscription @consumer, params, mixin
+ @add(subscription)
# Private
add: (subscription) ->
@subscriptions.push(subscription)
+ @consumer.ensureActiveConnection()
@notify(subscription, "initialized")
@sendCommand(subscription, "subscribe")
+ subscription
remove: (subscription) ->
@forget(subscription)
-
unless @findAll(subscription.identifier).length
@sendCommand(subscription, "unsubscribe")
+ subscription
reject: (identifier) ->
for subscription in @findAll(identifier)
@forget(subscription)
@notify(subscription, "rejected")
+ subscription
forget: (subscription) ->
@subscriptions = (s for s in @subscriptions when s isnt subscription)
+ subscription
findAll: (identifier) ->
s for s in @subscriptions when s.identifier is identifier
@@ -59,4 +64,3 @@ class ActionCable.Subscriptions
sendCommand: (subscription, command) ->
{identifier} = subscription
@consumer.send({command, identifier})
-
diff --git a/actioncable/lib/action_cable.rb b/actioncable/lib/action_cable.rb
index a8e4d1cb25..68a5fff3e7 100644
--- a/actioncable/lib/action_cable.rb
+++ b/actioncable/lib/action_cable.rb
@@ -34,7 +34,8 @@ module ActionCable
ping: 'ping'.freeze,
confirmation: 'confirm_subscription'.freeze,
rejection: 'reject_subscription'.freeze
- }
+ },
+ default_mount_path: '/cable'.freeze
}
# Singleton instance of the server
diff --git a/actioncable/lib/action_cable/connection/client_socket.rb b/actioncable/lib/action_cable/connection/client_socket.rb
index 9e4dbcd6e6..7d6de78582 100644
--- a/actioncable/lib/action_cable/connection/client_socket.rb
+++ b/actioncable/lib/action_cable/connection/client_socket.rb
@@ -71,6 +71,8 @@ module ActionCable
def write(data)
@stream.write(data)
+ rescue => e
+ emit_error e.message
end
def transmit(message)
diff --git a/actioncable/lib/action_cable/connection/faye_client_socket.rb b/actioncable/lib/action_cable/connection/faye_client_socket.rb
index c9139b6858..47d09a9e14 100644
--- a/actioncable/lib/action_cable/connection/faye_client_socket.rb
+++ b/actioncable/lib/action_cable/connection/faye_client_socket.rb
@@ -36,6 +36,7 @@ module ActionCable
@faye.on(:open) { |event| @event_target.on_open }
@faye.on(:message) { |event| @event_target.on_message(event.data) }
@faye.on(:close) { |event| @event_target.on_close(event.reason, event.code) }
+ @faye.on(:error) { |event| @event_target.on_error(event.message) }
end
end
end
diff --git a/actioncable/lib/action_cable/connection/stream.rb b/actioncable/lib/action_cable/connection/stream.rb
index 2d97b28c09..0cf59091bc 100644
--- a/actioncable/lib/action_cable/connection/stream.rb
+++ b/actioncable/lib/action_cable/connection/stream.rb
@@ -29,7 +29,7 @@ module ActionCable
def write(data)
return @rack_hijack_io.write(data) if @rack_hijack_io
return @stream_send.call(data) if @stream_send
- rescue EOFError
+ rescue EOFError, Errno::ECONNRESET
@socket_object.client_gone
end
diff --git a/actioncable/lib/action_cable/engine.rb b/actioncable/lib/action_cable/engine.rb
index c90aadaf2c..7dc541d00c 100644
--- a/actioncable/lib/action_cable/engine.rb
+++ b/actioncable/lib/action_cable/engine.rb
@@ -6,7 +6,7 @@ require "active_support/core_ext/hash/indifferent_access"
module ActionCable
class Railtie < Rails::Engine # :nodoc:
config.action_cable = ActiveSupport::OrderedOptions.new
- config.action_cable.mount_path = '/cable'
+ config.action_cable.mount_path = ActionCable::INTERNAL[:default_mount_path]
config.eager_load_namespaces << ActionCable
diff --git a/actioncable/lib/action_cable/subscription_adapter/evented_redis.rb b/actioncable/lib/action_cable/subscription_adapter/evented_redis.rb
index e6c862959b..256876cf30 100644
--- a/actioncable/lib/action_cable/subscription_adapter/evented_redis.rb
+++ b/actioncable/lib/action_cable/subscription_adapter/evented_redis.rb
@@ -51,7 +51,7 @@ module ActionCable
@redis_connection_for_subscriptions || @server.mutex.synchronize do
@redis_connection_for_subscriptions ||= self.class.em_redis_connector.call(@server.config.cable).tap do |redis|
redis.on(:reconnect_failed) do
- @logger.info "[ActionCable] Redis reconnect failed."
+ @logger.error "[ActionCable] Redis reconnect failed."
end
end
end
diff --git a/actioncable/lib/rails/generators/channel/channel_generator.rb b/actioncable/lib/rails/generators/channel/channel_generator.rb
index 6debe40c91..d89ab45816 100644
--- a/actioncable/lib/rails/generators/channel/channel_generator.rb
+++ b/actioncable/lib/rails/generators/channel/channel_generator.rb
@@ -21,7 +21,7 @@ module Rails
protected
def file_name
- @_file_name ||= super.gsub(/\_channel/i, '')
+ @_file_name ||= super.gsub(/_channel/i, '')
end
# FIXME: Change these files to symlinks once RubyGems 2.5.0 is required.
diff --git a/actioncable/test/connection/client_socket_test.rb b/actioncable/test/connection/client_socket_test.rb
new file mode 100644
index 0000000000..dd730e348f
--- /dev/null
+++ b/actioncable/test/connection/client_socket_test.rb
@@ -0,0 +1,65 @@
+require 'test_helper'
+require 'stubs/test_server'
+
+class ActionCable::Connection::StreamTest < ActionCable::TestCase
+ class Connection < ActionCable::Connection::Base
+ attr_reader :websocket, :subscriptions, :message_buffer, :connected
+ attr_reader :errors
+
+ def initialize(*)
+ super
+ @errors = []
+ end
+
+ def connect
+ @connected = true
+ end
+
+ def disconnect
+ @connected = false
+ end
+
+ def send_async(method, *args)
+ send method, *args
+ end
+
+ def on_error(message)
+ @errors << message
+ end
+ end
+
+ setup do
+ @server = TestServer.new
+ @server.config.allowed_request_origins = %w( http://rubyonrails.com )
+ end
+
+ test 'delegate socket errors to on_error handler' do
+ skip if ENV['FAYE'].present?
+
+ run_in_eventmachine do
+ connection = open_connection
+
+ # Internal hax = :(
+ client = connection.websocket.send(:websocket)
+ client.instance_variable_get('@stream').expects(:write).raises('foo')
+ client.expects(:client_gone).never
+
+ client.write('boo')
+ assert_equal %w[ foo ], connection.errors
+ end
+ end
+
+ private
+ def open_connection
+ env = Rack::MockRequest.env_for '/test',
+ 'HTTP_CONNECTION' => 'upgrade', 'HTTP_UPGRADE' => 'websocket',
+ 'HTTP_HOST' => 'localhost', 'HTTP_ORIGIN' => 'http://rubyonrails.com'
+ env['rack.hijack'] = -> { env['rack.hijack_io'] = StringIO.new }
+
+ Connection.new(@server, env).tap do |connection|
+ connection.process
+ connection.send :handle_open
+ assert connection.connected
+ end
+ end
+end
diff --git a/actioncable/test/connection/stream_test.rb b/actioncable/test/connection/stream_test.rb
new file mode 100644
index 0000000000..d5aad63648
--- /dev/null
+++ b/actioncable/test/connection/stream_test.rb
@@ -0,0 +1,67 @@
+require 'test_helper'
+require 'stubs/test_server'
+
+class ActionCable::Connection::StreamTest < ActionCable::TestCase
+ class Connection < ActionCable::Connection::Base
+ attr_reader :websocket, :subscriptions, :message_buffer, :connected
+ attr_reader :errors
+
+ def initialize(*)
+ super
+ @errors = []
+ end
+
+ def connect
+ @connected = true
+ end
+
+ def disconnect
+ @connected = false
+ end
+
+ def send_async(method, *args)
+ send method, *args
+ end
+
+ def on_error(message)
+ @errors << message
+ end
+ end
+
+ setup do
+ @server = TestServer.new
+ @server.config.allowed_request_origins = %w( http://rubyonrails.com )
+ end
+
+ [ EOFError, Errno::ECONNRESET ].each do |closed_exception|
+ test "closes socket on #{closed_exception}" do
+ skip if ENV['FAYE'].present?
+
+ run_in_eventmachine do
+ connection = open_connection
+
+ # Internal hax = :(
+ client = connection.websocket.send(:websocket)
+ client.instance_variable_get('@stream').instance_variable_get('@rack_hijack_io').expects(:write).raises(closed_exception, 'foo')
+ client.expects(:client_gone)
+
+ client.write('boo')
+ assert_equal [], connection.errors
+ end
+ end
+ end
+
+ private
+ def open_connection
+ env = Rack::MockRequest.env_for '/test',
+ 'HTTP_CONNECTION' => 'upgrade', 'HTTP_UPGRADE' => 'websocket',
+ 'HTTP_HOST' => 'localhost', 'HTTP_ORIGIN' => 'http://rubyonrails.com'
+ env['rack.hijack'] = -> { env['rack.hijack_io'] = StringIO.new }
+
+ Connection.new(@server, env).tap do |connection|
+ connection.process
+ connection.send :handle_open
+ assert connection.connected
+ end
+ end
+end
diff --git a/actioncable/test/subscription_adapter/postgresql_test.rb b/actioncable/test/subscription_adapter/postgresql_test.rb
index 64c632b0cd..3b4fadbb2a 100644
--- a/actioncable/test/subscription_adapter/postgresql_test.rb
+++ b/actioncable/test/subscription_adapter/postgresql_test.rb
@@ -15,8 +15,15 @@ class PostgresqlAdapterTest < ActionCable::TestCase
local_config = ARTest.config['arunit']
database_config.update local_config if local_config
end
+
ActiveRecord::Base.establish_connection database_config
+ begin
+ ActiveRecord::Base.connection
+ rescue
+ skip "Couldn't connect to PostgreSQL: #{database_config.inspect}"
+ end
+
super
end
diff --git a/actionmailer/lib/action_mailer/base.rb b/actionmailer/lib/action_mailer/base.rb
index 559cd06d91..a223cf82a1 100644
--- a/actionmailer/lib/action_mailer/base.rb
+++ b/actionmailer/lib/action_mailer/base.rb
@@ -289,7 +289,7 @@ module ActionMailer
#
# Note that the proc is evaluated right at the start of the mail message generation, so if you
# set something in the default using a proc, and then set the same thing inside of your
- # mailer method, it will get over written by the mailer method.
+ # mailer method, it will get overwritten by the mailer method.
#
# It is also possible to set these default options that will be used in all mailers through
# the <tt>default_options=</tt> configuration in <tt>config/application.rb</tt>:
diff --git a/actionmailer/lib/action_mailer/railtie.rb b/actionmailer/lib/action_mailer/railtie.rb
index 215d0199af..a727ed38e9 100644
--- a/actionmailer/lib/action_mailer/railtie.rb
+++ b/actionmailer/lib/action_mailer/railtie.rb
@@ -45,9 +45,9 @@ module ActionMailer
register_observers(options.delete(:observers))
options.each { |k,v| send("#{k}=", v) }
-
- ActionDispatch::IntegrationTest.send :include, ActionMailer::TestCase::ClearTestDeliveries
end
+
+ ActiveSupport.on_load(:action_dispatch_integration_test) { include ActionMailer::TestCase::ClearTestDeliveries }
end
initializer "action_mailer.compile_config_methods" do
diff --git a/actionmailer/lib/rails/generators/mailer/mailer_generator.rb b/actionmailer/lib/rails/generators/mailer/mailer_generator.rb
index 5a5c9d32bb..f86d43be61 100644
--- a/actionmailer/lib/rails/generators/mailer/mailer_generator.rb
+++ b/actionmailer/lib/rails/generators/mailer/mailer_generator.rb
@@ -9,13 +9,19 @@ module Rails
def create_mailer_file
template "mailer.rb", File.join('app/mailers', class_path, "#{file_name}_mailer.rb")
+
+ in_root do
+ if self.behavior == :invoke && !File.exist?('app/mailers/application_mailer.rb')
+ template 'application_mailer.rb', 'app/mailers/application_mailer.rb'
+ end
+ end
end
hook_for :template_engine, :test_framework
protected
def file_name
- @_file_name ||= super.gsub(/\_mailer/i, '')
+ @_file_name ||= super.gsub(/_mailer/i, '')
end
end
end
diff --git a/actionmailer/lib/rails/generators/mailer/templates/application_mailer.rb b/actionmailer/lib/rails/generators/mailer/templates/application_mailer.rb
new file mode 100644
index 0000000000..286b2239d1
--- /dev/null
+++ b/actionmailer/lib/rails/generators/mailer/templates/application_mailer.rb
@@ -0,0 +1,4 @@
+class ApplicationMailer < ActionMailer::Base
+ default from: 'from@example.com'
+ layout 'mailer'
+end
diff --git a/actionpack/CHANGELOG.md b/actionpack/CHANGELOG.md
index 6b73b29ace..e8a29f5182 100644
--- a/actionpack/CHANGELOG.md
+++ b/actionpack/CHANGELOG.md
@@ -1,3 +1,25 @@
+* When a `respond_to` collector with a block doesn't have a response, then
+ a `:no_content` response should be rendered. This brings the default
+ rendering behavior introduced by https://github.com/rails/rails/issues/19036
+ to controller methods employing `respond_to`.
+
+ *Justin Coyne*
+
+* Add `ActionController::Parameters#dig` on Ruby 2.3 and greater, which
+ behaves the same as `Hash#dig`.
+
+ *Sean Griffin*
+
+* Add request headers in the payload of the `start_processing.action_controller`
+ and `process_action.action_controller` notifications.
+
+ *Gareth du Plooy*
+
+* Add `action_dispatch_integration_test` load hook. The hook can be used to
+ extend `ActionDispatch::IntegrationTest` once it has been loaded.
+
+ *Yuichiro Kaneko*
+
* Update default rendering policies when the controller action did
not explicitly indicate a response.
@@ -8,10 +30,10 @@
First, if a template exists for the controller action, it is rendered.
This template lookup takes into account the action name, locales, format,
- variant, template handlers, etc. (see +render+ for details).
+ variant, template handlers, etc. (see `render` for details).
Second, if other templates exist for the controller action but is not in
- the right format (or variant, etc.), an <tt>ActionController::UnknownFormat</tt>
+ the right format (or variant, etc.), an `ActionController::UnknownFormat`
is raised. The list of available templates is assumed to be a complete
enumeration of all the possible formats (or variants, etc.); that is,
having only HTML and JSON templates indicate that the controller action is
@@ -20,7 +42,7 @@
Third, if the current request is an "interactive" browser request (the user
navigated here by entering the URL in the address bar, submiting a form,
clicking on a link, etc. as opposed to an XHR or non-browser API request),
- <tt>ActionView::UnknownFormat</tt> is raised to display a helpful error
+ `ActionView::UnknownFormat` is raised to display a helpful error
message.
Finally, it falls back to the same "204 No Content" behavior as API controllers.
@@ -29,7 +51,7 @@
## Rails 5.0.0.beta3 (February 24, 2016) ##
-* Add application/gzip as a default mime type.
+* Add "application/gzip" as a default mime type.
*Mehmet Emin İNAÇ*
@@ -80,7 +102,7 @@
*Kasper Timm Hansen*
-* Add image/svg+xml as a default mime type.
+* Add "image/svg+xml" as a default mime type.
*DHH*
@@ -93,7 +115,7 @@
See #18902.
- *Anton Davydov* & *Vipul A M*
+ *Anton Davydov*, *Vipul A M*
* Response etags to always be weak: Prefixes 'W/' to value returned by
`ActionDispatch::Http::Cache::Response#etag=`, such that etags set in
@@ -125,11 +147,7 @@
* Add option for per-form CSRF tokens.
- *Greg Ose & Ben Toews*
-
-* Add tests and documentation for `ActionController::Renderers::use_renderers`.
-
- *Benjamin Fleischer*
+ *Greg Ose*, *Ben Toews*
* Fix `ActionController::Parameters#convert_parameters_to_hashes` to return filtered
or unfiltered values based on from where it is called, `to_h` or `to_unsafe_h`
diff --git a/actionpack/actionpack.gemspec b/actionpack/actionpack.gemspec
index 28d8bc3091..66300754e3 100644
--- a/actionpack/actionpack.gemspec
+++ b/actionpack/actionpack.gemspec
@@ -13,7 +13,7 @@ Gem::Specification.new do |s|
s.author = 'David Heinemeier Hansson'
s.email = 'david@loudthinking.com'
- s.homepage = 'http://www.rubyonrails.org'
+ s.homepage = 'http://rubyonrails.org'
s.files = Dir['CHANGELOG.md', 'README.rdoc', 'MIT-LICENSE', 'lib/**/*']
s.require_path = 'lib'
diff --git a/actionpack/lib/abstract_controller/base.rb b/actionpack/lib/abstract_controller/base.rb
index 8edea0f52b..16dec31938 100644
--- a/actionpack/lib/abstract_controller/base.rb
+++ b/actionpack/lib/abstract_controller/base.rb
@@ -1,13 +1,11 @@
require 'erubis'
+require 'abstract_controller/error'
require 'active_support/configurable'
require 'active_support/descendants_tracker'
require 'active_support/core_ext/module/anonymous'
require 'active_support/core_ext/module/attr_internal'
module AbstractController
- class Error < StandardError #:nodoc:
- end
-
# Raised when a non-existing controller action is triggered.
class ActionNotFound < StandardError
end
diff --git a/actionpack/lib/abstract_controller/error.rb b/actionpack/lib/abstract_controller/error.rb
new file mode 100644
index 0000000000..7fafce4dd4
--- /dev/null
+++ b/actionpack/lib/abstract_controller/error.rb
@@ -0,0 +1,4 @@
+module AbstractController
+ class Error < StandardError #:nodoc:
+ end
+end
diff --git a/actionpack/lib/abstract_controller/helpers.rb b/actionpack/lib/abstract_controller/helpers.rb
index d84c238a62..ab4355296b 100644
--- a/actionpack/lib/abstract_controller/helpers.rb
+++ b/actionpack/lib/abstract_controller/helpers.rb
@@ -38,7 +38,8 @@ module AbstractController
end
# Declare a controller method as a helper. For example, the following
- # makes the +current_user+ controller method available to the view:
+ # makes the +current_user+ and +logged_in?+ controller methods available
+ # to the view:
# class ApplicationController < ActionController::Base
# helper_method :current_user, :logged_in?
#
diff --git a/actionpack/lib/abstract_controller/rendering.rb b/actionpack/lib/abstract_controller/rendering.rb
index e765d73ce4..9f192c54f7 100644
--- a/actionpack/lib/abstract_controller/rendering.rb
+++ b/actionpack/lib/abstract_controller/rendering.rb
@@ -1,3 +1,4 @@
+require 'abstract_controller/error'
require 'active_support/concern'
require 'active_support/core_ext/class/attribute'
require 'action_view'
diff --git a/actionpack/lib/action_controller/metal/conditional_get.rb b/actionpack/lib/action_controller/metal/conditional_get.rb
index e2535d024c..35befc05e1 100644
--- a/actionpack/lib/action_controller/metal/conditional_get.rb
+++ b/actionpack/lib/action_controller/metal/conditional_get.rb
@@ -222,12 +222,10 @@ module ActionController
# * +public+: By default, HTTP responses are private, cached only on the
# user's web browser. To allow proxies to cache the response, set +true+ to
# indicate that they can serve the cached response to all users.
- #
- # * +version+: the version passed as a key for the cache.
- def http_cache_forever(public: false, version: 'v1')
+ def http_cache_forever(public: false)
expires_in 100.years, public: public
- yield if stale?(etag: "#{version}-#{request.fullpath}",
+ yield if stale?(etag: request.fullpath,
last_modified: Time.new(2011, 1, 1).utc,
public: public)
end
diff --git a/actionpack/lib/action_controller/metal/instrumentation.rb b/actionpack/lib/action_controller/metal/instrumentation.rb
index bf74b39ac4..885ea3fefd 100644
--- a/actionpack/lib/action_controller/metal/instrumentation.rb
+++ b/actionpack/lib/action_controller/metal/instrumentation.rb
@@ -19,6 +19,7 @@ module ActionController
:controller => self.class.name,
:action => self.action_name,
:params => request.filtered_parameters,
+ :headers => request.headers,
:format => request.format.ref,
:method => request.request_method,
:path => request.fullpath
diff --git a/actionpack/lib/action_controller/metal/mime_responds.rb b/actionpack/lib/action_controller/metal/mime_responds.rb
index 173a14a1d2..2e89af1a5e 100644
--- a/actionpack/lib/action_controller/metal/mime_responds.rb
+++ b/actionpack/lib/action_controller/metal/mime_responds.rb
@@ -198,7 +198,7 @@ module ActionController #:nodoc:
_process_format(format)
_set_rendered_content_type format
response = collector.response
- response ? response.call : render({})
+ response.call if response
else
raise ActionController::UnknownFormat
end
diff --git a/actionpack/lib/action_controller/metal/redirecting.rb b/actionpack/lib/action_controller/metal/redirecting.rb
index b13ba06962..3c7cc15627 100644
--- a/actionpack/lib/action_controller/metal/redirecting.rb
+++ b/actionpack/lib/action_controller/metal/redirecting.rb
@@ -84,7 +84,7 @@ module ActionController
# redirect_back fallback_location: proc { edit_post_url(@post) }
#
# All options that can be passed to <tt>redirect_to</tt> are accepted as
- # options and the behavior is indetical.
+ # options and the behavior is identical.
def redirect_back(fallback_location:, **args)
if referer = request.headers["Referer"]
redirect_to referer, **args
diff --git a/actionpack/lib/action_controller/metal/rescue.rb b/actionpack/lib/action_controller/metal/rescue.rb
index 81b9a7b9ed..0621a7368c 100644
--- a/actionpack/lib/action_controller/metal/rescue.rb
+++ b/actionpack/lib/action_controller/metal/rescue.rb
@@ -7,8 +7,12 @@ module ActionController #:nodoc:
include ActiveSupport::Rescuable
def rescue_with_handler(exception)
- if exception.cause && handler_for_rescue(exception.cause)
- exception = exception.cause
+ if exception.cause
+ handler_index = index_of_handler_for_rescue(exception) || Float::INFINITY
+ cause_handler_index = index_of_handler_for_rescue(exception.cause)
+ if cause_handler_index && cause_handler_index <= handler_index
+ exception = exception.cause
+ end
end
super(exception)
end
diff --git a/actionpack/lib/action_controller/metal/strong_parameters.rb b/actionpack/lib/action_controller/metal/strong_parameters.rb
index a01110d474..76e3b4d25a 100644
--- a/actionpack/lib/action_controller/metal/strong_parameters.rb
+++ b/actionpack/lib/action_controller/metal/strong_parameters.rb
@@ -430,6 +430,21 @@ module ActionController
)
end
+ if Hash.method_defined?(:dig)
+ # Extracts the nested parameter from the given +keys+ by calling +dig+
+ # at each step. Returns +nil+ if any intermediate step is +nil+.
+ #
+ # params = ActionController::Parameters.new(foo: { bar: { baz: 1 } })
+ # params.dig(:foo, :bar, :baz) # => 1
+ # params.dig(:foo, :zot, :xyz) # => nil
+ #
+ # params2 = ActionController::Parameters.new(foo: [10, 11, 12])
+ # params2.dig(:foo, 1) # => 11
+ def dig(*keys)
+ convert_value_to_parameters(@parameters.dig(*keys))
+ end
+ end
+
# Returns a new <tt>ActionController::Parameters</tt> instance that
# includes only the given +keys+. If the given +keys+
# don't exist, returns an empty hash.
@@ -799,7 +814,8 @@ module ActionController
# end
#
# In order to use <tt>accepts_nested_attributes_for</tt> with Strong \Parameters, you
- # will need to specify which nested attributes should be whitelisted.
+ # will need to specify which nested attributes should be whitelisted. You might want
+ # to allow +:id+ and +:_destroy+, see ActiveRecord::NestedAttributes for more information.
#
# class Person
# has_many :pets
@@ -819,7 +835,7 @@ module ActionController
# # It's mandatory to specify the nested attributes that should be whitelisted.
# # If you use `permit` with just the key that points to the nested attributes hash,
# # it will return an empty hash.
- # params.require(:person).permit(:name, :age, pets_attributes: [ :name, :category ])
+ # params.require(:person).permit(:name, :age, pets_attributes: [ :id, :name, :category ])
# end
# end
#
diff --git a/actionpack/lib/action_dispatch/http/request.rb b/actionpack/lib/action_dispatch/http/request.rb
index 316a9f08b7..b0ed681623 100644
--- a/actionpack/lib/action_dispatch/http/request.rb
+++ b/actionpack/lib/action_dispatch/http/request.rb
@@ -337,7 +337,6 @@ module ActionDispatch
else
self.session = {}
end
- self.flash = nil
end
def session=(session) #:nodoc:
diff --git a/actionpack/lib/action_dispatch/middleware/flash.rb b/actionpack/lib/action_dispatch/middleware/flash.rb
index c51dcd542a..06038af571 100644
--- a/actionpack/lib/action_dispatch/middleware/flash.rb
+++ b/actionpack/lib/action_dispatch/middleware/flash.rb
@@ -70,6 +70,11 @@ module ActionDispatch
session.delete('flash')
end
end
+
+ def reset_session # :nodoc
+ super
+ self.flash = nil
+ end
end
class FlashNow #:nodoc:
diff --git a/actionpack/lib/action_dispatch/routing.rb b/actionpack/lib/action_dispatch/routing.rb
index dcf800b215..79d2f1f13c 100644
--- a/actionpack/lib/action_dispatch/routing.rb
+++ b/actionpack/lib/action_dispatch/routing.rb
@@ -73,14 +73,14 @@ module ActionDispatch
# get 'post/:id' => 'posts#show'
# post 'post/:id' => 'posts#create_comment'
#
+ # Now, if you POST to <tt>/posts/:id</tt>, it will route to the <tt>create_comment</tt> action. A GET on the same
+ # URL will route to the <tt>show</tt> action.
+ #
# If your route needs to respond to more than one HTTP method (or all methods) then using the
# <tt>:via</tt> option on <tt>match</tt> is preferable.
#
# match 'post/:id' => 'posts#show', via: [:get, :post]
#
- # Now, if you POST to <tt>/posts/:id</tt>, it will route to the <tt>create_comment</tt> action. A GET on the same
- # URL will route to the <tt>show</tt> action.
- #
# == Named routes
#
# Routes can be named by passing an <tt>:as</tt> option,
diff --git a/actionpack/lib/action_dispatch/testing/integration.rb b/actionpack/lib/action_dispatch/testing/integration.rb
index f4534b4173..60c562d7cd 100644
--- a/actionpack/lib/action_dispatch/testing/integration.rb
+++ b/actionpack/lib/action_dispatch/testing/integration.rb
@@ -735,34 +735,49 @@ module ActionDispatch
# Consult the Rails Testing Guide for more.
class IntegrationTest < ActiveSupport::TestCase
- include Integration::Runner
- include ActionController::TemplateAssertions
- include ActionDispatch::Routing::UrlFor
+ module UrlOptions
+ extend ActiveSupport::Concern
+ def url_options
+ integration_session.url_options
+ end
+ end
- @@app = nil
+ module Behavior
+ extend ActiveSupport::Concern
- def self.app
- @@app || ActionDispatch.test_app
- end
+ include Integration::Runner
+ include ActionController::TemplateAssertions
- def self.app=(app)
- @@app = app
- end
+ included do
+ include ActionDispatch::Routing::UrlFor
+ include UrlOptions # don't let UrlFor override the url_options method
+ ActiveSupport.run_load_hooks(:action_dispatch_integration_test, self)
+ @@app = nil
+ end
- def app
- super || self.class.app
- end
+ module ClassMethods
+ def app
+ defined?(@@app) ? @@app : ActionDispatch.test_app
+ end
- def url_options
- integration_session.url_options
- end
+ def app=(app)
+ @@app = app
+ end
- def document_root_element
- html_document.root
- end
+ def register_encoder(*args)
+ Integration::Session::RequestEncoder.register_encoder(*args)
+ end
+ end
- def self.register_encoder(*args)
- Integration::Session::RequestEncoder.register_encoder(*args)
+ def app
+ super || self.class.app
+ end
+
+ def document_root_element
+ html_document.root
+ end
end
+
+ include Behavior
end
end
diff --git a/actionpack/test/controller/log_subscriber_test.rb b/actionpack/test/controller/log_subscriber_test.rb
index 6ae33be3c8..57cf2dafdf 100644
--- a/actionpack/test/controller/log_subscriber_test.rb
+++ b/actionpack/test/controller/log_subscriber_test.rb
@@ -183,6 +183,12 @@ class ACLogSubscriberTest < ActionController::TestCase
assert_equal "test_value", @controller.last_payload[:test_key]
end
+ def test_process_action_headers
+ get :show
+ wait
+ assert_equal "Rails Testing", @controller.last_payload[:headers]['User-Agent']
+ end
+
def test_process_action_with_filter_parameters
@request.env["action_dispatch.parameter_filter"] = [:lifo, :amount]
diff --git a/actionpack/test/controller/mime/respond_to_test.rb b/actionpack/test/controller/mime/respond_to_test.rb
index d0c7b2e06a..993f4001de 100644
--- a/actionpack/test/controller/mime/respond_to_test.rb
+++ b/actionpack/test/controller/mime/respond_to_test.rb
@@ -74,6 +74,14 @@ class RespondToController < ActionController::Base
end
end
+ def missing_templates
+ respond_to do |type|
+ # This test requires a block that is empty
+ type.json { }
+ type.xml
+ end
+ end
+
def using_defaults_with_type_list
respond_to(:html, :xml)
end
@@ -624,6 +632,13 @@ class RespondToControllerTest < ActionController::TestCase
end
end
+ def test_missing_templates
+ get :missing_templates, format: :json
+ assert_response :no_content
+ get :missing_templates, format: :xml
+ assert_response :no_content
+ end
+
def test_invalid_variant
assert_raises(ActionController::UnknownFormat) do
get :variant_with_implicit_template_rendering, params: { v: :invalid }
diff --git a/actionpack/test/controller/parameters/accessors_test.rb b/actionpack/test/controller/parameters/accessors_test.rb
index cea265f9ab..17c62dc3fe 100644
--- a/actionpack/test/controller/parameters/accessors_test.rb
+++ b/actionpack/test/controller/parameters/accessors_test.rb
@@ -194,4 +194,24 @@ class ParametersAccessorsTest < ActiveSupport::TestCase
assert_match(/permitted: true/, @params.inspect)
end
+
+ if Hash.method_defined?(:dig)
+ test "#dig delegates the dig method to its values" do
+ assert_equal "David", @params.dig(:person, :name, :first)
+ assert_equal "Chicago", @params.dig(:person, :addresses, 0, :city)
+ end
+
+ test "#dig converts hashes to parameters" do
+ assert_kind_of ActionController::Parameters, @params.dig(:person)
+ assert_kind_of ActionController::Parameters, @params.dig(:person, :addresses, 0)
+ assert @params.dig(:person, :addresses).all? do |value|
+ value.is_a?(ActionController::Parameters)
+ end
+ end
+ else
+ test "ActionController::Parameters does not respond to #dig on Ruby 2.2" do
+ assert_not ActionController::Parameters.method_defined?(:dig)
+ assert_not @params.respond_to?(:dig)
+ end
+ end
end
diff --git a/actionpack/test/controller/render_test.rb b/actionpack/test/controller/render_test.rb
index b7f3e121fd..82fc8b0f8a 100644
--- a/actionpack/test/controller/render_test.rb
+++ b/actionpack/test/controller/render_test.rb
@@ -703,7 +703,7 @@ end
class HttpCacheForeverTest < ActionController::TestCase
class HttpCacheForeverController < ActionController::Base
def cache_me_forever
- http_cache_forever(public: params[:public], version: params[:version] || 'v1') do
+ http_cache_forever(public: params[:public]) do
render plain: 'hello'
end
end
@@ -742,13 +742,5 @@ class HttpCacheForeverTest < ActionController::TestCase
assert_response :not_modified
@request.if_modified_since = @response.headers['Last-Modified']
@request.if_none_match = @response.etag
-
- get :cache_me_forever, params: {version: 'v2'}
- assert_response :success
- @request.if_modified_since = @response.headers['Last-Modified']
- @request.if_none_match = @response.etag
-
- get :cache_me_forever, params: {version: 'v2'}
- assert_response :not_modified
end
end
diff --git a/actionpack/test/controller/rescue_test.rb b/actionpack/test/controller/rescue_test.rb
index f42bef883f..ed78f859ce 100644
--- a/actionpack/test/controller/rescue_test.rb
+++ b/actionpack/test/controller/rescue_test.rb
@@ -147,6 +147,24 @@ class RescueController < ActionController::Base
end
end
+ def exception_with_more_specific_handler_for_wrapper
+ raise RecordInvalid
+ rescue
+ raise NotAuthorized
+ end
+
+ def exception_with_more_specific_handler_for_cause
+ raise NotAuthorized
+ rescue
+ raise RecordInvalid
+ end
+
+ def exception_with_no_handler_for_wrapper
+ raise RecordInvalid
+ rescue
+ raise RangeError
+ end
+
protected
def deny_access
head :forbidden
@@ -301,6 +319,21 @@ class RescueControllerTest < ActionController::TestCase
get :resource_unavailable_raise_as_string
assert_equal "RescueController::ResourceUnavailableToRescueAsString", @response.body
end
+
+ test 'rescue when wrapper has more specific handler than cause' do
+ get :exception_with_more_specific_handler_for_wrapper
+ assert_response :unprocessable_entity
+ end
+
+ test 'rescue when cause has more specific handler than wrapper' do
+ get :exception_with_more_specific_handler_for_cause
+ assert_response :unprocessable_entity
+ end
+
+ test 'rescue when cause has handler, but wrapper doesnt' do
+ get :exception_with_no_handler_for_wrapper
+ assert_response :unprocessable_entity
+ end
end
class RescueTest < ActionDispatch::IntegrationTest
diff --git a/actionview/CHANGELOG.md b/actionview/CHANGELOG.md
index c15fb4304d..ecc1e764a5 100644
--- a/actionview/CHANGELOG.md
+++ b/actionview/CHANGELOG.md
@@ -44,7 +44,7 @@
* Create a new `ActiveSupport::SafeBuffer` instance when `content_for` is flushed.
- Fixes #19890
+ Fixes #19890.
*Yoong Kang Lim*
diff --git a/actionview/actionview.gemspec b/actionview/actionview.gemspec
index 612e94021d..8b0e031dee 100644
--- a/actionview/actionview.gemspec
+++ b/actionview/actionview.gemspec
@@ -9,11 +9,11 @@ Gem::Specification.new do |s|
s.required_ruby_version = '>= 2.2.2'
- s.license = 'MIT'
+ s.license = 'MIT'
- s.author = 'David Heinemeier Hansson'
- s.email = 'david@loudthinking.com'
- s.homepage = 'http://www.rubyonrails.org'
+ s.author = 'David Heinemeier Hansson'
+ s.email = 'david@loudthinking.com'
+ s.homepage = 'http://rubyonrails.org'
s.files = Dir['CHANGELOG.md', 'README.rdoc', 'MIT-LICENSE', 'lib/**/*']
s.require_path = 'lib'
diff --git a/actionview/lib/action_view/helpers/atom_feed_helper.rb b/actionview/lib/action_view/helpers/atom_feed_helper.rb
index dba70e284e..c875f5870f 100644
--- a/actionview/lib/action_view/helpers/atom_feed_helper.rb
+++ b/actionview/lib/action_view/helpers/atom_feed_helper.rb
@@ -132,7 +132,7 @@ module ActionView
end
private
- # Delegate to xml builder, first wrapping the element in a xhtml
+ # Delegate to xml builder, first wrapping the element in an xhtml
# namespaced div element if the method and arguments indicate
# that an xhtml_block? is desired.
def method_missing(method, *arguments, &block)
diff --git a/actionview/lib/action_view/helpers/form_helper.rb b/actionview/lib/action_view/helpers/form_helper.rb
index c1015ffe89..e91b3443c5 100644
--- a/actionview/lib/action_view/helpers/form_helper.rb
+++ b/actionview/lib/action_view/helpers/form_helper.rb
@@ -1922,8 +1922,6 @@ module ActionView
@object_name.to_s.humanize
end
- model = model.downcase
-
defaults = []
defaults << :"helpers.submit.#{object_name}.#{key}"
defaults << :"helpers.submit.#{key}"
diff --git a/actionview/lib/action_view/helpers/url_helper.rb b/actionview/lib/action_view/helpers/url_helper.rb
index ab67923376..11c7daf4da 100644
--- a/actionview/lib/action_view/helpers/url_helper.rb
+++ b/actionview/lib/action_view/helpers/url_helper.rb
@@ -302,7 +302,7 @@ module ActionView
params = html_options.delete('params')
method = html_options.delete('method').to_s
- method_tag = BUTTON_TAG_METHOD_VERBS.include?(method) ? method_tag(method) : ''.html_safe
+ method_tag = BUTTON_TAG_METHOD_VERBS.include?(method) ? method_tag(method) : ''.freeze.html_safe
form_method = method == 'get' ? 'get' : 'post'
form_options = html_options.delete('form') || {}
@@ -315,7 +315,7 @@ module ActionView
request_method = method.empty? ? 'post' : method
token_tag(nil, form_options: { action: url, method: request_method })
else
- ''
+ ''.freeze
end
html_options = convert_options_to_data_attributes(options, html_options)
@@ -481,7 +481,7 @@ module ActionView
option = html_options.delete(item).presence || next
"#{item.dasherize}=#{ERB::Util.url_encode(option)}"
}.compact
- extras = extras.empty? ? '' : '?' + extras.join('&')
+ extras = extras.empty? ? ''.freeze : '?' + extras.join('&')
encoded_email_address = ERB::Util.url_encode(email_address).gsub("%40", "@")
html_options["href"] = "mailto:#{encoded_email_address}#{extras}"
@@ -559,29 +559,29 @@ module ActionView
def convert_options_to_data_attributes(options, html_options)
if html_options
html_options = html_options.stringify_keys
- html_options['data-remote'] = 'true' if link_to_remote_options?(options) || link_to_remote_options?(html_options)
+ html_options['data-remote'] = 'true'.freeze if link_to_remote_options?(options) || link_to_remote_options?(html_options)
- method = html_options.delete('method')
+ method = html_options.delete('method'.freeze)
add_method_to_attributes!(html_options, method) if method
html_options
else
- link_to_remote_options?(options) ? {'data-remote' => 'true'} : {}
+ link_to_remote_options?(options) ? {'data-remote' => 'true'.freeze} : {}
end
end
def link_to_remote_options?(options)
if options.is_a?(Hash)
- options.delete('remote') || options.delete(:remote)
+ options.delete('remote'.freeze) || options.delete(:remote)
end
end
def add_method_to_attributes!(html_options, method)
- if method && method.to_s.downcase != "get" && html_options["rel"] !~ /nofollow/
- html_options["rel"] = "#{html_options["rel"]} nofollow".lstrip
+ if method && method.to_s.downcase != "get".freeze && html_options["rel".freeze] !~ /nofollow/
+ html_options["rel".freeze] = "#{html_options["rel".freeze]} nofollow".lstrip
end
- html_options["data-method"] = method
+ html_options["data-method".freeze] = method
end
def token_tag(token=nil, form_options: {})
@@ -589,7 +589,7 @@ module ActionView
token ||= form_authenticity_token(form_options: form_options)
tag(:input, type: "hidden", name: request_forgery_protection_token.to_s, value: token)
else
- ''
+ ''.freeze
end
end
diff --git a/actionview/lib/action_view/railtie.rb b/actionview/lib/action_view/railtie.rb
index 59d869d92d..df14ae09f4 100644
--- a/actionview/lib/action_view/railtie.rb
+++ b/actionview/lib/action_view/railtie.rb
@@ -59,7 +59,7 @@ module ActionView
rake_tasks do |app|
unless app.config.api_only
- load "action_view/tasks/dependencies.rake"
+ load "action_view/tasks/cache_digests.rake"
end
end
end
diff --git a/actionview/lib/action_view/renderer/partial_renderer.rb b/actionview/lib/action_view/renderer/partial_renderer.rb
index 514804b08e..13b4ec6133 100644
--- a/actionview/lib/action_view/renderer/partial_renderer.rb
+++ b/actionview/lib/action_view/renderer/partial_renderer.rb
@@ -521,7 +521,7 @@ module ActionView
def retrieve_variable(path, as)
variable = as || begin
base = path[-1] == "/".freeze ? "".freeze : File.basename(path)
- raise_invalid_identifier(path) unless base =~ /\A_?(.*)(?:\.\w+)*\z/
+ raise_invalid_identifier(path) unless base =~ /\A_?(.*?)(?:\.\w+)*\z/
$1.to_sym
end
if @collection
diff --git a/actionview/lib/action_view/tasks/dependencies.rake b/actionview/lib/action_view/tasks/cache_digests.rake
index 045bdf5691..045bdf5691 100644
--- a/actionview/lib/action_view/tasks/dependencies.rake
+++ b/actionview/lib/action_view/tasks/cache_digests.rake
diff --git a/actionview/lib/action_view/view_paths.rb b/actionview/lib/action_view/view_paths.rb
index b46fe06b01..717d6866c5 100644
--- a/actionview/lib/action_view/view_paths.rb
+++ b/actionview/lib/action_view/view_paths.rb
@@ -1,5 +1,3 @@
-require 'action_view/base'
-
module ActionView
module ViewPaths
extend ActiveSupport::Concern
diff --git a/actionview/test/abstract_unit.rb b/actionview/test/abstract_unit.rb
index d31f7ddc6e..3256d8fc4d 100644
--- a/actionview/test/abstract_unit.rb
+++ b/actionview/test/abstract_unit.rb
@@ -93,12 +93,14 @@ module ActionDispatch
super
return if DrawOnce.drew
- SharedTestRoutes.draw do
- get ':controller(/:action)'
- end
-
- ActionDispatch::IntegrationTest.app.routes.draw do
- get ':controller(/:action)'
+ ActiveSupport::Deprecation.silence do
+ SharedTestRoutes.draw do
+ get ':controller(/:action)'
+ end
+
+ ActionDispatch::IntegrationTest.app.routes.draw do
+ get ':controller(/:action)'
+ end
end
DrawOnce.drew = true
diff --git a/actionview/test/fixtures/test/_customer.mobile.erb b/actionview/test/fixtures/test/_customer.mobile.erb
new file mode 100644
index 0000000000..d8220afeda
--- /dev/null
+++ b/actionview/test/fixtures/test/_customer.mobile.erb
@@ -0,0 +1 @@
+Hello: <%= customer.name rescue "Anonymous" %> \ No newline at end of file
diff --git a/actionview/test/lib/controller/fake_models.rb b/actionview/test/lib/controller/fake_models.rb
index a122fe17c9..65c68fc34a 100644
--- a/actionview/test/lib/controller/fake_models.rb
+++ b/actionview/test/lib/controller/fake_models.rb
@@ -31,27 +31,6 @@ end
class GoodCustomer < Customer
end
-class TicketType < Struct.new(:name)
- extend ActiveModel::Naming
- include ActiveModel::Conversion
- extend ActiveModel::Translation
-
- def initialize(*args)
- super
- @persisted = false
- end
-
- def persisted=(boolean)
- @persisted = boolean
- end
-
- def persisted?
- @persisted
- end
-
- attr_accessor :name
-end
-
class Post < Struct.new(:title, :author_name, :body, :secret, :persisted, :written_on, :cost)
extend ActiveModel::Naming
include ActiveModel::Conversion
diff --git a/actionview/test/template/form_helper_test.rb b/actionview/test/template/form_helper_test.rb
index 034b8a4bf6..e77183e39f 100644
--- a/actionview/test/template/form_helper_test.rb
+++ b/actionview/test/template/form_helper_test.rb
@@ -128,8 +128,6 @@ class FormHelperTest < ActionView::TestCase
@post_delegator.title = 'Hello World'
@car = Car.new("#000FFF")
-
- @ticket_type = TicketType.new
end
Routes = ActionDispatch::Routing::RouteSet.new
@@ -138,8 +136,6 @@ class FormHelperTest < ActionView::TestCase
resources :comments
end
- resources :ticket_types
-
namespace :admin do
resources :posts do
resources :comments
@@ -1876,20 +1872,6 @@ class FormHelperTest < ActionView::TestCase
assert_dom_equal expected, output_buffer
end
- def test_lowercase_model_name_default_submit_button_value
- form_for(@ticket_type) do |f|
- concat f.submit
- end
-
- expected =
- '<form class="new_ticket_type" id="new_ticket_type" action="/ticket_types" accept-charset="UTF-8" method="post">' +
- hidden_fields +
- '<input type="submit" name="commit" value="Create ticket type" data-disable-with="Create ticket type" />' +
- '</form>'
-
- assert_dom_equal expected, output_buffer
- end
-
def test_form_for_with_symbol_object_name
form_for(@post, as: "other_name", html: { id: "create-post" }) do |f|
concat f.label(:title, class: 'post_title')
@@ -2257,7 +2239,7 @@ class FormHelperTest < ActionView::TestCase
end
expected = whole_form('/posts', 'new_post', 'new_post') do
- "<input name='commit' data-disable-with='Create post' type='submit' value='Create post' />"
+ "<input name='commit' data-disable-with='Create Post' type='submit' value='Create Post' />"
end
assert_dom_equal expected, output_buffer
@@ -2272,7 +2254,7 @@ class FormHelperTest < ActionView::TestCase
end
expected = whole_form('/posts/123', 'edit_post_123', 'edit_post', method: 'patch') do
- "<input name='commit' data-disable-with='Confirm post changes' type='submit' value='Confirm post changes' />"
+ "<input name='commit' data-disable-with='Confirm Post changes' type='submit' value='Confirm Post changes' />"
end
assert_dom_equal expected, output_buffer
@@ -2300,7 +2282,7 @@ class FormHelperTest < ActionView::TestCase
end
expected = whole_form('/posts/123', 'edit_another_post', 'edit_another_post', method: 'patch') do
- "<input name='commit' data-disable-with='Update your post' type='submit' value='Update your post' />"
+ "<input name='commit' data-disable-with='Update your Post' type='submit' value='Update your Post' />"
end
assert_dom_equal expected, output_buffer
diff --git a/actionview/test/template/render_test.rb b/actionview/test/template/render_test.rb
index 3561114d90..b417d1ebfa 100644
--- a/actionview/test/template/render_test.rb
+++ b/actionview/test/template/render_test.rb
@@ -270,6 +270,11 @@ module RenderTestCases
assert_equal "Hello: davidHello: mary", @view.render(:partial => "test/customer", :collection => [ Customer.new("david"), Customer.new("mary") ])
end
+ def test_render_partial_collection_with_partial_name_containing_dot
+ assert_equal "Hello: davidHello: mary",
+ @view.render(:partial => "test/customer.mobile", :collection => [ Customer.new("david"), Customer.new("mary") ])
+ end
+
def test_render_partial_collection_as_by_string
assert_equal "david david davidmary mary mary",
@view.render(:partial => "test/customer_with_var", :collection => [ Customer.new("david"), Customer.new("mary") ], :as => 'customer')
diff --git a/actionview/test/template/url_helper_test.rb b/actionview/test/template/url_helper_test.rb
index d6a19a829f..ab56d80de3 100644
--- a/actionview/test/template/url_helper_test.rb
+++ b/actionview/test/template/url_helper_test.rb
@@ -655,7 +655,9 @@ class UrlHelperControllerTest < ActionController::TestCase
to: 'url_helper_controller_test/url_helper#show_named_route',
as: :show_named_route
- get "/:controller(/:action(/:id))"
+ ActiveSupport::Deprecation.silence do
+ get "/:controller(/:action(/:id))"
+ end
get 'url_helper_controller_test/url_helper/normalize_recall_params',
to: UrlHelperController.action(:normalize_recall),
diff --git a/activejob/activejob.gemspec b/activejob/activejob.gemspec
index bc1671b508..e97bb40abf 100644
--- a/activejob/activejob.gemspec
+++ b/activejob/activejob.gemspec
@@ -13,7 +13,7 @@ Gem::Specification.new do |s|
s.author = 'David Heinemeier Hansson'
s.email = 'david@loudthinking.com'
- s.homepage = 'http://www.rubyonrails.org'
+ s.homepage = 'http://rubyonrails.org'
s.files = Dir['CHANGELOG.md', 'MIT-LICENSE', 'README.md', 'lib/**/*']
s.require_path = 'lib'
diff --git a/activejob/lib/active_job/core.rb b/activejob/lib/active_job/core.rb
index 19b900a285..f7f882c998 100644
--- a/activejob/lib/active_job/core.rb
+++ b/activejob/lib/active_job/core.rb
@@ -79,7 +79,7 @@ module ActiveJob
'queue_name' => queue_name,
'priority' => priority,
'arguments' => serialize_arguments(arguments),
- 'locale' => I18n.locale
+ 'locale' => I18n.locale.to_s
}
end
@@ -108,7 +108,7 @@ module ActiveJob
self.queue_name = job_data['queue_name']
self.priority = job_data['priority']
self.serialized_arguments = job_data['arguments']
- self.locale = job_data['locale'] || I18n.locale
+ self.locale = job_data['locale'] || I18n.locale.to_s
end
private
diff --git a/activejob/test/cases/argument_serialization_test.rb b/activejob/test/cases/argument_serialization_test.rb
index eb8ad185aa..59dc3d7f78 100644
--- a/activejob/test/cases/argument_serialization_test.rb
+++ b/activejob/test/cases/argument_serialization_test.rb
@@ -62,13 +62,14 @@ class ArgumentSerializationTest < ActiveSupport::TestCase
assert_raises ActiveJob::SerializationError do
ActiveJob::Arguments.serialize [ { :a => [{ 2 => 3 }] } ]
end
+ end
- assert_raises ActiveJob::SerializationError do
- ActiveJob::Arguments.serialize [ '_aj_globalid' => 1 ]
- end
-
- assert_raises ActiveJob::SerializationError do
- ActiveJob::Arguments.serialize [ :_aj_globalid => 1 ]
+ test 'should not allow reserved hash keys' do
+ ['_aj_globalid', :_aj_globalid, '_aj_symbol_keys', :_aj_symbol_keys,
+ '_aj_hash_with_indifferent_access', :_aj_hash_with_indifferent_access].each do |key|
+ assert_raises ActiveJob::SerializationError do
+ ActiveJob::Arguments.serialize [key => 1]
+ end
end
end
diff --git a/activejob/test/cases/job_serialization_test.rb b/activejob/test/cases/job_serialization_test.rb
index 229517774e..fa94209889 100644
--- a/activejob/test/cases/job_serialization_test.rb
+++ b/activejob/test/cases/job_serialization_test.rb
@@ -2,6 +2,7 @@ require 'helper'
require 'jobs/gid_job'
require 'jobs/hello_job'
require 'models/person'
+require 'json'
class JobSerializationTest < ActiveSupport::TestCase
setup do
@@ -15,18 +16,32 @@ class JobSerializationTest < ActiveSupport::TestCase
end
test 'serialize includes current locale' do
- assert_equal :en, HelloJob.new.serialize['locale']
+ assert_equal 'en', HelloJob.new.serialize['locale']
+ end
+
+ test 'serialize and deserialize are symmetric' do
+ # Round trip a job in memory only
+ h1 = HelloJob.new
+ h1.deserialize(h1.serialize)
+
+ # Now verify it's identical to a JSON round trip.
+ # We don't want any non-native JSON elements in the job hash,
+ # like symbols.
+ payload = JSON.dump(h1.serialize)
+ h2 = HelloJob.new
+ h2.deserialize(JSON.load(payload))
+ assert_equal h1.serialize, h2.serialize
end
test 'deserialize sets locale' do
job = HelloJob.new
- job.deserialize 'locale' => :es
- assert_equal :es, job.locale
+ job.deserialize 'locale' => 'es'
+ assert_equal 'es', job.locale
end
test 'deserialize sets default locale' do
job = HelloJob.new
job.deserialize({})
- assert_equal :en, job.locale
+ assert_equal 'en', job.locale
end
end
diff --git a/activemodel/activemodel.gemspec b/activemodel/activemodel.gemspec
index 53206580f0..1c3997b864 100644
--- a/activemodel/activemodel.gemspec
+++ b/activemodel/activemodel.gemspec
@@ -13,7 +13,7 @@ Gem::Specification.new do |s|
s.author = 'David Heinemeier Hansson'
s.email = 'david@loudthinking.com'
- s.homepage = 'http://www.rubyonrails.org'
+ s.homepage = 'http://rubyonrails.org'
s.files = Dir['CHANGELOG.md', 'MIT-LICENSE', 'README.rdoc', 'lib/**/*']
s.require_path = 'lib'
diff --git a/activemodel/lib/active_model/type.rb b/activemodel/lib/active_model/type.rb
index bec851594f..6ec3452478 100644
--- a/activemodel/lib/active_model/type.rb
+++ b/activemodel/lib/active_model/type.rb
@@ -47,7 +47,7 @@ module ActiveModel
register(:binary, Type::Binary)
register(:boolean, Type::Boolean)
register(:date, Type::Date)
- register(:date_time, Type::DateTime)
+ register(:datetime, Type::DateTime)
register(:decimal, Type::Decimal)
register(:float, Type::Float)
register(:immutable_string, Type::ImmutableString)
diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md
index 3bb4b5236e..3cfebdc2d0 100644
--- a/activerecord/CHANGELOG.md
+++ b/activerecord/CHANGELOG.md
@@ -1,3 +1,17 @@
+* MySQL: strict mode respects other SQL modes rather than overwriting them.
+ Setting `strict: true` adds `STRICT_ALL_TABLES` to `sql_mode`. Setting
+ `strict: false` removes `STRICT_TRANS_TABLES`, `STRICT_ALL_TABLES`, and
+ `TRADITIONAL` from `sql_mode`.
+
+ *Ryuta Kamizono*
+
+* Execute default_scope defined by abstract class in the context of subclass.
+
+ Fixes #23413.
+ Fixes #10658.
+
+ *Mehmet Emin İNAÇ*
+
* Fix an issue when preloading associations with extensions.
Previously every association with extension methods was transformed into an
instance dependent scope. This is no longer the case.
@@ -41,6 +55,12 @@
## Rails 5.0.0.beta3 (February 24, 2016) ##
+* Save many-to-many objects based on association primary key.
+
+ Fixes #20995.
+
+ *himesh-r*
+
* Ensure that mutations of the array returned from `ActiveRecord::Relation#to_a`
do not affect the original relation, by returning a duplicate array each time.
@@ -222,6 +242,21 @@
## Rails 5.0.0.beta1 (December 18, 2015) ##
+* Limit record touching to once per transaction.
+
+ If you have a parent/grand-parent relation like:
+
+ Comment belongs_to :message, touch: true
+ Message belongs_to :project, touch: true
+ Project belongs_to :account, touch: true
+
+ When the lowest entry(`Comment`) is saved, now, it won't repeat the touch
+ call multiple times for the parent records.
+
+ Related #18606.
+
+ *arthurnn*
+
* Order the result of `find(ids)` to match the passed array, if the relation
has no explicit order defined.
diff --git a/activerecord/activerecord.gemspec b/activerecord/activerecord.gemspec
index 4405da2812..881dee13e4 100644
--- a/activerecord/activerecord.gemspec
+++ b/activerecord/activerecord.gemspec
@@ -13,7 +13,7 @@ Gem::Specification.new do |s|
s.author = 'David Heinemeier Hansson'
s.email = 'david@loudthinking.com'
- s.homepage = 'http://www.rubyonrails.org'
+ s.homepage = 'http://rubyonrails.org'
s.files = Dir['CHANGELOG.md', 'MIT-LICENSE', 'README.rdoc', 'examples/**/*', 'lib/**/*']
s.require_path = 'lib'
diff --git a/activerecord/lib/active_record/associations/association.rb b/activerecord/lib/active_record/associations/association.rb
index d64ab64c99..f7edfbfb5f 100644
--- a/activerecord/lib/active_record/associations/association.rb
+++ b/activerecord/lib/active_record/associations/association.rb
@@ -257,7 +257,7 @@ module ActiveRecord
# Returns true if statement cache should be skipped on the association reader.
def skip_statement_cache?
- reflection.scope_chain.any?(&:any?) ||
+ reflection.has_scope? ||
scope.eager_loading? ||
klass.scope_attributes? ||
reflection.source_reflection.active_record.default_scopes.any?
diff --git a/activerecord/lib/active_record/associations/join_dependency.rb b/activerecord/lib/active_record/associations/join_dependency.rb
index 0e4e951269..b94feeff12 100644
--- a/activerecord/lib/active_record/associations/join_dependency.rb
+++ b/activerecord/lib/active_record/associations/join_dependency.rb
@@ -228,7 +228,7 @@ module ActiveRecord
def find_reflection(klass, name)
klass._reflect_on_association(name) or
- raise ConfigurationError, "Association named '#{ name }' was not found on #{ klass.name }; perhaps you misspelled it?"
+ raise ConfigurationError, "Can't join '#{ klass.name }' to association named '#{ name }'; perhaps you misspelled it?"
end
def build(associations, base_klass)
diff --git a/activerecord/lib/active_record/attributes.rb b/activerecord/lib/active_record/attributes.rb
index 5d0405c3be..e0ceafc617 100644
--- a/activerecord/lib/active_record/attributes.rb
+++ b/activerecord/lib/active_record/attributes.rb
@@ -119,7 +119,7 @@ module ActiveRecord
#
# class MoneyType < ActiveRecord::Type::Integer
# def cast(value)
- # if !value.kind_of(Numeric) && value.include?('$')
+ # if !value.kind_of?(Numeric) && value.include?('$')
# price_in_dollars = value.gsub(/\$/, '').to_f
# super(price_in_dollars * 100)
# else
@@ -154,7 +154,7 @@ module ActiveRecord
# end
#
# class MoneyType < Type::Value
- # def initialize(currency_converter)
+ # def initialize(currency_converter:)
# @currency_converter = currency_converter
# end
#
@@ -171,7 +171,7 @@ module ActiveRecord
#
# class Product < ActiveRecord::Base
# currency_converter = ConversionRatesFromTheInternet.new
- # attribute :price_in_bitcoins, :money, currency_converter
+ # attribute :price_in_bitcoins, :money, currency_converter: currency_converter
# end
#
# Product.where(price_in_bitcoins: Money.new(5, "USD"))
diff --git a/activerecord/lib/active_record/autosave_association.rb b/activerecord/lib/active_record/autosave_association.rb
index bac5a38a5d..06c7482bf9 100644
--- a/activerecord/lib/active_record/autosave_association.rb
+++ b/activerecord/lib/active_record/autosave_association.rb
@@ -22,7 +22,7 @@ module ActiveRecord
#
# == Validation
#
- # Children records are validated unless <tt>:validate</tt> is +false+.
+ # Child records are validated unless <tt>:validate</tt> is +false+.
#
# == Callbacks
#
diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_dumper.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_dumper.rb
index 2209874d0a..4880d216d6 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/schema_dumper.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_dumper.rb
@@ -14,7 +14,7 @@ module ActiveRecord
end
def column_spec_for_primary_key(column)
- return if column.type == :integer
+ return {} if default_primary_key?(column)
spec = { id: schema_type(column).inspect }
spec.merge!(prepare_column_options(column))
end
@@ -56,12 +56,20 @@ module ActiveRecord
private
+ def default_primary_key?(column)
+ schema_type(column) == :integer
+ end
+
def schema_type(column)
- column.type
+ if column.bigint?
+ :bigint
+ else
+ column.type
+ end
end
def schema_limit(column)
- limit = column.limit
+ limit = column.limit unless column.bigint?
limit.inspect if limit && limit != native_database_types[column.type][:limit]
end
diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb
index f0f855963a..a401310ee0 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb
@@ -854,7 +854,7 @@ module ActiveRecord
#
# generates:
#
- # ALTER TABLE "articles" ADD CONSTRAINT articles_author_id_fk FOREIGN KEY ("author_id") REFERENCES "authors" ("id")
+ # ALTER TABLE "articles" ADD CONSTRAINT fk_rails_e74ce85cbc FOREIGN KEY ("author_id") REFERENCES "authors" ("id")
#
# ====== Creating a foreign key on a specific column
#
@@ -870,7 +870,7 @@ module ActiveRecord
#
# generates:
#
- # ALTER TABLE "articles" ADD CONSTRAINT articles_author_id_fk FOREIGN KEY ("author_id") REFERENCES "authors" ("id") ON DELETE CASCADE
+ # ALTER TABLE "articles" ADD CONSTRAINT fk_rails_e74ce85cbc FOREIGN KEY ("author_id") REFERENCES "authors" ("id") ON DELETE CASCADE
#
# The +options+ hash can include the following keys:
# [<tt>:column</tt>]
diff --git a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb
index fcc1ef9d5f..6704843c07 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb
@@ -420,8 +420,8 @@ module ActiveRecord
end
end
- def new_column(name, default, sql_type_metadata = nil, null = true, default_function = nil, collation = nil)
- Column.new(name, default, sql_type_metadata, null, default_function, collation)
+ def new_column(name, default, sql_type_metadata, null, table_name, default_function = nil, collation = nil) # :nodoc:
+ Column.new(name, default, sql_type_metadata, null, table_name, default_function, collation)
end
def lookup_cast_type(sql_type) # :nodoc:
diff --git a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb
index b12bac2737..0e22062913 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb
@@ -153,8 +153,8 @@ module ActiveRecord
raise NotImplementedError
end
- def new_column(field, default, sql_type_metadata = nil, null = true, default_function = nil, collation = nil) # :nodoc:
- MySQL::Column.new(field, default, sql_type_metadata, null, default_function, collation)
+ def new_column(field, default, sql_type_metadata, null, table_name, default_function = nil, collation = nil) # :nodoc:
+ MySQL::Column.new(field, default, sql_type_metadata, null, table_name, default_function, collation)
end
# Must return the MySQL error number from the exception, if the exception has an
@@ -421,16 +421,15 @@ module ActiveRecord
# Returns an array of +Column+ objects for the table specified by +table_name+.
def columns(table_name) # :nodoc:
- sql = "SHOW FULL FIELDS FROM #{quote_table_name(table_name)}"
- execute_and_free(sql, 'SCHEMA') do |result|
- each_hash(result).map do |field|
- type_metadata = fetch_type_metadata(field[:Type], field[:Extra])
- if type_metadata.type == :datetime && field[:Default] == "CURRENT_TIMESTAMP"
- new_column(field[:Field], nil, type_metadata, field[:Null] == "YES", field[:Default], field[:Collation])
- else
- new_column(field[:Field], field[:Default], type_metadata, field[:Null] == "YES", nil, field[:Collation])
- end
+ table_name = table_name.to_s
+ column_definitions(table_name).map do |field|
+ type_metadata = fetch_type_metadata(field[:Type], field[:Extra])
+ if type_metadata.type == :datetime && field[:Default] == "CURRENT_TIMESTAMP"
+ default, default_function = nil, field[:Default]
+ else
+ default, default_function = field[:Default], nil
end
+ new_column(field[:Field], default, type_metadata, field[:Null] == "YES", table_name, default_function, field[:Collation])
end
end
@@ -608,10 +607,10 @@ module ActiveRecord
end
def case_sensitive_comparison(table, attribute, column, value)
- if value.nil? || column.case_sensitive?
- super
- else
+ if !value.nil? && column.collation && !column.case_sensitive?
table[attribute].eq(Arel::Nodes::Bin.new(Arel::Nodes::BindParam.new))
+ else
+ super
end
end
@@ -668,7 +667,7 @@ module ActiveRecord
register_integer_type m, %r(^smallint)i, limit: 2
register_integer_type m, %r(^tinyint)i, limit: 1
- m.alias_type %r(tinyint\(1\))i, 'boolean' if emulate_booleans
+ m.register_type %r(^tinyint\(1\))i, Type::Boolean.new if emulate_booleans
m.alias_type %r(year)i, 'integer'
m.alias_type %r(bit)i, 'binary'
@@ -847,9 +846,18 @@ module ActiveRecord
# Make MySQL reject illegal values rather than truncating or blanking them, see
# http://dev.mysql.com/doc/refman/5.7/en/sql-mode.html#sqlmode_strict_all_tables
# If the user has provided another value for sql_mode, don't replace it.
- unless variables.has_key?('sql_mode') || defaults.include?(@config[:strict])
- variables['sql_mode'] = strict_mode? ? 'STRICT_ALL_TABLES' : ''
+ if sql_mode = variables.delete('sql_mode')
+ sql_mode = quote(sql_mode)
+ elsif !defaults.include?(strict_mode?)
+ if strict_mode?
+ sql_mode = "CONCAT(@@sql_mode, ',STRICT_ALL_TABLES')"
+ else
+ sql_mode = "REPLACE(@@sql_mode, 'STRICT_TRANS_TABLES', '')"
+ sql_mode = "REPLACE(#{sql_mode}, 'STRICT_ALL_TABLES', '')"
+ sql_mode = "REPLACE(#{sql_mode}, 'TRADITIONAL', '')"
+ end
end
+ sql_mode_assignment = "@@SESSION.sql_mode = #{sql_mode}, " if sql_mode
# NAMES does not have an equals sign, see
# http://dev.mysql.com/doc/refman/5.7/en/set-statement.html#id944430
@@ -871,7 +879,13 @@ module ActiveRecord
end.compact.join(', ')
# ...and send them all in one query
- @connection.query "SET #{encoding} #{variable_assignments}"
+ @connection.query "SET #{encoding} #{sql_mode_assignment} #{variable_assignments}"
+ end
+
+ def column_definitions(table_name) # :nodoc:
+ execute_and_free("SHOW FULL FIELDS FROM #{quote_table_name(table_name)}", 'SCHEMA') do |result|
+ each_hash(result)
+ end
end
def extract_foreign_key_action(structure, name, action) # :nodoc:
diff --git a/activerecord/lib/active_record/connection_adapters/column.rb b/activerecord/lib/active_record/connection_adapters/column.rb
index 10f908538f..2e718b29fa 100644
--- a/activerecord/lib/active_record/connection_adapters/column.rb
+++ b/activerecord/lib/active_record/connection_adapters/column.rb
@@ -5,7 +5,7 @@ module ActiveRecord
module ConnectionAdapters
# An abstract definition of a column in a table.
class Column
- attr_reader :name, :null, :sql_type_metadata, :default, :default_function, :collation
+ attr_reader :name, :default, :sql_type_metadata, :null, :table_name, :default_function, :collation
delegate :precision, :scale, :limit, :type, :sql_type, to: :sql_type_metadata, allow_nil: true
@@ -15,14 +15,14 @@ module ActiveRecord
# +default+ is the type-casted default value, such as +new+ in <tt>sales_stage varchar(20) default 'new'</tt>.
# +sql_type_metadata+ is various information about the type of the column
# +null+ determines if this column allows +NULL+ values.
- def initialize(name, default, sql_type_metadata = nil, null = true, default_function = nil, collation = nil)
+ def initialize(name, default, sql_type_metadata = nil, null = true, table_name = nil, default_function = nil, collation = nil)
@name = name.freeze
+ @table_name = table_name
@sql_type_metadata = sql_type_metadata
@null = null
@default = default
@default_function = default_function
@collation = collation
- @table_name = nil
end
def has_default?
@@ -54,7 +54,7 @@ module ActiveRecord
protected
def attributes_for_hash
- [self.class, name, default, sql_type_metadata, null, default_function, collation]
+ [self.class, name, default, sql_type_metadata, null, table_name, default_function, collation]
end
end
diff --git a/activerecord/lib/active_record/connection_adapters/mysql/schema_dumper.rb b/activerecord/lib/active_record/connection_adapters/mysql/schema_dumper.rb
index 3cdd46236b..be40df4101 100644
--- a/activerecord/lib/active_record/connection_adapters/mysql/schema_dumper.rb
+++ b/activerecord/lib/active_record/connection_adapters/mysql/schema_dumper.rb
@@ -3,18 +3,13 @@ module ActiveRecord
module MySQL
module ColumnDumper
def column_spec_for_primary_key(column)
- spec = {}
if column.bigint?
- spec[:id] = ':bigint'
+ spec = { id: :bigint.inspect }
spec[:default] = schema_default(column) || 'nil' unless column.auto_increment?
- spec[:unsigned] = 'true' if column.unsigned?
- elsif column.auto_increment?
- spec[:unsigned] = 'true' if column.unsigned?
- return if spec.empty?
else
- spec[:id] = schema_type(column).inspect
- spec.merge!(prepare_column_options(column).delete_if { |key, _| key == :null })
+ spec = super.except!(:null)
end
+ spec[:unsigned] = 'true' if column.unsigned?
spec
end
@@ -30,6 +25,10 @@ module ActiveRecord
private
+ def default_primary_key?(column)
+ super && column.auto_increment?
+ end
+
def schema_type(column)
if column.sql_type == 'tinyblob'
:blob
@@ -38,16 +37,12 @@ module ActiveRecord
end
end
- def schema_limit(column)
- super unless column.type == :boolean
- end
-
def schema_precision(column)
super unless /time/ === column.sql_type && column.precision == 0
end
def schema_collation(column)
- if column.collation && table_name = column.instance_variable_get(:@table_name)
+ if column.collation && table_name = column.table_name
@table_collation_cache ||= {}
@table_collation_cache[table_name] ||= select_one("SHOW TABLE STATUS LIKE '#{table_name}'")["Collation"]
column.collation.inspect if column.collation != @table_collation_cache[table_name]
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/column.rb b/activerecord/lib/active_record/connection_adapters/postgresql/column.rb
index bfa03fa136..3ad1911a28 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql/column.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql/column.rb
@@ -8,7 +8,6 @@ module ActiveRecord
def serial?
return unless default_function
- table_name = @table_name || '(?<table_name>.+)'
%r{\Anextval\('"?#{table_name}_#{name}_seq"?'::regclass\)\z} === default_function
end
end
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/schema_dumper.rb b/activerecord/lib/active_record/connection_adapters/postgresql/schema_dumper.rb
index 19761618cf..1047ba8cac 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql/schema_dumper.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql/schema_dumper.rb
@@ -3,16 +3,9 @@ module ActiveRecord
module PostgreSQL
module ColumnDumper
def column_spec_for_primary_key(column)
- spec = {}
- if column.serial?
- return unless column.bigint?
- spec[:id] = ':bigserial'
- elsif column.type == :uuid
- spec[:id] = ':uuid'
- spec[:default] = schema_default(column) || 'nil'
- else
- spec[:id] = schema_type(column).inspect
- spec.merge!(prepare_column_options(column).delete_if { |key, _| key == :null })
+ spec = super.except!(:null)
+ if schema_type(column) == :uuid
+ spec[:default] ||= 'nil'
end
spec
end
@@ -31,6 +24,10 @@ module ActiveRecord
private
+ def default_primary_key?(column)
+ schema_type(column) == :serial
+ end
+
def schema_type(column)
return super unless column.serial?
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 67e727d8ed..ca2a41b136 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb
@@ -213,20 +213,20 @@ module ActiveRecord
end
# Returns the list of all column definitions for a table.
- def columns(table_name)
- # Limit, precision, and scale are all handled by the superclass.
+ def columns(table_name) # :nodoc:
+ table_name = table_name.to_s
column_definitions(table_name).map do |column_name, type, default, notnull, oid, fmod, collation|
oid = oid.to_i
fmod = fmod.to_i
type_metadata = fetch_type_metadata(column_name, type, oid, fmod)
default_value = extract_value_from_default(default)
default_function = extract_default_function(default_value, default)
- new_column(column_name, default_value, type_metadata, !notnull, default_function, collation)
+ new_column(column_name, default_value, type_metadata, !notnull, table_name, default_function, collation)
end
end
- def new_column(name, default, sql_type_metadata = nil, null = true, default_function = nil, collation = nil) # :nodoc:
- PostgreSQLColumn.new(name, default, sql_type_metadata, null, default_function, collation)
+ def new_column(name, default, sql_type_metadata, null, table_name, default_function = nil, collation = nil) # :nodoc:
+ PostgreSQLColumn.new(name, default, sql_type_metadata, null, table_name, default_function, collation)
end
# Returns the current database name.
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
index 61c9628de3..6497b1cc31 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
@@ -815,7 +815,7 @@ module ActiveRecord
ActiveRecord::Type.register(:bit_varying, OID::BitVarying, adapter: :postgresql)
ActiveRecord::Type.register(:binary, OID::Bytea, adapter: :postgresql)
ActiveRecord::Type.register(:cidr, OID::Cidr, adapter: :postgresql)
- ActiveRecord::Type.register(:date_time, OID::DateTime, adapter: :postgresql)
+ ActiveRecord::Type.register(:datetime, OID::DateTime, adapter: :postgresql)
ActiveRecord::Type.register(:decimal, OID::Decimal, adapter: :postgresql)
ActiveRecord::Type.register(:enum, OID::Enum, adapter: :postgresql)
ActiveRecord::Type.register(:hstore, OID::Hstore, adapter: :postgresql)
diff --git a/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb b/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb
index c65d33ccb3..7ac81bdf23 100644
--- a/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb
@@ -337,7 +337,8 @@ module ActiveRecord
end
# Returns an array of +Column+ objects for the table specified by +table_name+.
- def columns(table_name) #:nodoc:
+ def columns(table_name) # :nodoc:
+ table_name = table_name.to_s
table_structure(table_name).map do |field|
case field["dflt_value"]
when /^null$/i
@@ -351,7 +352,7 @@ module ActiveRecord
collation = field['collation']
sql_type = field['type']
type_metadata = fetch_type_metadata(sql_type)
- new_column(field['name'], field['dflt_value'], type_metadata, field['notnull'].to_i == 0, nil, collation)
+ new_column(field['name'], field['dflt_value'], type_metadata, field['notnull'].to_i == 0, table_name, nil, collation)
end
end
diff --git a/activerecord/lib/active_record/enum.rb b/activerecord/lib/active_record/enum.rb
index 903c63a7db..7be332fb97 100644
--- a/activerecord/lib/active_record/enum.rb
+++ b/activerecord/lib/active_record/enum.rb
@@ -152,7 +152,7 @@ module ActiveRecord
enum_values = ActiveSupport::HashWithIndifferentAccess.new
name = name.to_sym
- # def self.statuses statuses end
+ # def self.statuses() statuses end
detect_enum_conflict!(name, name.to_s.pluralize, true)
klass.singleton_class.send(:define_method, name.to_s.pluralize) { enum_values }
diff --git a/activerecord/lib/active_record/nested_attributes.rb b/activerecord/lib/active_record/nested_attributes.rb
index ae78ceee01..fe68869143 100644
--- a/activerecord/lib/active_record/nested_attributes.rb
+++ b/activerecord/lib/active_record/nested_attributes.rb
@@ -215,7 +215,7 @@ module ActiveRecord
#
# The keys of the hash which is the value for +:posts_attributes+ are
# ignored in this case.
- # However, it is not allowed to use +'id'+ or +:id+ for one of
+ # However, it is not allowed to use <tt>'id'</tt> or <tt>:id</tt> for one of
# such keys, otherwise the hash will be wrapped in an array and
# interpreted as an attribute hash for a single post.
#
diff --git a/activerecord/lib/active_record/railties/databases.rake b/activerecord/lib/active_record/railties/databases.rake
index 69a7838001..00cf8536e1 100644
--- a/activerecord/lib/active_record/railties/databases.rake
+++ b/activerecord/lib/active_record/railties/databases.rake
@@ -22,7 +22,7 @@ db_namespace = namespace :db do
end
end
- desc 'Creates the database from DATABASE_URL or config/database.yml for the current RAILS_ENV (use db:create:all to create all databases in the config). Without RAILS_ENV, it defaults to creating the development and test databases.'
+ desc 'Creates the database from DATABASE_URL or config/database.yml for the current RAILS_ENV (use db:create:all to create all databases in the config). Without RAILS_ENV or when RAILS_ENV is development, it defaults to creating the development and test databases.'
task :create => [:load_config] do
ActiveRecord::Tasks::DatabaseTasks.create_current
end
@@ -33,7 +33,7 @@ db_namespace = namespace :db do
end
end
- desc 'Drops the database from DATABASE_URL or config/database.yml for the current RAILS_ENV (use db:drop:all to drop all databases in the config). Without RAILS_ENV, it defaults to dropping the development and test databases.'
+ desc 'Drops the database from DATABASE_URL or config/database.yml for the current RAILS_ENV (use db:drop:all to drop all databases in the config). Without RAILS_ENV or when RAILS_ENV is development, it defaults to dropping the development and test databases.'
task :drop => [:load_config, :check_protected_environments] do
db_namespace["drop:_unsafe"].invoke
end
diff --git a/activerecord/lib/active_record/reflection.rb b/activerecord/lib/active_record/reflection.rb
index 43f573f193..f8dffce2f1 100644
--- a/activerecord/lib/active_record/reflection.rb
+++ b/activerecord/lib/active_record/reflection.rb
@@ -138,6 +138,10 @@ module ActiveRecord
# PolymorphicReflection
# RuntimeReflection
class AbstractReflection # :nodoc:
+ def through_reflection?
+ false
+ end
+
def table_name
klass.table_name
end
@@ -445,6 +449,10 @@ module ActiveRecord
scope ? [[scope]] : [[]]
end
+ def has_scope?
+ scope
+ end
+
def has_inverse?
inverse_name
end
@@ -700,6 +708,10 @@ module ActiveRecord
@source_reflection_name = delegate_reflection.options[:source]
end
+ def through_reflection?
+ true
+ end
+
def klass
@klass ||= delegate_reflection.compute_class(class_name)
end
@@ -765,7 +777,6 @@ module ActiveRecord
# This is for clearing cache on the reflection. Useful for tests that need to compare
# SQL queries on associations.
def clear_association_scope_cache # :nodoc:
- @chain = nil
delegate_reflection.clear_association_scope_cache
source_reflection.clear_association_scope_cache
through_reflection.clear_association_scope_cache
@@ -812,13 +823,19 @@ module ActiveRecord
end
end
+ def has_scope?
+ scope || options[:source_type] ||
+ source_reflection.has_scope? ||
+ through_reflection.has_scope?
+ end
+
def join_keys(association_klass)
source_reflection.join_keys(association_klass)
end
# A through association is nested if there would be more than one join table
def nested?
- chain.length > 2
+ source_reflection.through_reflection? || through_reflection.through_reflection?
end
# We want to use the klass from this reflection, rather than just delegate straight to
diff --git a/activerecord/lib/active_record/relation/finder_methods.rb b/activerecord/lib/active_record/relation/finder_methods.rb
index c3053f0b13..27dd0b4143 100644
--- a/activerecord/lib/active_record/relation/finder_methods.rb
+++ b/activerecord/lib/active_record/relation/finder_methods.rb
@@ -42,10 +42,10 @@ module ActiveRecord
# Person.find_by(name: 'Spartacus', rating: 4)
# # returns the first item or nil.
#
- # Person.where(name: 'Spartacus', rating: 4).first_or_initialize
+ # Person.find_or_initialize_by(name: 'Spartacus', rating: 4)
# # returns the first item or returns a new instance (requires you call .save to persist against the database).
#
- # Person.where(name: 'Spartacus', rating: 4).first_or_create
+ # Person.find_or_create_by(name: 'Spartacus', rating: 4)
# # returns the first item or creates it and returns it.
#
# ==== Alternatives for #find
diff --git a/activerecord/lib/active_record/schema_dumper.rb b/activerecord/lib/active_record/schema_dumper.rb
index f115c7542b..affcd9aed1 100644
--- a/activerecord/lib/active_record/schema_dumper.rb
+++ b/activerecord/lib/active_record/schema_dumper.rb
@@ -104,10 +104,7 @@ HEADER
end
def table(table, stream)
- columns = @connection.columns(table).map do |column|
- column.instance_variable_set(:@table_name, table)
- column
- end
+ columns = @connection.columns(table)
begin
tbl = StringIO.new
@@ -126,7 +123,7 @@ HEADER
tbl.print ", primary_key: #{pk.inspect}" unless pk == 'id'
pkcol = columns.detect { |c| c.name == pk }
pkcolspec = @connection.column_spec_for_primary_key(pkcol)
- if pkcolspec
+ if pkcolspec.present?
pkcolspec.each do |key, value|
tbl.print ", #{key}: #{value}"
end
diff --git a/activerecord/lib/active_record/scoping/default.rb b/activerecord/lib/active_record/scoping/default.rb
index f6b6768ce3..9eab59ac78 100644
--- a/activerecord/lib/active_record/scoping/default.rb
+++ b/activerecord/lib/active_record/scoping/default.rb
@@ -115,7 +115,8 @@ module ActiveRecord
base_rel ||= relation
evaluate_default_scope do
default_scopes.inject(base_rel) do |default_scope, scope|
- default_scope.merge(base_rel.scoping { scope.call })
+ scope = scope.respond_to?(:to_proc) ? scope : scope.method(:call)
+ default_scope.merge(base_rel.instance_exec(&scope))
end
end
end
diff --git a/activerecord/lib/active_record/tasks/database_tasks.rb b/activerecord/lib/active_record/tasks/database_tasks.rb
index 7dc41fa98c..261a6a264f 100644
--- a/activerecord/lib/active_record/tasks/database_tasks.rb
+++ b/activerecord/lib/active_record/tasks/database_tasks.rb
@@ -282,8 +282,7 @@ module ActiveRecord
def each_current_configuration(environment)
environments = [environment]
- # add test environment only if no RAILS_ENV was specified.
- environments << 'test' if environment == 'development' && ENV['RAILS_ENV'].nil?
+ environments << 'test' if environment == 'development'
configurations = ActiveRecord::Base.configurations.values_at(*environments)
configurations.compact.each do |configuration|
diff --git a/activerecord/lib/active_record/tasks/mysql_database_tasks.rb b/activerecord/lib/active_record/tasks/mysql_database_tasks.rb
index 7a49322e06..af0c935342 100644
--- a/activerecord/lib/active_record/tasks/mysql_database_tasks.rb
+++ b/activerecord/lib/active_record/tasks/mysql_database_tasks.rb
@@ -130,7 +130,7 @@ IDENTIFIED BY '#{configuration['password']}' WITH GRANT OPTION;
'sslca' => '--ssl-ca',
'sslcert' => '--ssl-cert',
'sslcapath' => '--ssl-capath',
- 'sslcipher' => '--ssh-cipher',
+ 'sslcipher' => '--ssl-cipher',
'sslkey' => '--ssl-key'
}.map { |opt, arg| "#{arg}=#{configuration[opt]}" if configuration[opt] }.compact
diff --git a/activerecord/lib/active_record/type.rb b/activerecord/lib/active_record/type.rb
index e210e94f00..4911d93dd9 100644
--- a/activerecord/lib/active_record/type.rb
+++ b/activerecord/lib/active_record/type.rb
@@ -61,7 +61,7 @@ module ActiveRecord
register(:binary, Type::Binary, override: false)
register(:boolean, Type::Boolean, override: false)
register(:date, Type::Date, override: false)
- register(:date_time, Type::DateTime, override: false)
+ register(:datetime, Type::DateTime, override: false)
register(:decimal, Type::Decimal, override: false)
register(:float, Type::Float, override: false)
register(:integer, Type::Integer, override: false)
diff --git a/activerecord/test/cases/adapters/mysql2/case_sensitivity_test.rb b/activerecord/test/cases/adapters/mysql2/case_sensitivity_test.rb
index 963116f08a..9cb05119a2 100644
--- a/activerecord/test/cases/adapters/mysql2/case_sensitivity_test.rb
+++ b/activerecord/test/cases/adapters/mysql2/case_sensitivity_test.rb
@@ -51,4 +51,13 @@ class Mysql2CaseSensitivityTest < ActiveRecord::Mysql2TestCase
cs_uniqueness_query = queries.detect { |q| q.match(/string_cs_column/) }
assert_no_match(/binary/i, cs_uniqueness_query)
end
+
+ def test_case_sensitive_comparison_for_binary_column
+ CollationTest.validates_uniqueness_of(:binary_column, case_sensitive: true)
+ CollationTest.create!(binary_column: 'A')
+ invalid = CollationTest.new(binary_column: 'A')
+ queries = assert_sql { invalid.save }
+ bin_uniqueness_query = queries.detect { |q| q.match(/binary_column/) }
+ assert_no_match(/\bBINARY\b/, bin_uniqueness_query)
+ end
end
diff --git a/activerecord/test/cases/adapters/mysql2/connection_test.rb b/activerecord/test/cases/adapters/mysql2/connection_test.rb
index 575138eb2a..c4715393b3 100644
--- a/activerecord/test/cases/adapters/mysql2/connection_test.rb
+++ b/activerecord/test/cases/adapters/mysql2/connection_test.rb
@@ -69,40 +69,48 @@ class Mysql2ConnectionTest < ActiveRecord::Mysql2TestCase
end
def test_mysql_default_in_strict_mode
- result = @connection.exec_query "SELECT @@SESSION.sql_mode"
- assert_equal [["STRICT_ALL_TABLES"]], result.rows
+ result = @connection.select_value("SELECT @@SESSION.sql_mode")
+ assert_match %r(STRICT_ALL_TABLES), result
end
def test_mysql_strict_mode_disabled
run_without_connection do |orig_connection|
- ActiveRecord::Base.establish_connection(orig_connection.merge({:strict => false}))
- result = ActiveRecord::Base.connection.exec_query "SELECT @@SESSION.sql_mode"
- assert_equal [['']], result.rows
+ ActiveRecord::Base.establish_connection(orig_connection.merge(strict: false))
+ result = ActiveRecord::Base.connection.select_value("SELECT @@SESSION.sql_mode")
+ assert_no_match %r(STRICT_ALL_TABLES), result
+ end
+ end
+
+ def test_mysql_strict_mode_specified_default
+ run_without_connection do |orig_connection|
+ ActiveRecord::Base.establish_connection(orig_connection.merge(strict: :default))
+ global_sql_mode = ActiveRecord::Base.connection.select_value("SELECT @@GLOBAL.sql_mode")
+ session_sql_mode = ActiveRecord::Base.connection.select_value("SELECT @@SESSION.sql_mode")
+ assert_equal global_sql_mode, session_sql_mode
+ end
+ end
+
+ def test_mysql_sql_mode_variable_overrides_strict_mode
+ run_without_connection do |orig_connection|
+ ActiveRecord::Base.establish_connection(orig_connection.deep_merge(variables: { 'sql_mode' => 'ansi' }))
+ result = ActiveRecord::Base.connection.select_value('SELECT @@SESSION.sql_mode')
+ assert_no_match %r(STRICT_ALL_TABLES), result
end
end
def test_passing_arbitary_flags_to_adapter
- run_without_connection do |orig_connection|
+ run_without_connection do |orig_connection|
ActiveRecord::Base.establish_connection(orig_connection.merge({flags: Mysql2::Client::COMPRESS}))
assert_equal (Mysql2::Client::COMPRESS | Mysql2::Client::FOUND_ROWS), ActiveRecord::Base.connection.raw_connection.query_options[:flags]
end
end
-
+
def test_passing_flags_by_array_to_adapter
- run_without_connection do |orig_connection|
+ run_without_connection do |orig_connection|
ActiveRecord::Base.establish_connection(orig_connection.merge({flags: ['COMPRESS'] }))
assert_equal ["COMPRESS", "FOUND_ROWS"], ActiveRecord::Base.connection.raw_connection.query_options[:flags]
end
end
-
- def test_mysql_strict_mode_specified_default
- run_without_connection do |orig_connection|
- ActiveRecord::Base.establish_connection(orig_connection.merge({strict: :default}))
- global_sql_mode = ActiveRecord::Base.connection.exec_query "SELECT @@GLOBAL.sql_mode"
- session_sql_mode = ActiveRecord::Base.connection.exec_query "SELECT @@SESSION.sql_mode"
- assert_equal global_sql_mode.rows, session_sql_mode.rows
- end
- end
def test_mysql_set_session_variable
run_without_connection do |orig_connection|
@@ -112,14 +120,6 @@ class Mysql2ConnectionTest < ActiveRecord::Mysql2TestCase
end
end
- def test_mysql_sql_mode_variable_overrides_strict_mode
- run_without_connection do |orig_connection|
- ActiveRecord::Base.establish_connection(orig_connection.deep_merge(variables: { 'sql_mode' => 'ansi' }))
- result = ActiveRecord::Base.connection.exec_query 'SELECT @@SESSION.sql_mode'
- assert_not_equal [['STRICT_ALL_TABLES']], result.rows
- end
- end
-
def test_mysql_set_session_variable_to_default
run_without_connection do |orig_connection|
ActiveRecord::Base.establish_connection(orig_connection.deep_merge({:variables => {:default_week_format => :default}}))
diff --git a/activerecord/test/cases/adapters/mysql2/unsigned_type_test.rb b/activerecord/test/cases/adapters/mysql2/unsigned_type_test.rb
index c95a64cc16..0a9703263e 100644
--- a/activerecord/test/cases/adapters/mysql2/unsigned_type_test.rb
+++ b/activerecord/test/cases/adapters/mysql2/unsigned_type_test.rb
@@ -58,7 +58,7 @@ class Mysql2UnsignedTypeTest < ActiveRecord::Mysql2TestCase
test "schema dump includes unsigned option" do
schema = dump_table_schema "unsigned_types"
assert_match %r{t.integer\s+"unsigned_integer",\s+unsigned: true$}, schema
- assert_match %r{t.integer\s+"unsigned_bigint",\s+limit: 8,\s+unsigned: true$}, schema
+ assert_match %r{t.bigint\s+"unsigned_bigint",\s+unsigned: true$}, schema
assert_match %r{t.float\s+"unsigned_float",\s+limit: 24,\s+unsigned: true$}, schema
assert_match %r{t.decimal\s+"unsigned_decimal",\s+precision: 10,\s+scale: 2,\s+unsigned: true$}, schema
end
diff --git a/activerecord/test/cases/adapters/postgresql/bytea_test.rb b/activerecord/test/cases/adapters/postgresql/bytea_test.rb
index b6bb1929e6..7adc070430 100644
--- a/activerecord/test/cases/adapters/postgresql/bytea_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/bytea_test.rb
@@ -1,6 +1,9 @@
require "cases/helper"
+require 'support/schema_dumping_helper'
class PostgresqlByteaTest < ActiveRecord::PostgreSQLTestCase
+ include SchemaDumpingHelper
+
class ByteaDataType < ActiveRecord::Base
self.table_name = 'bytea_data_type'
end
@@ -122,4 +125,10 @@ class PostgresqlByteaTest < ActiveRecord::PostgreSQLTestCase
obj.reload
assert_equal "hello world", obj.serialized
end
+
+ def test_schema_dumping
+ output = dump_table_schema("bytea_data_type")
+ assert_match %r{t\.binary\s+"payload"$}, output
+ assert_match %r{t\.binary\s+"serialized"$}, output
+ end
end
diff --git a/activerecord/test/cases/adapters/postgresql/serial_test.rb b/activerecord/test/cases/adapters/postgresql/serial_test.rb
index 7d30db247b..8abe064bf1 100644
--- a/activerecord/test/cases/adapters/postgresql/serial_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/serial_test.rb
@@ -10,6 +10,7 @@ class PostgresqlSerialTest < ActiveRecord::PostgreSQLTestCase
@connection = ActiveRecord::Base.connection
@connection.create_table "postgresql_serials", force: true do |t|
t.serial :seq
+ t.integer :serials_id, default: -> { "nextval('postgresql_serials_id_seq')" }
end
end
@@ -24,9 +25,21 @@ class PostgresqlSerialTest < ActiveRecord::PostgreSQLTestCase
assert column.serial?
end
+ def test_not_serial_column
+ column = PostgresqlSerial.columns_hash["serials_id"]
+ assert_equal :integer, column.type
+ assert_equal "integer", column.sql_type
+ assert_not column.serial?
+ end
+
def test_schema_dump_with_shorthand
output = dump_table_schema "postgresql_serials"
- assert_match %r{t\.serial\s+"seq"}, output
+ assert_match %r{t\.serial\s+"seq",\s+null: false$}, output
+ end
+
+ def test_schema_dump_with_not_serial
+ output = dump_table_schema "postgresql_serials"
+ assert_match %r{t\.integer\s+"serials_id",\s+default: -> \{ "nextval\('postgresql_serials_id_seq'::regclass\)" \}$}, output
end
end
@@ -39,6 +52,7 @@ class PostgresqlBigSerialTest < ActiveRecord::PostgreSQLTestCase
@connection = ActiveRecord::Base.connection
@connection.create_table "postgresql_big_serials", force: true do |t|
t.bigserial :seq
+ t.bigint :serials_id, default: -> { "nextval('postgresql_big_serials_id_seq')" }
end
end
@@ -53,8 +67,20 @@ class PostgresqlBigSerialTest < ActiveRecord::PostgreSQLTestCase
assert column.serial?
end
+ def test_not_bigserial_column
+ column = PostgresqlBigSerial.columns_hash["serials_id"]
+ assert_equal :integer, column.type
+ assert_equal "bigint", column.sql_type
+ assert_not column.serial?
+ end
+
def test_schema_dump_with_shorthand
output = dump_table_schema "postgresql_big_serials"
- assert_match %r{t\.bigserial\s+"seq"}, output
+ assert_match %r{t\.bigserial\s+"seq",\s+null: false$}, output
+ end
+
+ def test_schema_dump_with_not_bigserial
+ output = dump_table_schema "postgresql_big_serials"
+ assert_match %r{t\.bigint\s+"serials_id",\s+default: -> \{ "nextval\('postgresql_big_serials_id_seq'::regclass\)" \}$}, output
end
end
diff --git a/activerecord/test/cases/associations/join_model_test.rb b/activerecord/test/cases/associations/join_model_test.rb
index 1d892a0956..c7bd9d2119 100644
--- a/activerecord/test/cases/associations/join_model_test.rb
+++ b/activerecord/test/cases/associations/join_model_test.rb
@@ -747,6 +747,23 @@ class AssociationsJoinModelTest < ActiveRecord::TestCase
assert_equal aircraft.engines, [engine]
end
+ def test_proper_error_message_for_eager_load_and_includes_association_errors
+ includes_error = assert_raises(ActiveRecord::ConfigurationError) {
+ Post.includes(:nonexistent_relation).where(nonexistent_relation: {name: 'Rochester'}).find(1)
+ }
+ assert_equal("Can't join 'Post' to association named 'nonexistent_relation'; perhaps you misspelled it?", includes_error.message)
+
+ eager_load_error = assert_raises(ActiveRecord::ConfigurationError) {
+ Post.eager_load(:nonexistent_relation).where(nonexistent_relation: {name: 'Rochester'}).find(1)
+ }
+ assert_equal("Can't join 'Post' to association named 'nonexistent_relation'; perhaps you misspelled it?", eager_load_error.message)
+
+ includes_and_eager_load_error = assert_raises(ActiveRecord::ConfigurationError) {
+ Post.eager_load(:nonexistent_relation).includes(:nonexistent_relation).where(nonexistent_relation: {name: 'Rochester'}).find(1)
+ }
+ assert_equal("Can't join 'Post' to association named 'nonexistent_relation'; perhaps you misspelled it?", includes_and_eager_load_error.message)
+ end
+
private
# create dynamic Post models to allow different dependency options
def find_post_with_dependency(post_id, association, association_name, dependency)
diff --git a/activerecord/test/cases/autosave_association_test.rb b/activerecord/test/cases/autosave_association_test.rb
index 3608063b01..9e3266b7d6 100644
--- a/activerecord/test/cases/autosave_association_test.rb
+++ b/activerecord/test/cases/autosave_association_test.rb
@@ -749,7 +749,7 @@ class TestDestroyAsPartOfAutosaveAssociation < ActiveRecord::TestCase
end
# has_one
- def test_should_destroy_a_child_association_as_part_of_the_save_transaction_if_it_was_marked_for_destroyal
+ def test_should_destroy_a_child_association_as_part_of_the_save_transaction_if_it_was_marked_for_destruction
assert !@pirate.ship.marked_for_destruction?
@pirate.ship.mark_for_destruction
@@ -809,7 +809,7 @@ class TestDestroyAsPartOfAutosaveAssociation < ActiveRecord::TestCase
end
# belongs_to
- def test_should_destroy_a_parent_association_as_part_of_the_save_transaction_if_it_was_marked_for_destroyal
+ def test_should_destroy_a_parent_association_as_part_of_the_save_transaction_if_it_was_marked_for_destruction
assert !@ship.pirate.marked_for_destruction?
@ship.pirate.mark_for_destruction
diff --git a/activerecord/test/cases/inheritance_test.rb b/activerecord/test/cases/inheritance_test.rb
index 7da6842047..e234b9a6a9 100644
--- a/activerecord/test/cases/inheritance_test.rb
+++ b/activerecord/test/cases/inheritance_test.rb
@@ -441,12 +441,7 @@ class InheritanceComputeTypeTest < ActiveRecord::TestCase
include InheritanceTestHelper
fixtures :companies
- def setup
- ActiveSupport::Dependencies.log_activity = true
- end
-
teardown do
- ActiveSupport::Dependencies.log_activity = false
self.class.const_remove :FirmOnTheFly rescue nil
Firm.const_remove :FirmOnTheFly rescue nil
end
diff --git a/activerecord/test/cases/primary_keys_test.rb b/activerecord/test/cases/primary_keys_test.rb
index 6aaee8de7c..32bccce2ed 100644
--- a/activerecord/test/cases/primary_keys_test.rb
+++ b/activerecord/test/cases/primary_keys_test.rb
@@ -351,9 +351,9 @@ if current_adapter?(:PostgreSQLAdapter, :Mysql2Adapter)
test "schema dump primary key with bigserial" do
schema = dump_table_schema "widgets"
if current_adapter?(:PostgreSQLAdapter)
- assert_match %r{create_table "widgets", id: :bigserial}, schema
+ assert_match %r{create_table "widgets", id: :bigserial, force: :cascade}, schema
else
- assert_match %r{create_table "widgets", id: :bigint}, schema
+ assert_match %r{create_table "widgets", id: :bigint, force: :cascade}, schema
end
end
diff --git a/activerecord/test/cases/schema_dumper_test.rb b/activerecord/test/cases/schema_dumper_test.rb
index 8def74e75b..12c8a1d5ba 100644
--- a/activerecord/test/cases/schema_dumper_test.rb
+++ b/activerecord/test/cases/schema_dumper_test.rb
@@ -147,10 +147,10 @@ class SchemaDumperTest < ActiveRecord::TestCase
assert_match %r{c_int_7.*limit: 7}, output
assert_match %r{c_int_8.*limit: 8}, output
else
- assert_match %r{c_int_5.*limit: 8}, output
- assert_match %r{c_int_6.*limit: 8}, output
- assert_match %r{c_int_7.*limit: 8}, output
- assert_match %r{c_int_8.*limit: 8}, output
+ assert_match %r{t\.bigint\s+"c_int_5"$}, output
+ assert_match %r{t\.bigint\s+"c_int_6"$}, output
+ assert_match %r{t\.bigint\s+"c_int_7"$}, output
+ assert_match %r{t\.bigint\s+"c_int_8"$}, output
end
end
@@ -248,12 +248,12 @@ class SchemaDumperTest < ActiveRecord::TestCase
if current_adapter?(:PostgreSQLAdapter)
def test_schema_dump_includes_bigint_default
output = standard_dump
- assert_match %r{t\.integer\s+"bigint_default",\s+limit: 8,\s+default: 0}, output
+ assert_match %r{t\.bigint\s+"bigint_default",\s+default: 0}, output
end
def test_schema_dump_includes_limit_on_array_type
output = standard_dump
- assert_match %r{t\.integer\s+"big_int_data_points\",\s+limit: 8,\s+array: true}, output
+ assert_match %r{t\.bigint\s+"big_int_data_points\",\s+array: true}, output
end
def test_schema_dump_allows_array_of_decimal_defaults
diff --git a/activerecord/test/cases/scoping/default_scoping_test.rb b/activerecord/test/cases/scoping/default_scoping_test.rb
index c918cbdef5..dcd09b6973 100644
--- a/activerecord/test/cases/scoping/default_scoping_test.rb
+++ b/activerecord/test/cases/scoping/default_scoping_test.rb
@@ -4,6 +4,7 @@ require 'models/comment'
require 'models/developer'
require 'models/computer'
require 'models/vehicle'
+require 'models/cat'
class DefaultScopingTest < ActiveRecord::TestCase
fixtures :developers, :posts, :comments
@@ -485,4 +486,15 @@ class DefaultScopingTest < ActiveRecord::TestCase
assert_equal 1, SubConditionalStiPost.all.to_a.size
assert_equal 2, SubConditionalStiPost.unscope(where: :title).to_a.size
end
+
+ def test_with_abstract_class_scope_should_be_executed_in_correct_context
+ vegetarian_pattern, gender_pattern = if current_adapter?(:Mysql2Adapter)
+ [/`lions`.`is_vegetarian`/, /`lions`.`gender`/]
+ else
+ [/"lions"."is_vegetarian"/, /"lions"."gender"/]
+ end
+
+ assert_match vegetarian_pattern, Lion.all.to_sql
+ assert_match gender_pattern, Lion.female.to_sql
+ end
end
diff --git a/activerecord/test/cases/tasks/database_tasks_test.rb b/activerecord/test/cases/tasks/database_tasks_test.rb
index 49df6628eb..429aeca1d9 100644
--- a/activerecord/test/cases/tasks/database_tasks_test.rb
+++ b/activerecord/test/cases/tasks/database_tasks_test.rb
@@ -161,21 +161,25 @@ module ActiveRecord
with('database' => 'dev-db')
ActiveRecord::Tasks::DatabaseTasks.expects(:create).
with('database' => 'test-db')
- ENV.expects(:[]).with('RAILS_ENV').returns(nil)
ActiveRecord::Tasks::DatabaseTasks.create_current(
ActiveSupport::StringInquirer.new('development')
)
end
- def test_creates_only_development_database_when_rails_env_is_development
+ def test_creates_test_and_development_databases_when_rails_env_is_development
+ old_env = ENV['RAILS_ENV']
+ ENV['RAILS_ENV'] = 'development'
ActiveRecord::Tasks::DatabaseTasks.expects(:create).
with('database' => 'dev-db')
- ENV.expects(:[]).with('RAILS_ENV').returns('development')
+ ActiveRecord::Tasks::DatabaseTasks.expects(:create).
+ with('database' => 'test-db')
ActiveRecord::Tasks::DatabaseTasks.create_current(
ActiveSupport::StringInquirer.new('development')
)
+ ensure
+ ENV['RAILS_ENV'] = old_env
end
def test_establishes_connection_for_the_given_environment
@@ -282,21 +286,25 @@ module ActiveRecord
with('database' => 'dev-db')
ActiveRecord::Tasks::DatabaseTasks.expects(:drop).
with('database' => 'test-db')
- ENV.expects(:[]).with('RAILS_ENV').returns(nil)
ActiveRecord::Tasks::DatabaseTasks.drop_current(
ActiveSupport::StringInquirer.new('development')
)
end
- def test_drops_only_development_database_when_rails_env_is_development
+ def test_drops_testand_development_databases_when_rails_env_is_development
+ old_env = ENV['RAILS_ENV']
+ ENV['RAILS_ENV'] = 'development'
ActiveRecord::Tasks::DatabaseTasks.expects(:drop).
with('database' => 'dev-db')
- ENV.expects(:[]).with('RAILS_ENV').returns('development')
+ ActiveRecord::Tasks::DatabaseTasks.expects(:drop).
+ with('database' => 'test-db')
ActiveRecord::Tasks::DatabaseTasks.drop_current(
ActiveSupport::StringInquirer.new('development')
)
+ ensure
+ ENV['RAILS_ENV'] = old_env
end
end
diff --git a/activerecord/test/cases/validations/i18n_validation_test.rb b/activerecord/test/cases/validations/i18n_validation_test.rb
index 981239c4d6..b8307d6665 100644
--- a/activerecord/test/cases/validations/i18n_validation_test.rb
+++ b/activerecord/test/cases/validations/i18n_validation_test.rb
@@ -47,8 +47,6 @@ class I18nValidationTest < ActiveRecord::TestCase
# [ "given on condition", {on: :save}, {}]
]
- # validates_uniqueness_of w/ mocha
-
COMMON_CASES.each do |name, validation_options, generate_message_options|
test "validates_uniqueness_of on generated message #{name}" do
Topic.validates_uniqueness_of :title, validation_options
@@ -59,8 +57,6 @@ class I18nValidationTest < ActiveRecord::TestCase
end
end
- # validates_associated w/ mocha
-
COMMON_CASES.each do |name, validation_options, generate_message_options|
test "validates_associated on generated message #{name}" do
Topic.validates_associated :replies, validation_options
@@ -70,8 +66,6 @@ class I18nValidationTest < ActiveRecord::TestCase
end
end
- # validates_associated w/o mocha
-
def test_validates_associated_finds_custom_model_key_translation
I18n.backend.store_translations 'en', :activerecord => {:errors => {:models => {:topic => {:attributes => {:replies => {:invalid => 'custom message'}}}}}}
I18n.backend.store_translations 'en', :activerecord => {:errors => {:messages => {:invalid => 'global message'}}}
diff --git a/activerecord/test/models/cat.rb b/activerecord/test/models/cat.rb
new file mode 100644
index 0000000000..dfdde18641
--- /dev/null
+++ b/activerecord/test/models/cat.rb
@@ -0,0 +1,10 @@
+class Cat < ActiveRecord::Base
+ self.abstract_class = true
+
+ enum gender: [:female, :male]
+
+ default_scope -> { where(is_vegetarian: false) }
+end
+
+class Lion < Cat
+end
diff --git a/activerecord/test/schema/mysql2_specific_schema.rb b/activerecord/test/schema/mysql2_specific_schema.rb
index 101e657982..5a49b38457 100644
--- a/activerecord/test/schema/mysql2_specific_schema.rb
+++ b/activerecord/test/schema/mysql2_specific_schema.rb
@@ -33,6 +33,7 @@ ActiveRecord::Schema.define do
create_table :collation_tests, id: false, force: true do |t|
t.string :string_cs_column, limit: 1, collation: 'utf8_bin'
t.string :string_ci_column, limit: 1, collation: 'utf8_general_ci'
+ t.binary :binary_column, limit: 1
end
ActiveRecord::Base.connection.execute <<-SQL
diff --git a/activerecord/test/schema/schema.rb b/activerecord/test/schema/schema.rb
index 2a8996f35c..01dbf2cee6 100644
--- a/activerecord/test/schema/schema.rb
+++ b/activerecord/test/schema/schema.rb
@@ -421,6 +421,11 @@ ActiveRecord::Schema.define do
t.integer :amount
end
+ create_table :lions, force: true do |t|
+ t.integer :gender
+ t.boolean :is_vegetarian, default: false
+ end
+
create_table :lock_without_defaults, force: true do |t|
t.column :lock_version, :integer
end
diff --git a/activesupport/CHANGELOG.md b/activesupport/CHANGELOG.md
index d4d4491ae3..b020f3bd41 100644
--- a/activesupport/CHANGELOG.md
+++ b/activesupport/CHANGELOG.md
@@ -1,8 +1,13 @@
+* Prevent `Marshal.load` from looping infinitely when trying to autoload a constant
+ which resolves to a different name.
+
+ *Olek Janiszewski*
+
* Deprecate `Module.local_constants`. Please use `Module.constants(false)` instead.
*Yuichiro Kaneko*
-* Publish ActiveSupport::Executor and ActiveSupport::Reloader APIs to allow
+* Publish `ActiveSupport::Executor` and `ActiveSupport::Reloader` APIs to allow
components and libraries to manage, and participate in, the execution of
application code, and the application reloading process.
@@ -41,7 +46,7 @@
## Rails 5.0.0.beta2 (February 01, 2016) ##
-* Change number_to_currency behavior for checking negativity.
+* Change `number_to_currency` behavior for checking negativity.
Used `to_f.negative` instead of using `to_f.phase` for checking negativity
of a number in number_to_currency helper.
diff --git a/activesupport/activesupport.gemspec b/activesupport/activesupport.gemspec
index 68a80701ed..71fe4d7253 100644
--- a/activesupport/activesupport.gemspec
+++ b/activesupport/activesupport.gemspec
@@ -13,7 +13,7 @@ Gem::Specification.new do |s|
s.author = 'David Heinemeier Hansson'
s.email = 'david@loudthinking.com'
- s.homepage = 'http://www.rubyonrails.org'
+ s.homepage = 'http://rubyonrails.org'
s.files = Dir['CHANGELOG.md', 'MIT-LICENSE', 'README.rdoc', 'lib/**/*']
s.require_path = 'lib'
diff --git a/activesupport/lib/active_support/core_ext/date_and_time/calculations.rb b/activesupport/lib/active_support/core_ext/date_and_time/calculations.rb
index 2de0d19a7e..4da7fdd159 100644
--- a/activesupport/lib/active_support/core_ext/date_and_time/calculations.rb
+++ b/activesupport/lib/active_support/core_ext/date_and_time/calculations.rb
@@ -1,3 +1,5 @@
+require 'active_support/core_ext/object/try'
+
module DateAndTime
module Calculations
DAYS_INTO_WEEK = {
diff --git a/activesupport/lib/active_support/core_ext/marshal.rb b/activesupport/lib/active_support/core_ext/marshal.rb
index e333b26133..ca278cb2fa 100644
--- a/activesupport/lib/active_support/core_ext/marshal.rb
+++ b/activesupport/lib/active_support/core_ext/marshal.rb
@@ -5,7 +5,10 @@ module ActiveSupport
rescue ArgumentError, NameError => exc
if exc.message.match(%r|undefined class/module (.+)|)
# try loading the class/module
- $1.constantize
+ loaded = $1.constantize
+
+ raise unless $1 == loaded.name
+
# if it is an IO we need to go back to read the object
source.rewind if source.respond_to?(:rewind)
retry
diff --git a/activesupport/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb b/activesupport/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb
index 8a7e6776da..0b3d18301e 100644
--- a/activesupport/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb
+++ b/activesupport/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb
@@ -47,7 +47,7 @@ class Module
unless options[:instance_reader] == false || options[:instance_accessor] == false
class_eval(<<-EOS, __FILE__, __LINE__ + 1)
def #{sym}
- Thread.current[:"attr_#{self.class.name}_#{sym}"]
+ Thread.current[:"attr_#{name}_#{sym}"]
end
EOS
end
@@ -86,7 +86,7 @@ class Module
unless options[:instance_writer] == false || options[:instance_accessor] == false
class_eval(<<-EOS, __FILE__, __LINE__ + 1)
def #{sym}=(obj)
- Thread.current[:"attr_#{self.class.name}_#{sym}"] = obj
+ Thread.current[:"attr_#{name}_#{sym}"] = obj
end
EOS
end
diff --git a/activesupport/lib/active_support/dependencies.rb b/activesupport/lib/active_support/dependencies.rb
index 0da01b0fe8..57f6286de3 100644
--- a/activesupport/lib/active_support/dependencies.rb
+++ b/activesupport/lib/active_support/dependencies.rb
@@ -88,15 +88,6 @@ module ActiveSupport #:nodoc:
mattr_accessor :explicitly_unloadable_constants
self.explicitly_unloadable_constants = []
- # The logger is used for generating information on the action run-time
- # (including benchmarking) if available. Can be set to nil for no logging.
- # Compatible with both Ruby's own Logger and Log4r loggers.
- mattr_accessor :logger
-
- # Set to +true+ to enable logging of const_missing and file loads.
- mattr_accessor :log_activity
- self.log_activity = false
-
# The WatchStack keeps a stack of the modules being watched as files are
# loaded. If a file in the process of being loaded (parent.rb) triggers the
# load of another file (child.rb) the stack will ensure that child.rb
@@ -352,7 +343,6 @@ module ActiveSupport #:nodoc:
end
def clear
- log_call
Dependencies.unload_interlock do
loaded.clear
loading.clear
@@ -361,7 +351,6 @@ module ActiveSupport #:nodoc:
end
def require_or_load(file_name, const_path = nil)
- log_call file_name, const_path
file_name = $` if file_name =~ /\.rb\z/
expanded = File.expand_path(file_name)
return if loaded.include?(expanded)
@@ -377,8 +366,6 @@ module ActiveSupport #:nodoc:
begin
if load?
- log "loading #{file_name}"
-
# Enable warnings if this file has not been loaded before and
# warnings_on_first_load is set.
load_args = ["#{file_name}.rb"]
@@ -390,7 +377,6 @@ module ActiveSupport #:nodoc:
enable_warnings { result = load_file(*load_args) }
end
else
- log "requiring #{file_name}"
result = require file_name
end
rescue Exception
@@ -483,7 +469,6 @@ module ActiveSupport #:nodoc:
# set of names that the file at +path+ may define. See
# +loadable_constants_for_path+ for more details.
def load_file(path, const_paths = loadable_constants_for_path(path))
- log_call path, const_paths
const_paths = [const_paths].compact unless const_paths.is_a? Array
parent_paths = const_paths.collect { |const_path| const_path[/.*(?=::)/] || ::Object }
@@ -494,7 +479,6 @@ module ActiveSupport #:nodoc:
autoloaded_constants.concat newly_defined_paths unless load_once_path?(path)
autoloaded_constants.uniq!
- log "loading #{path} defined #{newly_defined_paths * ', '}" unless newly_defined_paths.empty?
result
end
@@ -508,8 +492,6 @@ module ActiveSupport #:nodoc:
# it is not possible to load the constant into from_mod, try its parent
# module using +const_missing+.
def load_missing_constant(from_mod, const_name)
- log_call from_mod, const_name
-
unless qualified_const_defined?(from_mod.name) && Inflector.constantize(from_mod.name).equal?(from_mod)
raise ArgumentError, "A copy of #{from_mod} has been removed from the module tree but is still active!"
end
@@ -673,25 +655,20 @@ module ActiveSupport #:nodoc:
# exception, any new constants are regarded as being only partially defined
# and will be removed immediately.
def new_constants_in(*descs)
- log_call(*descs)
-
constant_watch_stack.watch_namespaces(descs)
- aborting = true
+ success = false
begin
yield # Now yield to the code that is to define new constants.
- aborting = false
+ success = true
ensure
new_constants = constant_watch_stack.new_constants
- log "New constants: #{new_constants * ', '}"
- return new_constants unless aborting
+ return new_constants if success
- log "Error during loading, removing partially loaded constants "
- new_constants.each { |c| remove_constant(c) }.clear
+ # Remove partially loaded constants.
+ new_constants.each { |c| remove_constant(c) }
end
-
- []
end
# Convert the provided const desc to a qualified constant name (as a string).
@@ -738,8 +715,6 @@ module ActiveSupport #:nodoc:
parent = constantize(parent_name)
end
- log "removing constant #{const}"
-
# In an autoloaded user.rb like this
#
# autoload :Foo, 'foo'
@@ -760,7 +735,7 @@ module ActiveSupport #:nodoc:
begin
constantized = parent.const_get(to_remove, false)
rescue NameError
- log "the constant #{const} is not reachable anymore, skipping"
+ # The constant is no longer reachable, just skip it.
return
else
constantized.before_remove_const if constantized.respond_to?(:before_remove_const)
@@ -770,27 +745,9 @@ module ActiveSupport #:nodoc:
begin
parent.instance_eval { remove_const to_remove }
rescue NameError
- log "the constant #{const} is not reachable anymore, skipping"
+ # The constant is no longer reachable, just skip it.
end
end
-
- protected
- def log_call(*args)
- if log_activity?
- arg_str = args.collect(&:inspect) * ', '
- /in `([a-z_\?\!]+)'/ =~ caller(1).first
- selector = $1 || '<unknown>'
- log "called #{selector}(#{arg_str})"
- end
- end
-
- def log(msg)
- logger.debug "Dependencies: #{msg}" if log_activity?
- end
-
- def log_activity?
- logger && log_activity
- end
end
end
diff --git a/activesupport/lib/active_support/evented_file_update_checker.rb b/activesupport/lib/active_support/evented_file_update_checker.rb
index 63f4f7e277..6a02a838b7 100644
--- a/activesupport/lib/active_support/evented_file_update_checker.rb
+++ b/activesupport/lib/active_support/evented_file_update_checker.rb
@@ -21,7 +21,13 @@ module ActiveSupport
# Loading listen triggers warnings. These are originated by a legit
# usage of attr_* macros for private attributes, but adds a lot of noise
# to our test suite. Thus, we lazy load it and disable warnings locally.
- silence_warnings { require 'listen' }
+ silence_warnings do
+ begin
+ require 'listen'
+ rescue LoadError => e
+ raise LoadError, "Could not load the 'listen' gem. Add `gem 'listen'` to the development group of your Gemfile", e.backtrace
+ end
+ end
Listen.to(*dtw, &method(:changed)).start
end
end
diff --git a/activesupport/lib/active_support/file_update_checker.rb b/activesupport/lib/active_support/file_update_checker.rb
index dc7434fcac..8708a502e6 100644
--- a/activesupport/lib/active_support/file_update_checker.rb
+++ b/activesupport/lib/active_support/file_update_checker.rb
@@ -23,7 +23,7 @@ module ActiveSupport
# I18n.reload!
# end
#
- # ActionDispatch::Reloader.to_prepare do
+ # ActiveSupport::Reloader.to_prepare do
# i18n_reloader.execute_if_updated
# end
class FileUpdateChecker
diff --git a/activesupport/lib/active_support/rescuable.rb b/activesupport/lib/active_support/rescuable.rb
index fcf5553061..73bc52b56f 100644
--- a/activesupport/lib/active_support/rescuable.rb
+++ b/activesupport/lib/active_support/rescuable.rb
@@ -115,5 +115,15 @@ module ActiveSupport
end
end
end
+
+ def index_of_handler_for_rescue(exception)
+ handlers = self.class.rescue_handlers.reverse_each.with_index
+ _, index = handlers.detect do |(klass_name, _), _|
+ klass = self.class.const_get(klass_name) rescue nil
+ klass ||= (klass_name.constantize rescue nil)
+ klass === exception if klass
+ end
+ index
+ end
end
end
diff --git a/activesupport/lib/active_support/values/time_zone.rb b/activesupport/lib/active_support/values/time_zone.rb
index 7ca3592520..118bf8eab0 100644
--- a/activesupport/lib/active_support/values/time_zone.rb
+++ b/activesupport/lib/active_support/values/time_zone.rb
@@ -1,7 +1,6 @@
require 'tzinfo'
require 'concurrent/map'
require 'active_support/core_ext/object/blank'
-require 'active_support/core_ext/object/try'
module ActiveSupport
# The TimeZone class serves as a wrapper around TZInfo::Timezone instances.
diff --git a/activesupport/test/autoloading_fixtures/raises_arbitrary_exception.rb b/activesupport/test/autoloading_fixtures/raises_arbitrary_exception.rb
new file mode 100644
index 0000000000..404ae289c6
--- /dev/null
+++ b/activesupport/test/autoloading_fixtures/raises_arbitrary_exception.rb
@@ -0,0 +1,4 @@
+RaisesArbitraryException = 1
+A::B # Autoloading recursion, also expected to be watched and discarded.
+
+raise Exception, 'arbitray exception message'
diff --git a/activesupport/test/autoloading_fixtures/throws.rb b/activesupport/test/autoloading_fixtures/throws.rb
new file mode 100644
index 0000000000..5e47b9699b
--- /dev/null
+++ b/activesupport/test/autoloading_fixtures/throws.rb
@@ -0,0 +1,4 @@
+Throws = 1
+A::B # Autoloading recursion, expected to be discarded.
+
+throw :t
diff --git a/activesupport/test/core_ext/marshal_test.rb b/activesupport/test/core_ext/marshal_test.rb
index 5427837d19..07c0c0d8cb 100644
--- a/activesupport/test/core_ext/marshal_test.rb
+++ b/activesupport/test/core_ext/marshal_test.rb
@@ -64,6 +64,17 @@ class MarshalTest < ActiveSupport::TestCase
end
end
+ test "when one constant resolves to another" do
+ class Parent; C = Class.new; end
+ class Child < Parent; C = Class.new; end
+
+ dump = Marshal.dump(Child::C.new)
+
+ Child.send(:remove_const, :C)
+
+ assert_raise(ArgumentError) { Marshal.load(dump) }
+ end
+
test "that a real missing class is causing an exception" do
dumped = nil
with_autoloading_fixtures do
diff --git a/activesupport/test/core_ext/module/attribute_accessor_per_thread_test.rb b/activesupport/test/core_ext/module/attribute_accessor_per_thread_test.rb
index 65fadc5c20..a9fd878b80 100644
--- a/activesupport/test/core_ext/module/attribute_accessor_per_thread_test.rb
+++ b/activesupport/test/core_ext/module/attribute_accessor_per_thread_test.rb
@@ -106,4 +106,10 @@ class ModuleAttributeAccessorPerThreadTest < ActiveSupport::TestCase
end
assert_equal "invalid attribute name: 2valid_part", exception.message
end
+
+ def test_should_return_same_value_by_class_or_instance_accessor
+ @class.foo = 'fries'
+
+ assert_equal @class.foo, @object.foo
+ end
end
diff --git a/activesupport/test/dependencies_test.rb b/activesupport/test/dependencies_test.rb
index b7a5747f1b..04e7b24d30 100644
--- a/activesupport/test/dependencies_test.rb
+++ b/activesupport/test/dependencies_test.rb
@@ -269,6 +269,28 @@ class DependenciesTest < ActiveSupport::TestCase
remove_constants(:ModuleFolder)
end
+ def test_raising_discards_autoloaded_constants
+ with_autoloading_fixtures do
+ assert_raises(Exception, 'arbitray exception message') { RaisesArbitraryException }
+ assert_not defined?(A)
+ assert_not defined?(RaisesArbitraryException)
+ end
+ ensure
+ remove_constants(:A, :RaisesArbitraryException)
+ end
+
+ def test_throwing_discards_autoloaded_constants
+ with_autoloading_fixtures do
+ catch :t do
+ Throws
+ end
+ assert_not defined?(A)
+ assert_not defined?(Throws)
+ end
+ ensure
+ remove_constants(:A, :Throws)
+ end
+
def test_doesnt_break_normal_require
path = File.expand_path("../autoloading_fixtures/load_path", __FILE__)
original_path = $:.dup
diff --git a/guides/assets/images/favicon.ico b/guides/assets/images/favicon.ico
index faa10b4580..87192a8a07 100644
--- a/guides/assets/images/favicon.ico
+++ b/guides/assets/images/favicon.ico
Binary files differ
diff --git a/guides/source/5_0_release_notes.md b/guides/source/5_0_release_notes.md
index dc631e5cb9..a868c5f856 100644
--- a/guides/source/5_0_release_notes.md
+++ b/guides/source/5_0_release_notes.md
@@ -94,6 +94,10 @@ Please refer to the [Changelog][railties] for detailed changes.
* Deprecated `config.serve_static_files` in favor of `config.public_file_server.enabled`.
([Pull Request](https://github.com/rails/rails/pull/22173))
+* Deprecated the tasks in the `rails` task namespace in favor of the `app` namespace.
+ (e.g. `rails:update` and `rails:template` tasks is renamed to `app:update` and `app:template`.)
+ ([Pull Request](https://github.com/rails/rails/pull/23439))
+
### Notable changes
* Added Rails test runner `bin/rails test`.
@@ -120,6 +124,23 @@ Please refer to the [Changelog][railties] for detailed changes.
([Pull Request](https://github.com/rails/rails/pull/22457),
[Pull Request](https://github.com/rails/rails/pull/22288))
+* New applications are generated with the evented file system monitor enabled
+ on Linux and Mac OS X. The feature can be opted out by passing
+ `--skip-listen` to the generator.
+ ([commit](https://github.com/rails/rails/commit/de6ad5665d2679944a9ee9407826ba88395a1003),
+ [commit](https://github.com/rails/rails/commit/94dbc48887bf39c241ee2ce1741ee680d773f202))
+
+* Generate applications with an option to log to STDOUT in production
+ using the environment variable `RAILS_LOG_TO_STDOUT`.
+ ([Pull Request](https://github.com/rails/rails/pull/23734))
+
+* Enable HSTS with IncludeSudomains header for new applications.
+ ([Pull Request](https://github.com/rails/rails/pull/23852))
+
+* The application generator writes a new file `config/spring.rb`, which tells
+ Spring to watch additional common files.
+ ([commit](https://github.com/rails/rails/commit/b04d07337fd7bc17e88500e9d6bcd361885a45f8))
+
Action Pack
-----------
@@ -262,6 +283,17 @@ Please refer to the [Changelog][action-pack] for detailed changes.
(Pull Request [1](https://github.com/rails/rails/pull/19377),
[2](https://github.com/rails/rails/pull/23827))
+* Added an option for per-form CSRF tokens.
+ ([Pull Request](https://github.com/rails/rails/pull/22275))
+
+* Added request encoding and response parsing to integration tests.
+ ([Pull Request](https://github.com/rails/rails/pull/21671))
+
+* Update default rendering policies when the controller action did
+ not explicitly indicate a response.
+ ([Pull Request](https://github.com/rails/rails/pull/23827))
+
+
Action View
-------------
@@ -286,8 +318,9 @@ Please refer to the [Changelog][action-view] for detailed changes.
* Changed the default template handler from `ERB` to `Raw`.
([commit](https://github.com/rails/rails/commit/4be859f0fdf7b3059a28d03c279f03f5938efc80))
-* Collection rendering automatically caches and fetches multiple partials.
- ([Pull Request](https://github.com/rails/rails/pull/18948))
+* Collection rendering can cache and fetches multiple partials.
+ ([Pull Request](https://github.com/rails/rails/pull/18948),
+ [commit](https://github.com/rails/rails/commit/e93f0f0f133717f9b06b1eaefd3442bd0ff43985))
* Allow defining explicit collection caching using a `# Template Collection: ...`
directive inside templates.
@@ -300,8 +333,8 @@ Please refer to the [Changelog][action-view] for detailed changes.
button on submit to prevent double submits.
([Pull Request](https://github.com/rails/rails/pull/21135))
-* Downcase model name in form submit tags rather than humanize.
- ([Pull Request](https://github.com/rails/rails/pull/22764))
+* Collection rendering can cache and fetch multiple partials at once.
+ ([Pull Request](https://github.com/rails/rails/pull/21135))
Action Mailer
@@ -336,7 +369,9 @@ Please refer to the [Changelog][action-mailer] for detailed changes.
the mailer queue name.
([Pull Request](https://github.com/rails/rails/pull/18587))
-* Added `config.action_mailer.perform_caching` configuration to determine whether your templates should perform caching or not.
+* Added support for fragment caching in Action Mailer views.
+ Added new config option `config.action_mailer.perform_caching` to determine
+ whether your templates should perform caching or not.
([Pull Request](https://github.com/rails/rails/pull/22825))
@@ -456,6 +491,10 @@ Please refer to the [Changelog][active-record] for detailed changes.
`offset` method on relation instead.
([Pull Request](https://github.com/rails/rails/pull/22053))
+* Deprecated `{insert|update|delete}_sql` in `DatabaseStatements`.
+ Use the `{insert|update|delete}` public methods instead.
+ ([Pull Request](https://github.com/rails/rails/pull/23086))
+
### Notable changes
* Added a `foreign_key` option to `references` while creating the table.
@@ -557,6 +596,9 @@ Please refer to the [Changelog][active-record] for detailed changes.
model behavior.
([Pull Request](https://github.com/rails/rails/pull/22567))
+* Added ActiveRecord `#second_to_last` and `#third_to_last` methods.
+ ([Pull Request](https://github.com/rails/rails/pull/23583))
+
Active Model
------------
@@ -624,15 +666,20 @@ Please refer to the [Changelog][active-job] for detailed changes.
* A generated job now inherits from `app/jobs/application_job.rb` by default.
([Pull Request](https://github.com/rails/rails/pull/19034))
-* Allow `DelayedJob`, `Sidekiq`, `qu`, and `que` to report the job id back to
- `ActiveJob::Base` as `provider_job_id`.
+* Allow `DelayedJob`, `Sidekiq`, `qu`, `que`, and `queue_classic` to report
+ the job id back to `ActiveJob::Base` as `provider_job_id`.
([Pull Request](https://github.com/rails/rails/pull/20064),
- [Pull Request](https://github.com/rails/rails/pull/20056))
+ [Pull Request](https://github.com/rails/rails/pull/20056),
+ [commit](https://github.com/rails/rails/commit/68e3279163d06e6b04e043f91c9470e9259bbbe0))
* Implement a simple `AsyncJob` processor and associated `AsyncAdapter` that
queue jobs to a `concurrent-ruby` thread pool.
([Pull Request](https://github.com/rails/rails/pull/21257))
+* Change the default adapter from inline to async. It's a better default as
+ tests will then not mistakenly come to rely on behavior happening
+ synchronously.
+ ([commit](https://github.com/rails/rails/commit/625baa69d14881ac49ba2e5c7d9cac4b222d7022))
Active Support
--------------
@@ -701,6 +748,13 @@ Please refer to the [Changelog][active-support] for detailed changes.
Deprecated `ActiveSupport::Cache::LocaleCache#set_cache_value` in favor of `write_cache_value`.
([Pull Request](https://github.com/rails/rails/pull/22215))
+* Deprecated passing arguments to `assert_nothing_raised`.
+ ([Pull Request](https://github.com/rails/rails/pull/23789))
+
+* Deprecated `Module.local_constants` in favor of `Module.constants(false)`.
+ ([Pull Request](https://github.com/rails/rails/pull/23936))
+
+
### Notable changes
* Added `#verified` and `#valid_message?` methods to
@@ -770,6 +824,17 @@ Please refer to the [Changelog][active-support] for detailed changes.
class and module variables that live per-thread.
([Pull Request](https://github.com/rails/rails/pull/22630))
+* Added `Array#second_to_last` and `Array#third_to_last` methods.
+ ([Pull Request](https://github.com/rails/rails/pull/23583))
+
+* Added `#on_weekday?` method to `Date`, `Time`, and `DateTime`.
+ ([Pull Request](https://github.com/rails/rails/pull/23687))
+
+* Publish `ActiveSupport::Executor` and `ActiveSupport::Reloader` APIs to allow
+ components and libraries to manage, and participate in, the execution of
+ application code, and the application reloading process.
+ ([Pull Request](https://github.com/rails/rails/pull/23807))
+
Credits
-------
diff --git a/guides/source/action_cable_overview.md b/guides/source/action_cable_overview.md
index 16cfaf94e2..28578b3369 100644
--- a/guides/source/action_cable_overview.md
+++ b/guides/source/action_cable_overview.md
@@ -417,7 +417,7 @@ App.cable.subscriptions.create "AppearanceChannel",
2. **Client** initiates a subscription to the `Appearance Channel` for their connection via `App.cable.subscriptions.create "AppearanceChannel"`. [*`appearance.coffee`*]
3. **Server** recognizes a new subscription has been initiated for `AppearanceChannel` channel performs the `subscribed` callback, which calls the `appear` method on the `current_user`. [*`appearance_channel.rb`*]
4. **Client** recognizes that a subscription has been established and calls `connected` [*`appearance.coffee`*] which in turn calls `@install` and `@appear`. `@appear` calls`AppearanceChannel#appear(data)` on the server, and supplies a data hash of `appearing_on: $("main").data("appearing-on")`. This is possible because the server-side channel instance will automatically expose the public methods declared on the class (minus the callbacks), so that these can be reached as remote procedure calls via a subscription's `perform` method.
-5. **Server** receives the request for the `appear` action on the `AppearanceChannel` channel for the connection identified by `current_user`. [*`appearance_channel.rb`*] The server retrieves the data with the `appearing_on` key from the data hash, and sets it as the the value for the `on:` key being passed to `current_user.appear`.
+5. **Server** receives the request for the `appear` action on the `AppearanceChannel` channel for the connection identified by `current_user`. [*`appearance_channel.rb`*] The server retrieves the data with the `appearing_on` key from the data hash and sets it as the value for the `on:` key being passed to `current_user.appear`.
### Example 2: Receiving new web notifications
diff --git a/guides/source/action_controller_overview.md b/guides/source/action_controller_overview.md
index 9ef2c1a441..8997363fce 100644
--- a/guides/source/action_controller_overview.md
+++ b/guides/source/action_controller_overview.md
@@ -700,7 +700,7 @@ class LoginsController < ApplicationController
end
```
-Now, the `LoginsController`'s `new` and `create` actions will work as before without requiring the user to be logged in. The `:only` option is used to only skip this filter for these actions, and there is also an `:except` option which works the other way. These options can be used when adding filters too, so you can add a filter which only runs for selected actions in the first place.
+Now, the `LoginsController`'s `new` and `create` actions will work as before without requiring the user to be logged in. The `:only` option is used to skip this filter only for these actions, and there is also an `:except` option which works the other way. These options can be used when adding filters too, so you can add a filter which only runs for selected actions in the first place.
### After Filters and Around Filters
diff --git a/guides/source/action_mailer_basics.md b/guides/source/action_mailer_basics.md
index 558c16f5b0..5346b7c32b 100644
--- a/guides/source/action_mailer_basics.md
+++ b/guides/source/action_mailer_basics.md
@@ -204,10 +204,14 @@ class UsersController < ApplicationController
end
```
-NOTE: Active Job's default behavior is to execute jobs ':inline'. So, you can use
-`deliver_later` now to send emails, and when you later decide to start sending
-them from a background job, you'll only need to set up Active Job to use a queueing
-backend (Sidekiq, Resque, etc).
+NOTE: Active Job's default behavior is to execute jobs via the `:async` adapter. So, you can use
+`deliver_later` now to send emails asynchronously.
+Active Job's default adapter runs jobs with an in-process thread pool.
+It's well-suited for the development/test environments, since it doesn't require
+any external infrastructure, but it's a poor fit for production since it drops
+pending jobs on restart.
+If you need a persistent backend, you will need to use an Active Job adapter
+that has a persistent backend (Sidekiq, Resque, etc).
If you want to send emails right away (from a cronjob for example) just call
`deliver_now`:
diff --git a/guides/source/action_view_overview.md b/guides/source/action_view_overview.md
index ce6f943e49..46116b1e47 100644
--- a/guides/source/action_view_overview.md
+++ b/guides/source/action_view_overview.md
@@ -173,7 +173,7 @@ would produce:
```json
{
"name": "Alex",
- "email: "alex@example.com"
+ "email": "alex@example.com"
}
```
diff --git a/guides/source/active_record_basics.md b/guides/source/active_record_basics.md
index fba89f9d13..d9e9466a33 100644
--- a/guides/source/active_record_basics.md
+++ b/guides/source/active_record_basics.md
@@ -361,7 +361,7 @@ class CreatePublications < ActiveRecord::Migration[5.0]
t.string :publisher_type
t.boolean :single_issue
- t.timestamps null: false
+ t.timestamps
end
add_index :publications, :publication_type_id
end
diff --git a/guides/source/active_record_migrations.md b/guides/source/active_record_migrations.md
index feb0de8eea..cd6b7fdd67 100644
--- a/guides/source/active_record_migrations.md
+++ b/guides/source/active_record_migrations.md
@@ -41,7 +41,7 @@ class CreateProducts < ActiveRecord::Migration[5.0]
t.string :name
t.text :description
- t.timestamps null: false
+ t.timestamps
end
end
end
@@ -847,7 +847,7 @@ class CreateProducts < ActiveRecord::Migration[5.0]
create_table :products do |t|
t.string :name
t.text :description
- t.timestamps null: false
+ t.timestamps
end
end
diff --git a/guides/source/active_support_core_extensions.md b/guides/source/active_support_core_extensions.md
index b994c863d1..d7f9201b26 100644
--- a/guides/source/active_support_core_extensions.md
+++ b/guides/source/active_support_core_extensions.md
@@ -632,8 +632,6 @@ module ActiveSupport
mattr_accessor :load_once_paths
mattr_accessor :autoloaded_constants
mattr_accessor :explicitly_unloadable_constants
- mattr_accessor :logger
- mattr_accessor :log_activity
mattr_accessor :constant_watch_stack
mattr_accessor :constant_watch_stack_mutex
end
diff --git a/guides/source/active_support_instrumentation.md b/guides/source/active_support_instrumentation.md
index 0fd0112c9f..03af3cf819 100644
--- a/guides/source/active_support_instrumentation.md
+++ b/guides/source/active_support_instrumentation.md
@@ -112,6 +112,7 @@ Action Controller
| `:controller` | The controller name |
| `:action` | The action |
| `:params` | Hash of request parameters without any filtered parameter |
+| `:headers` | Request headers |
| `:format` | html/js/json/xml etc |
| `:method` | HTTP request verb |
| `:path` | Request path |
@@ -121,6 +122,7 @@ Action Controller
controller: "PostsController",
action: "new",
params: { "action" => "new", "controller" => "posts" },
+ headers: #<ActionDispatch::Http::Headers:0x0055a67a519b88>,
format: :html,
method: "GET",
path: "/posts/new"
@@ -134,6 +136,7 @@ Action Controller
| `:controller` | The controller name |
| `:action` | The action |
| `:params` | Hash of request parameters without any filtered parameter |
+| `:headers` | Request headers |
| `:format` | html/js/json/xml etc |
| `:method` | HTTP request verb |
| `:path` | Request path |
@@ -146,6 +149,7 @@ Action Controller
controller: "PostsController",
action: "index",
params: {"action" => "index", "controller" => "posts"},
+ headers: #<ActionDispatch::Http::Headers:0x0055a67a519b88>,
format: :html,
method: "GET",
path: "/posts",
diff --git a/guides/source/asset_pipeline.md b/guides/source/asset_pipeline.md
index b6c612794c..cc3da47db9 100644
--- a/guides/source/asset_pipeline.md
+++ b/guides/source/asset_pipeline.md
@@ -25,13 +25,9 @@ It allows assets in your application to be automatically combined with assets
from other gems. For example, jquery-rails includes a copy of jquery.js
and enables AJAX features in Rails.
-The asset pipeline is technically no longer a core feature from Rails 4 onwards -- it has
-been extracted out of the framework into the
-[sprockets-rails](https://github.com/rails/sprockets-rails) gem.
-
-The asset pipeline is enabled by default.
-
-You can disable the asset pipeline while creating a new application by
+The asset pipeline is implemented by the
+[sprockets-rails](https://github.com/rails/sprockets-rails) gem,
+and is enabled by default. You can disable it while creating a new application by
passing the `--skip-sprockets` option.
```bash
@@ -670,7 +666,7 @@ anymore, delete these options from the `javascript_include_tag` and
`stylesheet_link_tag`.
The fingerprinting behavior is controlled by the `config.assets.digest`
-initialization option (which defaults to `true` for production and development).
+initialization option (which defaults to `true`).
NOTE: Under normal circumstances the default `config.assets.digest` option
should not be changed. If there are no digests in the filenames, and far-future
@@ -789,7 +785,6 @@ location ~ ^/assets/ {
add_header Cache-Control public;
add_header ETag "";
- break;
}
```
diff --git a/guides/source/association_basics.md b/guides/source/association_basics.md
index 09ab64837a..67fd758fe1 100644
--- a/guides/source/association_basics.md
+++ b/guides/source/association_basics.md
@@ -105,13 +105,13 @@ class CreateBooks < ActiveRecord::Migration[5.0]
def change
create_table :authors do |t|
t.string :name
- t.timestamps null: false
+ t.timestamps
end
create_table :books do |t|
t.belongs_to :author, index: true
t.datetime :published_at
- t.timestamps null: false
+ t.timestamps
end
end
end
@@ -136,13 +136,13 @@ class CreateSuppliers < ActiveRecord::Migration[5.0]
def change
create_table :suppliers do |t|
t.string :name
- t.timestamps null: false
+ t.timestamps
end
create_table :accounts do |t|
t.belongs_to :supplier, index: true
t.string :account_number
- t.timestamps null: false
+ t.timestamps
end
end
end
@@ -180,13 +180,13 @@ class CreateAuthors < ActiveRecord::Migration[5.0]
def change
create_table :authors do |t|
t.string :name
- t.timestamps null: false
+ t.timestamps
end
create_table :books do |t|
t.belongs_to :author, index: true
t.datetime :published_at
- t.timestamps null: false
+ t.timestamps
end
end
end
@@ -222,19 +222,19 @@ class CreateAppointments < ActiveRecord::Migration[5.0]
def change
create_table :physicians do |t|
t.string :name
- t.timestamps null: false
+ t.timestamps
end
create_table :patients do |t|
t.string :name
- t.timestamps null: false
+ t.timestamps
end
create_table :appointments do |t|
t.belongs_to :physician, index: true
t.belongs_to :patient, index: true
t.datetime :appointment_date
- t.timestamps null: false
+ t.timestamps
end
end
end
@@ -308,19 +308,19 @@ class CreateAccountHistories < ActiveRecord::Migration[5.0]
def change
create_table :suppliers do |t|
t.string :name
- t.timestamps null: false
+ t.timestamps
end
create_table :accounts do |t|
t.belongs_to :supplier, index: true
t.string :account_number
- t.timestamps null: false
+ t.timestamps
end
create_table :account_histories do |t|
t.belongs_to :account, index: true
t.integer :credit_rating
- t.timestamps null: false
+ t.timestamps
end
end
end
@@ -349,12 +349,12 @@ class CreateAssembliesAndParts < ActiveRecord::Migration[5.0]
def change
create_table :assemblies do |t|
t.string :name
- t.timestamps null: false
+ t.timestamps
end
create_table :parts do |t|
t.string :part_number
- t.timestamps null: false
+ t.timestamps
end
create_table :assemblies_parts, id: false do |t|
@@ -388,13 +388,13 @@ class CreateSuppliers < ActiveRecord::Migration[5.0]
def change
create_table :suppliers do |t|
t.string :name
- t.timestamps null: false
+ t.timestamps
end
create_table :accounts do |t|
t.integer :supplier_id
t.string :account_number
- t.timestamps null: false
+ t.timestamps
end
add_index :accounts, :supplier_id
@@ -472,7 +472,7 @@ class CreatePictures < ActiveRecord::Migration[5.0]
t.string :name
t.integer :imageable_id
t.string :imageable_type
- t.timestamps null: false
+ t.timestamps
end
add_index :pictures, [:imageable_type, :imageable_id]
@@ -488,7 +488,7 @@ class CreatePictures < ActiveRecord::Migration[5.0]
create_table :pictures do |t|
t.string :name
t.references :imageable, polymorphic: true, index: true
- t.timestamps null: false
+ t.timestamps
end
end
end
@@ -518,7 +518,7 @@ class CreateEmployees < ActiveRecord::Migration[5.0]
def change
create_table :employees do |t|
t.references :manager, index: true
- t.timestamps null: false
+ t.timestamps
end
end
end
@@ -734,7 +734,7 @@ end
With these changes, Active Record will only load one copy of the author object, preventing inconsistencies and making your application more efficient:
```ruby
-a = author.first
+a = Author.first
b = a.books.first
a.first_name == b.author.first_name # => true
a.first_name = 'Manny'
@@ -932,15 +932,13 @@ side of the association.
Counter cache columns are added to the containing model's list of read-only attributes through `attr_readonly`.
##### `:dependent`
-If you set the `:dependent` option to:
-
-* `:destroy`, when the object is destroyed, `destroy` will be called on its
-associated objects.
-* `:delete_all`, when the object is destroyed, all its associated objects will be
-deleted directly from the database without calling their `destroy` method.
-* `:nullify`, causes the foreign key to be set to `NULL`. Callbacks are not executed.
-* `:restrict_with_exception`, causes an exception to be raised if there is an associated record
-* `:restrict_with_error`, causes an error to be added to the owner if there is an associated object
+Controls what happens to associated objects when their owner is destroyed:
+
+* `:destroy` causes the associated objects to also be destroyed.
+* `:delete_all` causes the associated objects to be deleted directly from the database (callbacks are not executed).
+* `:nullify` causes the foreign keys to be set to `NULL` (callbacks are not executed).
+* `:restrict_with_exception` causes an exception to be raised if there are associated records.
+* `:restrict_with_error` causes an error to be added to the owner if there are associated objects.
WARNING: You should not specify this option on a `belongs_to` association that is connected with a `has_many` association on the other class. Doing so can lead to orphaned records in your database.
diff --git a/guides/source/command_line.md b/guides/source/command_line.md
index e865a02cbd..62d742fc28 100644
--- a/guides/source/command_line.md
+++ b/guides/source/command_line.md
@@ -65,11 +65,12 @@ $ bin/rails server
=> Booting Puma
=> Rails 5.0.0 application starting in development on http://0.0.0.0:3000
=> Run `rails server -h` for more startup options
-=> Ctrl-C to shutdown server
-Puma 2.15.3 starting...
-* Min threads: 0, max threads: 16
+Puma starting in single mode...
+* Version 3.0.2 (ruby 2.3.0-p0), codename: Plethora of Penguin Pinatas
+* Min threads: 5, max threads: 5
* Environment: development
* Listening on tcp://localhost:3000
+Use Ctrl-C to stop
```
With just three commands we whipped up a Rails server listening on port 3000. Go to your browser and open [http://localhost:3000](http://localhost:3000), you will see a basic Rails app running.
diff --git a/guides/source/configuring.md b/guides/source/configuring.md
index 1d3ff6e6e7..e57d873719 100644
--- a/guides/source/configuring.md
+++ b/guides/source/configuring.md
@@ -108,7 +108,7 @@ numbers. New applications filter out passwords by adding the following `config.f
* `config.force_ssl` forces all requests to be served over HTTPS by using the `ActionDispatch::SSL` middleware, and sets `config.action_mailer.default_url_options` to be `{ protocol: 'https' }`. This can be configured by setting `config.ssl_options` - see the [ActionDispatch::SSL documentation](http://edgeapi.rubyonrails.org/classes/ActionDispatch/SSL.html) for details.
-* `config.log_formatter` defines the formatter of the Rails logger. This option defaults to an instance of `ActiveSupport::Logger::SimpleFormatter` for all modes except production, where it defaults to `Logger::Formatter`.
+* `config.log_formatter` defines the formatter of the Rails logger. This option defaults to an instance of `ActiveSupport::Logger::SimpleFormatter` for all modes except production, where it defaults to `Logger::Formatter`. If you are setting a value for `config.logger` you must manually pass the value of your formatter to your logger before it is wrapped in an `ActiveSupport::TaggedLogging` instance, Rails will not do it for you.
* `config.log_level` defines the verbosity of the Rails logger. This option
defaults to `:debug` for all environments. The available log levels are: `:debug`,
@@ -116,7 +116,21 @@ defaults to `:debug` for all environments. The available log levels are: `:debug
* `config.log_tags` accepts a list of: methods that the `request` object responds to, a `Proc` that accepts the `request` object, or something that responds to `to_s`. This makes it easy to tag log lines with debug information like subdomain and request id - both very helpful in debugging multi-user production applications.
-* `config.logger` accepts a logger conforming to the interface of Log4r or the default Ruby `Logger` class. Defaults to an instance of `ActiveSupport::Logger`.
+* `config.logger` is the logger that will be used for `Rails.logger` and any related Rails logging such as `ActiveRecord::Base.logger`. It defaults to an instance of `ActiveSupport::TaggedLogging` that wraps an instance of `ActiveSupport::Logger` which outputs a log to the `log/` directory. You can supply a custom logger, to get full compatability you must follow these guidelines:
+ * To support a formatter you must manually assign a formatter from the `config.log_formatter` value to the logger.
+ * To support tagged loggs the log instance must be wrapped with `ActiveSupport::TaggedLogging`.
+ * To support silencing the logger must include `LoggerSilence` and `ActiveSupport::LoggerThreadSafeLevel` modules. The `ActiveSupport::Logger` class already includes these modules.
+
+ ```ruby
+ class MyLogger < ::Logger
+ include ActiveSupport::LoggerThreadSafeLevel
+ include LoggerSilence
+ end
+
+ mylogger = MyLogger.new(STDOUT)
+ mylogger.formatter = config.log_formatter
+ 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.
@@ -157,7 +171,7 @@ pipeline is enabled. It is set to true by default.
* `config.assets.manifest` defines the full path to be used for the asset precompiler's manifest file. Defaults to a file named `manifest-<random>.json` in the `config.assets.prefix` directory within the public folder.
-* `config.assets.digest` enables the use of MD5 fingerprints in asset names. Set to `true` by default in `production.rb` and `development.rb`.
+* `config.assets.digest` enables the use of MD5 fingerprints in asset names. Set to `true` by default.
* `config.assets.debug` disables the concatenation and compression of assets. Set to `true` by default in `development.rb`.
@@ -191,6 +205,7 @@ The full set of methods that can be used in this block are as follows:
* `scaffold_controller` different from `resource_controller`, defines which generator to use for generating a _scaffolded_ controller when using `rails generate scaffold`. Defaults to `:scaffold_controller`.
* `stylesheets` turns on the hook for stylesheets in generators. Used in Rails for when the `scaffold` generator is run, but this hook can be used in other generates as well. Defaults to `true`.
* `stylesheet_engine` configures the stylesheet engine (for eg. sass) to be used when generating assets. Defaults to `:css`.
+* `scaffold_stylesheet` creates `scaffold.css` when generating a scaffolded resource. Defaults to `true`.
* `test_framework` defines which test framework to use. Defaults to `false` and will use Minitest by default.
* `template_engine` defines which template engine to use, such as ERB or Haml. Defaults to `:erb`.
@@ -568,7 +583,7 @@ There are a few configuration options available in Active Support:
`config.active_job` provides the following configuration options:
-* `config.active_job.queue_adapter` sets the adapter for the queueing backend. The default adapter is `:inline` which will perform jobs immediately. For an up-to-date list of built-in adapters see the [ActiveJob::QueueAdapters API documentation](http://api.rubyonrails.org/classes/ActiveJob/QueueAdapters.html).
+* `config.active_job.queue_adapter` sets the adapter for the queueing backend. The default adapter is `:async`. For an up-to-date list of built-in adapters see the [ActiveJob::QueueAdapters API documentation](http://api.rubyonrails.org/classes/ActiveJob/QueueAdapters.html).
```ruby
# Be sure to have the adapter's gem in your Gemfile
diff --git a/guides/source/contributing_to_ruby_on_rails.md b/guides/source/contributing_to_ruby_on_rails.md
index 0f98d12217..12d0280116 100644
--- a/guides/source/contributing_to_ruby_on_rails.md
+++ b/guides/source/contributing_to_ruby_on_rails.md
@@ -367,7 +367,7 @@ Finally,
$ bundle exec rake test
```
-will now run the four of them in turn.
+will now run the three of them in turn.
You can also run any single test separately:
diff --git a/guides/source/debugging_rails_applications.md b/guides/source/debugging_rails_applications.md
index faf475c294..877c87e9fa 100644
--- a/guides/source/debugging_rails_applications.md
+++ b/guides/source/debugging_rails_applications.md
@@ -314,11 +314,12 @@ For example:
=> Booting Puma
=> Rails 5.0.0 application starting in development on http://0.0.0.0:3000
=> Run `rails server -h` for more startup options
-=> Ctrl-C to shutdown server
-Puma 2.15.3 starting...
-* Min threads: 0, max threads: 16
+Puma starting in single mode...
+* Version 3.0.2 (ruby 2.3.0-p0), codename: Plethora of Penguin Pinatas
+* Min threads: 5, max threads: 5
* Environment: development
* Listening on tcp://localhost:3000
+Use Ctrl-C to stop
Started GET "/" for 127.0.0.1 at 2014-04-11 13:11:48 +0200
diff --git a/guides/source/documents.yaml b/guides/source/documents.yaml
index 2cf613f47f..03943d0f25 100644
--- a/guides/source/documents.yaml
+++ b/guides/source/documents.yaml
@@ -116,7 +116,7 @@
name: The Rails Initialization Process
work_in_progress: true
url: initialization.html
- description: This guide explains the internals of the Rails initialization process as of Rails 4.
+ description: This guide explains the internals of the Rails initialization process.
-
name: Autoloading and Reloading Constants
url: autoloading_and_reloading_constants.html
diff --git a/guides/source/engines.md b/guides/source/engines.md
index c5fc2f73b4..eafac4828c 100644
--- a/guides/source/engines.md
+++ b/guides/source/engines.md
@@ -799,7 +799,7 @@ before the article is saved. It will also need to have an `attr_accessor` set up
for this field, so that the setter and getter methods are defined for it.
To do all this, you'll need to add the `attr_accessor` for `author_name`, the
-association for the author and the `before_save` call into
+association for the author and the `before_validation` call into
`app/models/blorgh/article.rb`. The `author` association will be hard-coded to the
`User` class for the time being.
@@ -807,7 +807,7 @@ association for the author and the `before_save` call into
attr_accessor :author_name
belongs_to :author, class_name: "User"
-before_save :set_author
+before_validation :set_author
private
def set_author
@@ -1209,7 +1209,7 @@ module Blorgh::Concerns::Models::Article
attr_accessor :author_name
belongs_to :author, class_name: "User"
- before_save :set_author
+ before_validation :set_author
private
def set_author
diff --git a/guides/source/getting_started.md b/guides/source/getting_started.md
index 4431512eda..a615751eb5 100644
--- a/guides/source/getting_started.md
+++ b/guides/source/getting_started.md
@@ -690,7 +690,7 @@ class CreateArticles < ActiveRecord::Migration[5.0]
t.string :title
t.text :text
- t.timestamps null: false
+ t.timestamps
end
end
end
@@ -1558,9 +1558,9 @@ class CreateComments < ActiveRecord::Migration[5.0]
create_table :comments do |t|
t.string :commenter
t.text :body
- t.references :article, index: true, foreign_key: true
+ t.references :article, foreign_key: true
- t.timestamps null: false
+ t.timestamps
end
end
end
diff --git a/guides/source/i18n.md b/guides/source/i18n.md
index 56b0c6c812..0edfa072f8 100644
--- a/guides/source/i18n.md
+++ b/guides/source/i18n.md
@@ -1113,7 +1113,7 @@ Conclusion
At this point you should have a good overview about how I18n support in Ruby on Rails works and are ready to start translating your project.
-If you find anything missing or wrong in this guide, please file a ticket on our [issue tracker](http://i18n.lighthouseapp.com/projects/14948-rails-i18n/overview). If you want to discuss certain portions or have questions, please sign up to our [mailing list](http://groups.google.com/group/rails-i18n).
+If you want to discuss certain portions or have questions, please sign up to the [rails-i18n mailing list](http://groups.google.com/group/rails-i18n).
Contributing to Rails I18n
@@ -1130,10 +1130,8 @@ Resources
---------
* [Google group: rails-i18n](http://groups.google.com/group/rails-i18n) - The project's mailing list.
-* [GitHub: rails-i18n](https://github.com/svenfuchs/rails-i18n/tree/master) - Code repository for the rails-i18n project. Most importantly you can find lots of [example translations](https://github.com/svenfuchs/rails-i18n/tree/master/rails/locale) for Rails that should work for your application in most cases.
-* [GitHub: i18n](https://github.com/svenfuchs/i18n/tree/master) - Code repository for the i18n gem.
-* [Lighthouse: rails-i18n](http://i18n.lighthouseapp.com/projects/14948-rails-i18n/overview) - Issue tracker for the rails-i18n project.
-* [Lighthouse: i18n](http://i18n.lighthouseapp.com/projects/14947-ruby-i18n/overview) - Issue tracker for the i18n gem.
+* [GitHub: rails-i18n](https://github.com/svenfuchs/rails-i18n) - Code repository and issue tracker for the rails-i18n project. Most importantly you can find lots of [example translations](https://github.com/svenfuchs/rails-i18n/tree/master/rails/locale) for Rails that should work for your application in most cases.
+* [GitHub: i18n](https://github.com/svenfuchs/i18n) - Code repository and issue tracker for the i18n gem.
Authors
diff --git a/guides/source/initialization.md b/guides/source/initialization.md
index 156f9c92b4..89e5346d86 100644
--- a/guides/source/initialization.md
+++ b/guides/source/initialization.md
@@ -3,8 +3,8 @@
The Rails Initialization Process
================================
-This guide explains the internals of the initialization process in Rails
-as of Rails 4. It is an extremely in-depth guide and recommended for advanced Rails developers.
+This guide explains the internals of the initialization process in Rails.
+It is an extremely in-depth guide and recommended for advanced Rails developers.
After reading this guide, you will know:
@@ -356,8 +356,6 @@ private
def print_boot_information
...
puts "=> Run `rails server -h` for more startup options"
- ...
- puts "=> Ctrl-C to shutdown server" unless options[:daemonize]
end
def create_tmp_directories
diff --git a/guides/source/layouts_and_rendering.md b/guides/source/layouts_and_rendering.md
index 614ca4dbe1..2722789c49 100644
--- a/guides/source/layouts_and_rendering.md
+++ b/guides/source/layouts_and_rendering.md
@@ -149,23 +149,22 @@ render template: "products/show"
#### Rendering an Arbitrary File
-The `render` method can also use a view that's entirely outside of your application (perhaps you're sharing views between two Rails applications):
-
-```ruby
-render "/u/apps/warehouse_app/current/app/views/products/show"
-```
-
-Rails determines that this is a file render because of the leading slash character. To be explicit, you can use the `:file` option (which was required on Rails 2.2 and earlier):
+The `render` method can also use a view that's entirely outside of your application:
```ruby
render file: "/u/apps/warehouse_app/current/app/views/products/show"
```
-The `:file` option takes an absolute file-system path. Of course, you need to have rights to the view that you're using to render the content.
+The `:file` option takes an absolute file-system path. Of course, you need to have rights
+to the view that you're using to render the content.
+
+NOTE: Using the `:file` option in combination with users input can lead to security problems
+since an attacker could use this action to access security sensitive files in your file system.
NOTE: By default, the file is rendered using the current layout.
-TIP: If you're running Rails on Microsoft Windows, you should use the `:file` option to render a file, because Windows filenames do not have the same format as Unix filenames.
+TIP: If you're running Rails on Microsoft Windows, you should use the `:file` option to
+render a file, because Windows filenames do not have the same format as Unix filenames.
#### Wrapping it up
@@ -238,7 +237,7 @@ TIP: This is useful when you're rendering a small snippet of HTML code.
However, you might want to consider moving it to a template file if the markup
is complex.
-NOTE: When using `html:` option, HTML entities will be escaped if the string is not marked as HTML safe by using `html_safe` method.
+NOTE: When using `html:` option, HTML entities will be escaped if the string is not marked as HTML safe by using `html_safe` method.
#### Rendering JSON
diff --git a/guides/source/routing.md b/guides/source/routing.md
index bd3e236a2b..81321c7405 100644
--- a/guides/source/routing.md
+++ b/guides/source/routing.md
@@ -812,10 +812,10 @@ In all of these cases, if you don't provide the leading host (`http://www.exampl
Instead of a String like `'articles#index'`, which corresponds to the `index` action in the `ArticlesController`, you can specify any [Rack application](rails_on_rack.html) as the endpoint for a matcher:
```ruby
-match '/application.js', to: Sprockets, via: :all
+match '/application.js', to: MyRackApp, via: :all
```
-As long as `Sprockets` responds to `call` and returns a `[status, headers, body]`, the router won't know the difference between the Rack application and an action. This is an appropriate use of `via: :all`, as you will want to allow your Rack application to handle all verbs as it considers appropriate.
+As long as `MyRackApp` responds to `call` and returns a `[status, headers, body]`, the router won't know the difference between the Rack application and an action. This is an appropriate use of `via: :all`, as you will want to allow your Rack application to handle all verbs as it considers appropriate.
NOTE: For the curious, `'articles#index'` actually expands out to `ArticlesController.action(:index)`, which returns a valid Rack application.
diff --git a/guides/source/security.md b/guides/source/security.md
index f4a9f64669..4883c1abe7 100644
--- a/guides/source/security.md
+++ b/guides/source/security.md
@@ -160,7 +160,7 @@ The most effective countermeasure is to _issue a new session identifier_ and dec
reset_session
```
-If you use the popular RestfulAuthentication plugin for user management, add reset_session to the SessionsController#create action. Note that this removes any value from the session, _you have to transfer them to the new session_.
+If you use the popular [Devise](https://rubygems.org/gems/devise) gem for user management, it will automatically expire sessions on sign in and sign out for you. If you roll your own, remember to expire the session after your sign in action (when the session is created). This will remove values from the session, therefore _you will have to transfer them to the new session_.
Another countermeasure is to _save user-specific properties in the session_, verify them every time a request comes in, and deny access, if the information does not match. Such properties could be the remote IP address or the user agent (the web browser name), though the latter is less user-specific. When saving the IP address, you have to bear in mind that there are Internet service providers or large organizations that put their users behind proxies. _These might change over the course of a session_, so these users will not be able to use your application, or only in a limited way.
diff --git a/guides/source/upgrading_ruby_on_rails.md b/guides/source/upgrading_ruby_on_rails.md
index d5576be6f2..0c1e00100b 100644
--- a/guides/source/upgrading_ruby_on_rails.md
+++ b/guides/source/upgrading_ruby_on_rails.md
@@ -417,7 +417,7 @@ secrets, you need to:
3. Remove the `secret_token.rb` initializer.
-4. Use `rails secret` to generate new keys for the `development` and `test` sections.
+4. Use `rake secret` to generate new keys for the `development` and `test` sections.
5. Restart your server.
diff --git a/rails.gemspec b/rails.gemspec
index d4e78b6aa1..8f9cc181a0 100644
--- a/rails.gemspec
+++ b/rails.gemspec
@@ -14,7 +14,7 @@ Gem::Specification.new do |s|
s.author = 'David Heinemeier Hansson'
s.email = 'david@loudthinking.com'
- s.homepage = 'http://www.rubyonrails.org'
+ s.homepage = 'http://rubyonrails.org'
s.files = ['README.md']
diff --git a/railties/CHANGELOG.md b/railties/CHANGELOG.md
index a4eaf0ab0f..7193238e83 100644
--- a/railties/CHANGELOG.md
+++ b/railties/CHANGELOG.md
@@ -42,7 +42,9 @@
*Xavier Noria*
-* Add dummy files for apple-touch-icon.png and apple-touch-icon.png. GH#23427
+* Add dummy files for apple-touch-icon.png and apple-touch-icon.png.
+
+ See #23427.
*Alexey Zabelin*
diff --git a/railties/lib/rails/application.rb b/railties/lib/rails/application.rb
index d05d610ee1..4729ddcf62 100644
--- a/railties/lib/rails/application.rb
+++ b/railties/lib/rails/application.rb
@@ -74,8 +74,7 @@ module Rails
# the configuration.
#
# If you decide to define rake tasks, runners, or initializers in an
- # application other than +Rails.application+, then you must run those
- # these manually.
+ # application other than +Rails.application+, then you must run them manually.
class Application < Engine
autoload :Bootstrap, 'rails/application/bootstrap'
autoload :Configuration, 'rails/application/configuration'
diff --git a/railties/lib/rails/code_statistics.rb b/railties/lib/rails/code_statistics.rb
index fc8717c752..7a8f42fe94 100644
--- a/railties/lib/rails/code_statistics.rb
+++ b/railties/lib/rails/code_statistics.rb
@@ -1,4 +1,5 @@
require 'rails/code_statistics_calculator'
+require 'active_support/core_ext/enumerable'
class CodeStatistics #:nodoc:
diff --git a/railties/lib/rails/command.rb b/railties/lib/rails/command.rb
deleted file mode 100644
index f7753cbb83..0000000000
--- a/railties/lib/rails/command.rb
+++ /dev/null
@@ -1,70 +0,0 @@
-require 'rails/commands/commands_tasks'
-
-module Rails
- class Command #:nodoc:
- attr_reader :argv
-
- def initialize(argv = [])
- @argv = argv
-
- @option_parser = build_option_parser
- @options = {}
- end
-
- def self.run(task_name, argv)
- command_name = command_name_for(task_name)
-
- if command = command_for(command_name)
- command.new(argv).run(command_name)
- else
- Rails::CommandsTasks.new(argv).run_command!(task_name)
- end
- end
-
- def run(command_name)
- parse_options_for(command_name)
- @option_parser.parse! @argv
-
- public_send(command_name)
- end
-
- def self.options_for(command_name, &options_to_parse)
- @@command_options[command_name] = options_to_parse
- end
-
- def self.set_banner(command_name, banner)
- options_for(command_name) { |opts, _| opts.banner = banner }
- end
-
- private
- @@commands = []
- @@command_options = {}
-
- def parse_options_for(command_name)
- @@command_options.fetch(command_name, proc {}).call(@option_parser, @options)
- end
-
- def build_option_parser
- OptionParser.new do |opts|
- opts.on('-h', '--help', 'Show this help.') do
- puts opts
- exit
- end
- end
- end
-
- def self.inherited(command)
- @@commands << command
- end
-
- def self.command_name_for(task_name)
- task_name.gsub(':', '_').to_sym
- end
-
- def self.command_for(command_name)
- @@commands.find do |command|
- command.public_instance_methods.include?(command_name)
- end
- end
- end
-end
diff --git a/railties/lib/rails/commands.rb b/railties/lib/rails/commands.rb
index fa47c52b96..5a66b78a92 100644
--- a/railties/lib/rails/commands.rb
+++ b/railties/lib/rails/commands.rb
@@ -13,6 +13,6 @@ aliases = {
command = ARGV.shift
command = aliases[command] || command
-require 'rails/command'
+require 'rails/commands/commands_tasks'
-Rails::Command.run(command, ARGV)
+Rails::CommandsTasks.new(ARGV).run_command!(command)
diff --git a/railties/lib/rails/commands/server.rb b/railties/lib/rails/commands/server.rb
index d7597a13e1..c2434d62e2 100644
--- a/railties/lib/rails/commands/server.rb
+++ b/railties/lib/rails/commands/server.rb
@@ -2,6 +2,7 @@ require 'fileutils'
require 'optparse'
require 'action_dispatch'
require 'rails'
+require 'rails/dev_caching'
module Rails
class Server < ::Rack::Server
@@ -92,7 +93,7 @@ module Rails
DoNotReverseLookup: true,
environment: (ENV['RAILS_ENV'] || ENV['RACK_ENV'] || "development").dup,
daemonize: false,
- caching: false,
+ caching: nil,
pid: Options::DEFAULT_PID_PATH
})
end
@@ -100,12 +101,8 @@ module Rails
private
def setup_dev_caching
- return unless options[:environment] == "development"
-
- if options[:caching] == false
- delete_cache_file
- elsif options[:caching]
- create_cache_file
+ if options[:environment] == "development"
+ Rails::DevCaching.enable_by_argument(options[:caching])
end
end
@@ -116,14 +113,6 @@ module Rails
puts "=> Run `rails server -h` for more startup options"
end
- def create_cache_file
- FileUtils.touch("tmp/caching-dev.txt")
- end
-
- def delete_cache_file
- FileUtils.rm("tmp/caching-dev.txt") if File.exist?("tmp/caching-dev.txt")
- end
-
def create_tmp_directories
%w(cache pids sockets).each do |dir_to_make|
FileUtils.mkdir_p(File.join(Rails.root, 'tmp', dir_to_make))
diff --git a/railties/lib/rails/dev_caching.rb b/railties/lib/rails/dev_caching.rb
new file mode 100644
index 0000000000..4760010851
--- /dev/null
+++ b/railties/lib/rails/dev_caching.rb
@@ -0,0 +1,40 @@
+module Rails
+ module DevCaching # :nodoc:
+ class << self
+ FILE = 'tmp/caching-dev.txt'
+
+ def enable_by_file
+ FileUtils.mkdir_p('tmp')
+
+ if File.exist?(FILE)
+ delete_cache_file
+ puts 'Development mode is no longer being cached.'
+ else
+ create_cache_file
+ puts 'Development mode is now being cached.'
+ end
+
+ FileUtils.touch 'tmp/restart.txt'
+ end
+
+ def enable_by_argument(caching)
+ FileUtils.mkdir_p('tmp')
+
+ if caching
+ create_cache_file
+ elsif caching == false && File.exist?(FILE)
+ delete_cache_file
+ end
+ end
+
+ private
+ def create_cache_file
+ FileUtils.touch FILE
+ end
+
+ def delete_cache_file
+ File.delete FILE
+ end
+ end
+ end
+end
diff --git a/railties/lib/rails/generators/actions.rb b/railties/lib/rails/generators/actions.rb
index 5fa487b78e..57309112b5 100644
--- a/railties/lib/rails/generators/actions.rb
+++ b/railties/lib/rails/generators/actions.rb
@@ -207,18 +207,23 @@ module Rails
in_root { run_ruby_script("bin/rails generate #{what} #{argument}", verbose: false) }
end
- # Runs the supplied rake task
+ # Runs the supplied rake task (invoked with 'rake ...')
#
# rake("db:migrate")
# rake("db:migrate", env: "production")
# rake("gems:install", sudo: true)
def rake(command, options={})
- log :rake, command
- env = options[:env] || ENV["RAILS_ENV"] || 'development'
- sudo = options[:sudo] && RbConfig::CONFIG['host_os'] !~ /mswin|mingw/ ? 'sudo ' : ''
- in_root { run("#{sudo}#{extify(:rails)} #{command} RAILS_ENV=#{env}", verbose: false) }
+ execute_command :rake, command, options
+ end
+
+ # Runs the supplied rake task (invoked with 'rails ...')
+ #
+ # rails("db:migrate")
+ # rails("db:migrate", env: "production")
+ # rails("gems:install", sudo: true)
+ def rails_command(command, options={})
+ execute_command :rails, command, options
end
- alias :rails_command :rake
# Just run the capify command in root
#
@@ -271,6 +276,16 @@ module Rails
end
end
+
+ # Runs the supplied command using either "rake ..." or "rails ..."
+ # based on the executor parameter provided.
+ def execute_command(executor, command, options={})
+ log executor, command
+ env = options[:env] || ENV["RAILS_ENV"] || 'development'
+ sudo = options[:sudo] && RbConfig::CONFIG['host_os'] !~ /mswin|mingw/ ? 'sudo ' : ''
+ in_root { run("#{sudo}#{extify(executor)} #{command} RAILS_ENV=#{env}", verbose: false) }
+ end
+
# Add an extension to the given name based on the platform.
def extify(name)
if RbConfig::CONFIG['host_os'] =~ /mswin|mingw/
diff --git a/railties/lib/rails/generators/erb/mailer/mailer_generator.rb b/railties/lib/rails/generators/erb/mailer/mailer_generator.rb
index bc249aa5e5..7f00943d80 100644
--- a/railties/lib/rails/generators/erb/mailer/mailer_generator.rb
+++ b/railties/lib/rails/generators/erb/mailer/mailer_generator.rb
@@ -26,7 +26,7 @@ module Erb # :nodoc:
end
def file_name
- @_file_name ||= super.gsub(/\_mailer/i, '')
+ @_file_name ||= super.gsub(/_mailer/i, '')
end
end
end
diff --git a/railties/lib/rails/generators/rails/app/app_generator.rb b/railties/lib/rails/generators/rails/app/app_generator.rb
index e9435c946a..d6be69e16c 100644
--- a/railties/lib/rails/generators/rails/app/app_generator.rb
+++ b/railties/lib/rails/generators/rails/app/app_generator.rb
@@ -95,9 +95,14 @@ module Rails
action_cable_config_exist = File.exist?('config/cable.yml')
ssl_options_exist = File.exist?('config/initializers/ssl_options.rb')
rack_cors_config_exist = File.exist?('config/initializers/cors.rb')
+ development_config_exist = File.exist?('config/environments/development.rb')
config
+ if development_config_exist
+ gsub_file 'config/environments/development.rb', /^(\s+)config\.file_watcher/, '\1# config.file_watcher'
+ end
+
unless callback_terminator_config_exist
remove_file 'config/initializers/callback_terminator.rb'
end
diff --git a/railties/lib/rails/generators/rails/app/templates/Gemfile b/railties/lib/rails/generators/rails/app/templates/Gemfile
index e8ec214b28..86143ca1f1 100644
--- a/railties/lib/rails/generators/rails/app/templates/Gemfile
+++ b/railties/lib/rails/generators/rails/app/templates/Gemfile
@@ -31,11 +31,11 @@ end
group :development do
<%- unless options.api? -%>
- # Access an IRB console on exception pages or by using <%%= console %> in views
+ # Access an IRB console on exception pages or by using <%%= console %> anywhere in the code.
<%- if options.dev? || options.edge? -%>
gem 'web-console', github: 'rails/web-console'
<%- else -%>
- gem 'web-console', '~> 3.0'
+ gem 'web-console'
<%- end -%>
<%- end -%>
<% if depend_on_listen? -%>
diff --git a/railties/lib/rails/generators/rails/app/templates/Rakefile b/railties/lib/rails/generators/rails/app/templates/Rakefile
index ba6b733dd2..e85f913914 100644
--- a/railties/lib/rails/generators/rails/app/templates/Rakefile
+++ b/railties/lib/rails/generators/rails/app/templates/Rakefile
@@ -1,6 +1,6 @@
# Add your own tasks in files placed in lib/tasks ending in .rake,
# for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
-require File.expand_path('../config/application', __FILE__)
+require_relative 'config/application'
Rails.application.load_tasks
diff --git a/railties/lib/rails/generators/rails/app/templates/bin/rails b/railties/lib/rails/generators/rails/app/templates/bin/rails
index 80ec8080ab..513a2e0183 100644
--- a/railties/lib/rails/generators/rails/app/templates/bin/rails
+++ b/railties/lib/rails/generators/rails/app/templates/bin/rails
@@ -1,3 +1,3 @@
-APP_PATH = File.expand_path('../../config/application', __FILE__)
+APP_PATH = File.expand_path('../config/application', __dir__)
require_relative '../config/boot'
require 'rails/commands'
diff --git a/railties/lib/rails/generators/rails/app/templates/bin/setup b/railties/lib/rails/generators/rails/app/templates/bin/setup
index df88bfd3bc..acae810c1a 100644
--- a/railties/lib/rails/generators/rails/app/templates/bin/setup
+++ b/railties/lib/rails/generators/rails/app/templates/bin/setup
@@ -15,7 +15,7 @@ chdir APP_ROOT do
puts '== Installing dependencies =='
system! 'gem install bundler --conservative'
- system('bundle check') or system!('bundle install')
+ system('bundle check') || system!('bundle install')
# puts "\n== Copying sample files =="
# unless File.exist?('config/database.yml')
diff --git a/railties/lib/rails/generators/rails/app/templates/bin/update b/railties/lib/rails/generators/rails/app/templates/bin/update
index c6ed3ae64b..770a605fed 100644
--- a/railties/lib/rails/generators/rails/app/templates/bin/update
+++ b/railties/lib/rails/generators/rails/app/templates/bin/update
@@ -15,7 +15,7 @@ chdir APP_ROOT do
puts '== Installing dependencies =='
system! 'gem install bundler --conservative'
- system 'bundle check' or system! 'bundle install'
+ system('bundle check') || system!('bundle install')
puts "\n== Updating database =="
system! 'bin/rails db:migrate'
diff --git a/railties/lib/rails/generators/rails/app/templates/config.ru b/railties/lib/rails/generators/rails/app/templates/config.ru
index bd83b25412..f7ba0b527b 100644
--- a/railties/lib/rails/generators/rails/app/templates/config.ru
+++ b/railties/lib/rails/generators/rails/app/templates/config.ru
@@ -1,4 +1,5 @@
# This file is used by Rack-based servers to start the application.
-require ::File.expand_path('../config/environment', __FILE__)
+require_relative 'config/environment'
+
run Rails.application
diff --git a/railties/lib/rails/generators/rails/app/templates/config/application.rb b/railties/lib/rails/generators/rails/app/templates/config/application.rb
index cb83364360..c0a0bd0a3e 100644
--- a/railties/lib/rails/generators/rails/app/templates/config/application.rb
+++ b/railties/lib/rails/generators/rails/app/templates/config/application.rb
@@ -1,4 +1,4 @@
-require File.expand_path('../boot', __FILE__)
+require_relative 'boot'
<% if include_all_railties? -%>
require 'rails/all'
diff --git a/railties/lib/rails/generators/rails/app/templates/config/boot.rb b/railties/lib/rails/generators/rails/app/templates/config/boot.rb
index 6b750f00b1..30f5120df6 100644
--- a/railties/lib/rails/generators/rails/app/templates/config/boot.rb
+++ b/railties/lib/rails/generators/rails/app/templates/config/boot.rb
@@ -1,3 +1,3 @@
-ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)
+ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__)
require 'bundler/setup' # Set up gems listed in the Gemfile.
diff --git a/railties/lib/rails/generators/rails/app/templates/config/environment.rb b/railties/lib/rails/generators/rails/app/templates/config/environment.rb
index ee8d90dc65..426333bb46 100644
--- a/railties/lib/rails/generators/rails/app/templates/config/environment.rb
+++ b/railties/lib/rails/generators/rails/app/templates/config/environment.rb
@@ -1,5 +1,5 @@
# Load the Rails application.
-require File.expand_path('../application', __FILE__)
+require_relative 'application'
# Initialize the Rails application.
Rails.application.initialize!
diff --git a/railties/lib/rails/generators/rails/app/templates/config/environments/development.rb.tt b/railties/lib/rails/generators/rails/app/templates/config/environments/development.rb.tt
index e6a2de0928..7a537610e9 100644
--- a/railties/lib/rails/generators/rails/app/templates/config/environments/development.rb.tt
+++ b/railties/lib/rails/generators/rails/app/templates/config/environments/development.rb.tt
@@ -46,15 +46,6 @@ Rails.application.configure do
# This option may cause significant delays in view rendering with a large
# number of complex assets.
config.assets.debug = true
-
- # Asset digests allow you to set far-future HTTP expiration dates on all assets,
- # yet still be able to expire them through the digest params.
- config.assets.digest = true
-
- # Adds additional error checking when serving assets at runtime.
- # Checks for improperly declared sprockets dependencies.
- # Raises helpful error messages.
- config.assets.raise_runtime_errors = true
<%- end -%>
# Raises error for missing translations
diff --git a/railties/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt b/railties/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt
index 5205c0ef0a..6bd5e42251 100644
--- a/railties/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt
+++ b/railties/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt
@@ -26,10 +26,6 @@ Rails.application.configure do
# Do not fallback to assets pipeline if a precompiled asset is missed.
config.assets.compile = false
- # Asset digests allow you to set far-future HTTP expiration dates on all assets,
- # yet still be able to expire them through the digest params.
- config.assets.digest = true
-
# `config.assets.precompile` and `config.assets.version` have moved to config/initializers/assets.rb
<%- end -%>
@@ -59,14 +55,6 @@ Rails.application.configure do
# Prepend all log lines with the following tags.
config.log_tags = [ :request_id ]
- # Use a different logger for distributed setups.
- # require 'syslog/logger'
- # config.logger = ActiveSupport::TaggedLogging.new(Syslog::Logger.new 'app-name')
-
- if ENV["RAILS_LOG_TO_STDOUT"].present?
- config.logger = ActiveSupport::TaggedLogging.new(Logger.new(STDOUT))
- end
-
# Use a different cache store in production.
# config.cache_store = :mem_cache_store
@@ -90,6 +78,16 @@ Rails.application.configure do
# Use default logging formatter so that PID and timestamp are not suppressed.
config.log_formatter = ::Logger::Formatter.new
+
+ # Use a different logger for distributed setups.
+ # require 'syslog/logger'
+ # config.logger = ActiveSupport::TaggedLogging.new(Syslog::Logger.new 'app-name')
+
+ if ENV["RAILS_LOG_TO_STDOUT"].present?
+ logger = ActiveSupport::Logger.new(STDOUT)
+ logger.formatter = config.log_formatter
+ config.logger = ActiveSupport::TaggedLogging.new(logger)
+ end
<%- unless options.skip_active_record? -%>
# Do not dump schema after migrations.
diff --git a/railties/lib/rails/generators/rails/plugin/templates/rails/application.rb b/railties/lib/rails/generators/rails/plugin/templates/rails/application.rb
index b1038c839e..d03b1be878 100644
--- a/railties/lib/rails/generators/rails/plugin/templates/rails/application.rb
+++ b/railties/lib/rails/generators/rails/plugin/templates/rails/application.rb
@@ -1,4 +1,4 @@
-require File.expand_path('../boot', __FILE__)
+require_relative 'boot'
<% if include_all_railties? -%>
require 'rails/all'
@@ -6,10 +6,12 @@ require 'rails/all'
# Pick the frameworks you want:
<%= comment_if :skip_active_record %>require "active_record/railtie"
require "action_controller/railtie"
-<%= comment_if :skip_action_mailer %>require "action_mailer/railtie"
require "action_view/railtie"
-<%= comment_if :skip_sprockets %>require "sprockets/railtie"
+<%= comment_if :skip_action_mailer %>require "action_mailer/railtie"
+require "active_job/railtie"
+<%= comment_if :skip_action_cable %>require "action_cable/engine"
<%= comment_if :skip_test %>require "rails/test_unit/railtie"
+<%= comment_if :skip_sprockets %>require "sprockets/railtie"
<% end -%>
Bundler.require(*Rails.groups)
diff --git a/railties/lib/rails/generators/rails/plugin/templates/rails/boot.rb b/railties/lib/rails/generators/rails/plugin/templates/rails/boot.rb
index 6266cfc509..c9aef85d40 100644
--- a/railties/lib/rails/generators/rails/plugin/templates/rails/boot.rb
+++ b/railties/lib/rails/generators/rails/plugin/templates/rails/boot.rb
@@ -1,5 +1,5 @@
# Set up gems listed in the Gemfile.
-ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../../../Gemfile', __FILE__)
+ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../../Gemfile', __dir__)
require 'bundler/setup' if File.exist?(ENV['BUNDLE_GEMFILE'])
-$LOAD_PATH.unshift File.expand_path('../../../../lib', __FILE__)
+$LOAD_PATH.unshift File.expand_path('../../../lib', __dir__)
diff --git a/railties/lib/rails/generators/test_unit/mailer/mailer_generator.rb b/railties/lib/rails/generators/test_unit/mailer/mailer_generator.rb
index 343c8a3949..76a0b79654 100644
--- a/railties/lib/rails/generators/test_unit/mailer/mailer_generator.rb
+++ b/railties/lib/rails/generators/test_unit/mailer/mailer_generator.rb
@@ -19,7 +19,7 @@ module TestUnit # :nodoc:
protected
def file_name
- @_file_name ||= super.gsub(/\_mailer/i, '')
+ @_file_name ||= super.gsub(/_mailer/i, '')
end
end
end
diff --git a/railties/lib/rails/tasks/dev.rake b/railties/lib/rails/tasks/dev.rake
index ff2de264ce..d2ceaacc0c 100644
--- a/railties/lib/rails/tasks/dev.rake
+++ b/railties/lib/rails/tasks/dev.rake
@@ -1,16 +1,8 @@
+require 'rails/dev_caching'
+
namespace :dev do
desc 'Toggle development mode caching on/off'
task :cache do
- FileUtils.mkdir_p('tmp')
-
- if File.exist? 'tmp/caching-dev.txt'
- File.delete 'tmp/caching-dev.txt'
- puts 'Development mode is no longer being cached.'
- else
- FileUtils.touch 'tmp/caching-dev.txt'
- puts 'Development mode is now being cached.'
- end
-
- FileUtils.touch 'tmp/restart.txt'
+ Rails::DevCaching.enable_by_file
end
end
diff --git a/railties/lib/rails/tasks/framework.rake b/railties/lib/rails/tasks/framework.rake
index bf25b74627..61fb8311a5 100644
--- a/railties/lib/rails/tasks/framework.rake
+++ b/railties/lib/rails/tasks/framework.rake
@@ -47,8 +47,9 @@ namespace :app do
@app_generator ||= begin
require 'rails/generators'
require 'rails/generators/rails/app/app_generator'
- gen = Rails::Generators::AppGenerator.new ["rails"], { with_dispatchers: true, api: !!Rails.application.config.api_only },
- destination_root: Rails.root
+ gen = Rails::Generators::AppGenerator.new ["rails"],
+ { api: !!Rails.application.config.api_only },
+ destination_root: Rails.root
File.exist?(Rails.root.join("config", "application.rb")) ?
gen.send(:app_const) : gen.send(:valid_const?)
gen
diff --git a/railties/lib/rails/test_unit/minitest_plugin.rb b/railties/lib/rails/test_unit/minitest_plugin.rb
index f22139490b..e9195d5b4e 100644
--- a/railties/lib/rails/test_unit/minitest_plugin.rb
+++ b/railties/lib/rails/test_unit/minitest_plugin.rb
@@ -84,14 +84,18 @@ module Minitest
end
# Replace progress reporter for colors.
- self.reporter.reporters.delete_if { |reporter| reporter.kind_of?(SummaryReporter) || reporter.kind_of?(ProgressReporter) }
- self.reporter << SuppressedSummaryReporter.new(options[:io], options)
- self.reporter << ::Rails::TestUnitReporter.new(options[:io], options)
+ reporter.reporters.delete_if { |reporter| reporter.kind_of?(SummaryReporter) || reporter.kind_of?(ProgressReporter) }
+ reporter << SuppressedSummaryReporter.new(options[:io], options)
+ reporter << ::Rails::TestUnitReporter.new(options[:io], options)
end
mattr_accessor(:run_with_autorun) { false }
mattr_accessor(:run_with_rails_extension) { false }
end
+# Put Rails as the first plugin minitest initializes so other plugins
+# can override or replace our default reporter setup.
+# Since minitest only loads plugins if its extensions are empty we have
+# to call `load_plugins` first.
Minitest.load_plugins
-Minitest.extensions << 'rails'
+Minitest.extensions.unshift 'rails'
diff --git a/railties/railties.gemspec b/railties/railties.gemspec
index a06336f698..fa417816eb 100644
--- a/railties/railties.gemspec
+++ b/railties/railties.gemspec
@@ -13,7 +13,7 @@ Gem::Specification.new do |s|
s.author = 'David Heinemeier Hansson'
s.email = 'david@loudthinking.com'
- s.homepage = 'http://www.rubyonrails.org'
+ s.homepage = 'http://rubyonrails.org'
s.files = Dir['CHANGELOG.md', 'README.rdoc', 'MIT-LICENSE', 'RDOC_MAIN.rdoc', 'exe/**/*', 'lib/**/{*,.[a-z]*}']
s.require_path = 'lib'
diff --git a/railties/test/application/configuration_test.rb b/railties/test/application/configuration_test.rb
index d03dd1afcc..decc4d138d 100644
--- a/railties/test/application/configuration_test.rb
+++ b/railties/test/application/configuration_test.rb
@@ -1337,7 +1337,7 @@ module ApplicationTests
assert_equal 'custom key', Rails.application.config.my_custom_config['key']
end
- test "config_for use the Pathname object if it is provided" do
+ test "config_for uses the Pathname object if it is provided" do
app_file 'config/custom.yml', <<-RUBY
development:
key: 'custom key'
@@ -1464,7 +1464,7 @@ module ApplicationTests
assert_equal :api, Rails.configuration.debug_exception_response_format
end
- test "debug_exception_response_format can be override" do
+ test "debug_exception_response_format can be overriden" do
add_to_config <<-RUBY
config.api_only = true
RUBY
diff --git a/railties/test/application/initializers/i18n_test.rb b/railties/test/application/initializers/i18n_test.rb
index ab7f29b0f2..0f9bb41053 100644
--- a/railties/test/application/initializers/i18n_test.rb
+++ b/railties/test/application/initializers/i18n_test.rb
@@ -245,7 +245,7 @@ fr:
assert_fallbacks de: [:de, :'en-US', :en]
end
- test "[shortcut] config.i18n.fallbacks = [{ :ca => :'es-ES' }] initializes fallbacks with a mapping de-AT => de-DE" do
+ test "[shortcut] config.i18n.fallbacks = [{ :ca => :'es-ES' }] initializes fallbacks with a mapping ca => es-ES" do
I18n::Railtie.config.i18n.fallbacks.map = { :ca => :'es-ES' }
load_app
assert_fallbacks ca: [:ca, :"es-ES", :es, :en]
@@ -257,6 +257,12 @@ fr:
assert_fallbacks ca: [:ca, :"es-ES", :es, :'en-US', :en]
end
+ test "[shortcut] config.i18n.fallbacks = { ca: :en } initializes fallbacks with a mapping ca => :en" do
+ I18n::Railtie.config.i18n.fallbacks = { ca: :en }
+ load_app
+ assert_fallbacks ca: [:ca, :en]
+ end
+
test "disable config.i18n.enforce_available_locales" do
add_to_config <<-RUBY
config.i18n.enforce_available_locales = false
diff --git a/railties/test/application/middleware/session_test.rb b/railties/test/application/middleware/session_test.rb
index f847e80471..85e7761727 100644
--- a/railties/test/application/middleware/session_test.rb
+++ b/railties/test/application/middleware/session_test.rb
@@ -345,5 +345,33 @@ module ApplicationTests
get '/foo/read_raw_cookie'
assert_equal 2, verifier.verify(last_response.body)['foo']
end
+
+ test 'calling reset_session on request does not trigger an error for API apps' do
+ add_to_config 'config.api_only = true'
+
+ controller :test, <<-RUBY
+ class TestController < ApplicationController
+ def dump_flash
+ request.reset_session
+ render plain: 'It worked!'
+ end
+ end
+ RUBY
+
+ app_file 'config/routes.rb', <<-RUBY
+ Rails.application.routes.draw do
+ get '/dump_flash' => "test#dump_flash"
+ end
+ RUBY
+
+ require "#{app_path}/config/environment"
+
+ get '/dump_flash'
+
+ assert_equal 200, last_response.status
+ assert_equal 'It worked!', last_response.body
+
+ refute Rails.application.middleware.include?(ActionDispatch::Flash)
+ end
end
end
diff --git a/railties/test/application/rake/dev_test.rb b/railties/test/application/rake/dev_test.rb
index 43d7a5e156..59b46c6e79 100644
--- a/railties/test/application/rake/dev_test.rb
+++ b/railties/test/application/rake/dev_test.rb
@@ -15,7 +15,7 @@ module ApplicationTests
test 'dev:cache creates file and outputs message' do
Dir.chdir(app_path) do
- output = `rake dev:cache`
+ output = `rails dev:cache`
assert File.exist?('tmp/caching-dev.txt')
assert_match(/Development mode is now being cached/, output)
end
diff --git a/railties/test/application/rake_test.rb b/railties/test/application/rake_test.rb
index dc3c4755c7..1a786a3fd3 100644
--- a/railties/test/application/rake_test.rb
+++ b/railties/test/application/rake_test.rb
@@ -24,7 +24,7 @@ module ApplicationTests
assert $task_loaded
end
- def test_the_test_rake_task_is_protected_when_previous_migration_was_production
+ test "task is protected when previous migration was production" do
Dir.chdir(app_path) do
output = `bin/rails generate model product name:string;
env RAILS_ENV=production bin/rails db:create db:migrate;
@@ -122,7 +122,7 @@ module ApplicationTests
Dir.chdir(app_path){ `bin/rails stats` }
end
- def test_rake_routes_calls_the_route_inspector
+ def test_rails_routes_calls_the_route_inspector
app_file "config/routes.rb", <<-RUBY
Rails.application.routes.draw do
get '/cart', to: 'cart#show'
@@ -133,7 +133,7 @@ module ApplicationTests
assert_equal "Prefix Verb URI Pattern Controller#Action\n cart GET /cart(.:format) cart#show\n", output
end
- def test_rake_routes_with_controller_environment
+ def test_rails_routes_with_controller_environment
app_file "config/routes.rb", <<-RUBY
Rails.application.routes.draw do
get '/cart', to: 'cart#show'
@@ -151,7 +151,7 @@ module ApplicationTests
assert_equal "Prefix Verb URI Pattern Controller#Action\n cart GET /cart(.:format) cart#show\n", output
end
- def test_rake_routes_with_namespaced_controller_environment
+ def test_rails_routes_with_namespaced_controller_environment
app_file "config/routes.rb", <<-RUBY
Rails.application.routes.draw do
namespace :admin do
@@ -175,7 +175,7 @@ module ApplicationTests
assert_equal expected_output, output
end
- def test_rake_routes_with_global_search_key
+ def test_rails_routes_with_global_search_key
app_file "config/routes.rb", <<-RUBY
Rails.application.routes.draw do
get '/cart', to: 'cart#show'
@@ -195,7 +195,7 @@ module ApplicationTests
"basketballs GET /basketballs(.:format) basketball#index\n", output
end
- def test_rake_routes_with_controller_search_key
+ def test_rails_routes_with_controller_search_key
app_file "config/routes.rb", <<-RUBY
Rails.application.routes.draw do
get '/cart', to: 'cart#show'
@@ -213,7 +213,7 @@ module ApplicationTests
assert_equal "Prefix Verb URI Pattern Controller#Action\n cart GET /cart(.:format) cart#show\n", output
end
- def test_rake_routes_displays_message_when_no_routes_are_defined
+ def test_rails_routes_displays_message_when_no_routes_are_defined
app_file "config/routes.rb", <<-RUBY
Rails.application.routes.draw do
end
diff --git a/railties/test/commands/server_test.rb b/railties/test/commands/server_test.rb
index 0c49bd9c53..964b9a44de 100644
--- a/railties/test/commands/server_test.rb
+++ b/railties/test/commands/server_test.rb
@@ -54,7 +54,8 @@ class Rails::ServerTest < ActiveSupport::TestCase
def test_caching_without_option
args = []
options = Rails::Server::Options.new.parse!(args)
- assert_equal nil, options[:caching]
+ merged_options = Rails::Server.new.default_options.merge(options)
+ assert_equal nil, merged_options[:caching]
end
def test_caching_with_option
diff --git a/railties/test/generators/actions_test.rb b/railties/test/generators/actions_test.rb
index 58394a11f0..3b2b3c37d0 100644
--- a/railties/test/generators/actions_test.rb
+++ b/railties/test/generators/actions_test.rb
@@ -202,7 +202,7 @@ class ActionsTest < Rails::Generators::TestCase
end
def test_rails_should_run_rake_command_with_default_env
- assert_called_with(generator, :run, ["rails log:clear RAILS_ENV=development", verbose: false]) do
+ assert_called_with(generator, :run, ["rake log:clear RAILS_ENV=development", verbose: false]) do
with_rails_env nil do
action :rake, 'log:clear'
end
@@ -210,13 +210,13 @@ class ActionsTest < Rails::Generators::TestCase
end
def test_rails_with_env_option_should_run_rake_command_in_env
- assert_called_with(generator, :run, ['rails log:clear RAILS_ENV=production', verbose: false]) do
+ assert_called_with(generator, :run, ['rake log:clear RAILS_ENV=production', verbose: false]) do
action :rake, 'log:clear', env: 'production'
end
end
test "rails command with RAILS_ENV variable should run rake command in env" do
- assert_called_with(generator, :run, ['rails log:clear RAILS_ENV=production', verbose: false]) do
+ assert_called_with(generator, :run, ['rake log:clear RAILS_ENV=production', verbose: false]) do
with_rails_env "production" do
action :rake, 'log:clear'
end
@@ -224,7 +224,7 @@ class ActionsTest < Rails::Generators::TestCase
end
test "env option should win over RAILS_ENV variable when running rake" do
- assert_called_with(generator, :run, ['rails log:clear RAILS_ENV=production', verbose: false]) do
+ assert_called_with(generator, :run, ['rake log:clear RAILS_ENV=production', verbose: false]) do
with_rails_env "staging" do
action :rake, 'log:clear', env: 'production'
end
@@ -232,7 +232,7 @@ class ActionsTest < Rails::Generators::TestCase
end
test "rails command with sudo option should run rake command with sudo" do
- assert_called_with(generator, :run, ["sudo rails log:clear RAILS_ENV=development", verbose: false]) do
+ assert_called_with(generator, :run, ["sudo rake log:clear RAILS_ENV=development", verbose: false]) do
with_rails_env nil do
action :rake, 'log:clear', sudo: true
end
diff --git a/railties/test/generators/app_generator_test.rb b/railties/test/generators/app_generator_test.rb
index 2cbce4bc5e..0572a23df9 100644
--- a/railties/test/generators/app_generator_test.rb
+++ b/railties/test/generators/app_generator_test.rb
@@ -126,7 +126,7 @@ class AppGeneratorTest < Rails::Generators::TestCase
# make sure we are in correct dir
FileUtils.cd(app_moved_root)
- generator = Rails::Generators::AppGenerator.new ["rails"], { with_dispatchers: true },
+ generator = Rails::Generators::AppGenerator.new ["rails"], [],
destination_root: app_moved_root, shell: @shell
generator.send(:app_const)
quietly { generator.send(:update_config_files) }
@@ -141,7 +141,7 @@ class AppGeneratorTest < Rails::Generators::TestCase
run_generator [app_root]
stub_rails_application(app_root) do
- generator = Rails::Generators::AppGenerator.new ["rails"], { with_dispatchers: true }, destination_root: app_root, shell: @shell
+ generator = Rails::Generators::AppGenerator.new ["rails"], [], destination_root: app_root, shell: @shell
generator.send(:app_const)
quietly { generator.send(:update_config_files) }
assert_file "myapp/config/initializers/session_store.rb", /_myapp_session/
@@ -165,7 +165,7 @@ class AppGeneratorTest < Rails::Generators::TestCase
run_generator [app_root]
stub_rails_application(app_root) do
- generator = Rails::Generators::AppGenerator.new ["rails"], { with_dispatchers: true }, destination_root: app_root, shell: @shell
+ generator = Rails::Generators::AppGenerator.new ["rails"], [], destination_root: app_root, shell: @shell
generator.send(:app_const)
quietly { generator.send(:update_config_files) }
assert_file("#{app_root}/config/initializers/cookies_serializer.rb", /Rails\.application\.config\.action_dispatch\.cookies_serializer = :json/)
@@ -179,7 +179,7 @@ class AppGeneratorTest < Rails::Generators::TestCase
FileUtils.rm("#{app_root}/config/initializers/callback_terminator.rb")
stub_rails_application(app_root) do
- generator = Rails::Generators::AppGenerator.new ["rails"], { with_dispatchers: true }, destination_root: app_root, shell: @shell
+ generator = Rails::Generators::AppGenerator.new ["rails"], [], destination_root: app_root, shell: @shell
generator.send(:app_const)
quietly { generator.send(:update_config_files) }
assert_no_file "#{app_root}/config/initializers/callback_terminator.rb"
@@ -193,7 +193,7 @@ class AppGeneratorTest < Rails::Generators::TestCase
FileUtils.touch("#{app_root}/config/initializers/callback_terminator.rb")
stub_rails_application(app_root) do
- generator = Rails::Generators::AppGenerator.new ["rails"], { with_dispatchers: true }, destination_root: app_root, shell: @shell
+ generator = Rails::Generators::AppGenerator.new ["rails"], [], destination_root: app_root, shell: @shell
generator.send(:app_const)
quietly { generator.send(:update_config_files) }
assert_file "#{app_root}/config/initializers/callback_terminator.rb"
@@ -207,7 +207,7 @@ class AppGeneratorTest < Rails::Generators::TestCase
FileUtils.rm("#{app_root}/config/initializers/cookies_serializer.rb")
stub_rails_application(app_root) do
- generator = Rails::Generators::AppGenerator.new ["rails"], { with_dispatchers: true }, destination_root: app_root, shell: @shell
+ generator = Rails::Generators::AppGenerator.new ["rails"], [], destination_root: app_root, shell: @shell
generator.send(:app_const)
quietly { generator.send(:update_config_files) }
assert_file("#{app_root}/config/initializers/cookies_serializer.rb",
@@ -215,6 +215,20 @@ class AppGeneratorTest < Rails::Generators::TestCase
end
end
+ def test_rails_update_dont_set_file_watcher
+ app_root = File.join(destination_root, 'myapp')
+ run_generator [app_root]
+
+ stub_rails_application(app_root) do
+ generator = Rails::Generators::AppGenerator.new ["rails"], [], destination_root: app_root, shell: @shell
+ generator.send(:app_const)
+ quietly { generator.send(:update_config_files) }
+ assert_file "#{app_root}/config/environments/development.rb" do |content|
+ assert_match(/# config.file_watcher/, content)
+ end
+ end
+ end
+
def test_rails_update_does_not_create_active_record_belongs_to_required_by_default
app_root = File.join(destination_root, 'myapp')
run_generator [app_root]
@@ -222,7 +236,7 @@ class AppGeneratorTest < Rails::Generators::TestCase
FileUtils.rm("#{app_root}/config/initializers/active_record_belongs_to_required_by_default.rb")
stub_rails_application(app_root) do
- generator = Rails::Generators::AppGenerator.new ["rails"], { with_dispatchers: true }, destination_root: app_root, shell: @shell
+ generator = Rails::Generators::AppGenerator.new ["rails"], [], destination_root: app_root, shell: @shell
generator.send(:app_const)
quietly { generator.send(:update_config_files) }
assert_no_file "#{app_root}/config/initializers/active_record_belongs_to_required_by_default.rb"
@@ -236,7 +250,7 @@ class AppGeneratorTest < Rails::Generators::TestCase
FileUtils.touch("#{app_root}/config/initializers/active_record_belongs_to_required_by_default.rb")
stub_rails_application(app_root) do
- generator = Rails::Generators::AppGenerator.new ["rails"], { with_dispatchers: true }, destination_root: app_root, shell: @shell
+ generator = Rails::Generators::AppGenerator.new ["rails"], [], destination_root: app_root, shell: @shell
generator.send(:app_const)
quietly { generator.send(:update_config_files) }
assert_file "#{app_root}/config/initializers/active_record_belongs_to_required_by_default.rb"
@@ -250,7 +264,7 @@ class AppGeneratorTest < Rails::Generators::TestCase
FileUtils.rm("#{app_root}/config/initializers/ssl_options.rb")
stub_rails_application(app_root) do
- generator = Rails::Generators::AppGenerator.new ["rails"], { with_dispatchers: true }, destination_root: app_root, shell: @shell
+ generator = Rails::Generators::AppGenerator.new ["rails"], [], destination_root: app_root, shell: @shell
generator.send(:app_const)
quietly { generator.send(:update_config_files) }
assert_no_file "#{app_root}/config/initializers/ssl_options.rb"
@@ -264,7 +278,7 @@ class AppGeneratorTest < Rails::Generators::TestCase
FileUtils.touch("#{app_root}/config/initializers/ssl_options.rb")
stub_rails_application(app_root) do
- generator = Rails::Generators::AppGenerator.new ["rails"], { with_dispatchers: true }, destination_root: app_root, shell: @shell
+ generator = Rails::Generators::AppGenerator.new ["rails"], [], destination_root: app_root, shell: @shell
generator.send(:app_const)
quietly { generator.send(:update_config_files) }
assert_file "#{app_root}/config/initializers/ssl_options.rb"
@@ -276,7 +290,7 @@ class AppGeneratorTest < Rails::Generators::TestCase
run_generator [app_root]
stub_rails_application(app_root) do
- generator = Rails::Generators::AppGenerator.new ["rails"], { with_dispatchers: true }, destination_root: app_root, shell: @shell
+ generator = Rails::Generators::AppGenerator.new ["rails"], [], destination_root: app_root, shell: @shell
generator.send(:app_const)
quietly { generator.send(:update_config_files) }
assert_no_file "#{app_root}/config/initializers/cors.rb"
@@ -290,7 +304,7 @@ class AppGeneratorTest < Rails::Generators::TestCase
FileUtils.touch("#{app_root}/config/initializers/cors.rb")
stub_rails_application(app_root) do
- generator = Rails::Generators::AppGenerator.new ["rails"], { with_dispatchers: true }, destination_root: app_root, shell: @shell
+ generator = Rails::Generators::AppGenerator.new ["rails"], [], destination_root: app_root, shell: @shell
generator.send(:app_const)
quietly { generator.send(:update_config_files) }
assert_file "#{app_root}/config/initializers/cors.rb"
@@ -632,7 +646,7 @@ class AppGeneratorTest < Rails::Generators::TestCase
assert_file "Gemfile" do |content|
assert_match(/gem 'web-console',\s+github: 'rails\/web-console'/, content)
- assert_no_match(/gem 'web-console', '~> 3.0'/, content)
+ assert_no_match(/\Agem 'web-console'\z/, content)
end
end
@@ -641,7 +655,7 @@ class AppGeneratorTest < Rails::Generators::TestCase
assert_file "Gemfile" do |content|
assert_match(/gem 'web-console',\s+github: 'rails\/web-console'/, content)
- assert_no_match(/gem 'web-console', '~> 3.0'/, content)
+ assert_no_match(/\Agem 'web-console'\z/, content)
end
end
diff --git a/railties/test/generators/mailer_generator_test.rb b/railties/test/generators/mailer_generator_test.rb
index f8d9ccacb4..8728b39dae 100644
--- a/railties/test/generators/mailer_generator_test.rb
+++ b/railties/test/generators/mailer_generator_test.rb
@@ -12,6 +12,12 @@ class MailerGeneratorTest < Rails::Generators::TestCase
assert_no_match(/default from: "from@example.com"/, mailer)
assert_no_match(/layout :mailer_notifier/, mailer)
end
+
+ assert_file 'app/mailers/application_mailer.rb' do |mailer|
+ assert_match(/class ApplicationMailer < ActionMailer::Base/, mailer)
+ assert_match(/default from: 'from@example.com'/, mailer)
+ assert_match(/layout 'mailer'/, mailer)
+ end
end
def test_mailer_with_i18n_helper