aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Gemfile5
-rw-r--r--Gemfile.lock24
-rw-r--r--RELEASING_RAILS.md6
-rw-r--r--actioncable/README.md2
-rw-r--r--actioncable/app/assets/javascripts/action_cable.coffee.erb4
-rw-r--r--actioncable/app/assets/javascripts/action_cable/connection.coffee2
-rw-r--r--actioncable/blade.yml12
-rw-r--r--actioncable/lib/action_cable/channel/streams.rb2
-rw-r--r--actioncable/test/javascript/src/test.coffee2
-rw-r--r--actioncable/test/javascript/src/test_helpers/consumer_test_helper.coffee37
-rw-r--r--actioncable/test/javascript/src/test_helpers/index.coffee3
-rw-r--r--actioncable/test/javascript/src/test_helpers/mock_websocket.coffee21
-rw-r--r--actioncable/test/javascript/src/unit/action_cable_test.coffee17
-rw-r--r--actioncable/test/javascript/src/unit/consumer_test.coffee34
-rw-r--r--actionmailer/lib/action_mailer/base.rb2
-rw-r--r--actionpack/lib/action_controller/test_case.rb49
-rw-r--r--actionpack/test/abstract_unit.rb27
-rw-r--r--actionpack/test/controller/metal/renderers_test.rb6
-rw-r--r--actionpack/test/controller/resources_test.rb16
-rw-r--r--actionpack/test/controller/test_case_test.rb24
-rw-r--r--actionpack/test/dispatch/routing/concerns_test.rb2
-rw-r--r--activemodel/test/cases/helper.rb1
-rw-r--r--activemodel/test/models/project.rb3
-rw-r--r--activerecord/CHANGELOG.md5
-rw-r--r--activerecord/lib/active_record/aggregations.rb9
-rw-r--r--activerecord/lib/active_record/attribute.rb20
-rw-r--r--activerecord/lib/active_record/attribute_set.rb3
-rw-r--r--activerecord/lib/active_record/attribute_set/builder.rb2
-rw-r--r--activerecord/lib/active_record/attribute_set/yaml_encoder.rb39
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb13
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb4
-rw-r--r--activerecord/lib/active_record/core.rb10
-rw-r--r--activerecord/lib/active_record/legacy_yaml_adapter.rb2
-rw-r--r--activerecord/lib/active_record/model_schema.rb5
-rw-r--r--activerecord/test/cases/adapters/mysql2/charset_collation_test.rb2
-rw-r--r--activerecord/test/cases/aggregations_test.rb5
-rw-r--r--activerecord/test/cases/base_test.rb4
-rw-r--r--activerecord/test/cases/invertible_migration_test.rb15
-rw-r--r--activerecord/test/cases/schema_dumper_test.rb19
-rw-r--r--activerecord/test/cases/yaml_serialization_test.rb10
-rw-r--r--activerecord/test/models/customer.rb7
-rw-r--r--railties/lib/rails/generators/app_base.rb2
-rw-r--r--railties/lib/rails/generators/rails/app/app_generator.rb29
-rw-r--r--railties/lib/rails/generators/rails/app/templates/config/initializers/new_framework_defaults.rb.tt37
-rw-r--r--railties/lib/rails/generators/rails/app/templates/config/initializers/new_framework_defaults/active_record_belongs_to_required_by_default.rb6
-rw-r--r--railties/lib/rails/generators/rails/app/templates/config/initializers/new_framework_defaults/callback_terminator.rb6
-rw-r--r--railties/lib/rails/generators/rails/app/templates/config/initializers/new_framework_defaults/per_form_csrf_tokens.rb4
-rw-r--r--railties/lib/rails/generators/rails/app/templates/config/initializers/new_framework_defaults/request_forgery_protection.rb4
-rw-r--r--railties/lib/rails/generators/rails/app/templates/config/initializers/new_framework_defaults/ssl_options.rb6
-rw-r--r--railties/lib/rails/generators/rails/app/templates/config/initializers/new_framework_defaults/to_time_preserves_timezone.rb10
-rw-r--r--railties/test/generators/api_app_generator_test.rb11
-rw-r--r--railties/test/generators/app_generator_test.rb101
52 files changed, 375 insertions, 316 deletions
diff --git a/Gemfile b/Gemfile
index 858aa55916..c851d32dea 100644
--- a/Gemfile
+++ b/Gemfile
@@ -65,8 +65,11 @@ group :cable do
gem 'faye-websocket', require: false
+ # Lock to 1.1.1 until the fix for https://github.com/faye/faye/issues/394 is released
+ gem 'faye', '1.1.1', require: false
+
gem 'blade', '~> 0.5.5', require: false
- gem 'blade-sauce_labs_plugin', github: 'javan/blade-sauce_labs_plugin', require: false
+ gem 'blade-sauce_labs_plugin', '~> 0.5.1', require: false
end
# Add your own local bundler stuff.
diff --git a/Gemfile.lock b/Gemfile.lock
index 7cddaa7e3b..ed325aef55 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -22,15 +22,6 @@ GIT
delayed_job (>= 3.0, < 5)
GIT
- remote: git://github.com/javan/blade-sauce_labs_plugin.git
- revision: dd4230c556aaa19b62cca757d6faeb2bb6bf95e7
- specs:
- blade-sauce_labs_plugin (0.5.1)
- childprocess
- faraday
- selenium-webdriver
-
-GIT
remote: git://github.com/rails/coffee-rails.git
revision: aa2e623cbda4f3c789a0a15d1f707239e68f5736
specs:
@@ -139,6 +130,10 @@ GEM
thor (~> 0.19.1)
useragent (~> 0.16.7)
blade-qunit_adapter (1.20.0)
+ blade-sauce_labs_plugin (0.5.1)
+ childprocess
+ faraday
+ selenium-webdriver
builder (3.2.2)
bunny (2.2.2)
amq-protocol (>= 2.0.1)
@@ -174,7 +169,7 @@ GEM
execjs (2.6.0)
faraday (0.9.2)
multipart-post (>= 1.2, < 3)
- faye (1.1.2)
+ faye (1.1.1)
cookiejar (>= 0.3.0)
em-http-request (>= 0.3.0)
eventmachine (>= 0.12.0)
@@ -182,7 +177,7 @@ GEM
multi_json (>= 1.0.0)
rack (>= 1.0.0)
websocket-driver (>= 0.5.1)
- faye-websocket (0.10.3)
+ faye-websocket (0.10.4)
eventmachine (>= 0.12.0)
websocket-driver (>= 0.5.1)
ffi (1.9.10)
@@ -218,7 +213,7 @@ GEM
mocha (0.14.0)
metaclass (~> 0.0.1)
mono_logger (1.1.0)
- multi_json (1.12.0)
+ multi_json (1.12.1)
multipart-post (2.0.0)
mustache (1.0.3)
mysql2 (0.4.4)
@@ -337,7 +332,7 @@ GEM
nokogiri
wdm (0.1.1)
websocket (1.2.3)
- websocket-driver (0.6.3)
+ websocket-driver (0.6.4)
websocket-extensions (>= 0.1.0)
websocket-extensions (0.1.2)
@@ -354,13 +349,14 @@ DEPENDENCIES
bcrypt (~> 3.1.11)
benchmark-ips
blade (~> 0.5.5)
- blade-sauce_labs_plugin!
+ blade-sauce_labs_plugin (~> 0.5.1)
byebug
coffee-rails!
dalli (>= 2.2.1)
delayed_job!
delayed_job_active_record!
em-hiredis
+ faye (= 1.1.1)
faye-websocket
hiredis
jquery-rails
diff --git a/RELEASING_RAILS.md b/RELEASING_RAILS.md
index 5ed5a8b029..4e6b811d3e 100644
--- a/RELEASING_RAILS.md
+++ b/RELEASING_RAILS.md
@@ -20,7 +20,7 @@ http://travis-ci.org/rails/rails
### Is Sam Ruby happy? If not, make him happy.
Sam Ruby keeps a [test suite](https://github.com/rubys/awdwr) that makes
-sure the code samples in his book
+sure the code samples in his book
([Agile Web Development with Rails](https://pragprog.com/titles/rails5/agile-web-development-with-rails-5th-edition))
all work. These are valuable system tests
for Rails. You can check the status of these tests here:
@@ -47,7 +47,7 @@ Ruby implementors have high stakes in making sure Rails works. Be kind and
give them a heads up that Rails will be released soonish.
This is only required for major and minor releases, bugfix releases aren't a
-big enough deal, and are supposed to be backwards compatible.
+big enough deal, and are supposed to be backward compatible.
Send an email just giving a heads up about the upcoming release to these
lists:
@@ -150,7 +150,7 @@ break existing applications.
### Post the announcement to the Rails blog.
-If you used Markdown format for your email, you can just paste it in to the
+If you used Markdown format for your email, you can just paste it into the
blog.
* http://weblog.rubyonrails.org
diff --git a/actioncable/README.md b/actioncable/README.md
index 71fec714f5..fa6a3ed0df 100644
--- a/actioncable/README.md
+++ b/actioncable/README.md
@@ -430,7 +430,7 @@ For every instance of your server you create and for every worker your server sp
### Notes
-Beware that currently the cable server will _not_ auto-reload any changes in the framework. As we've discussed, long-running cable connections mean long-running objects. We don't yet have a way of reloading the classes of those objects in a safe manner. So when you change your channels, or the model your channels use, you must restart the cable server.
+Beware that currently, the cable server will _not_ auto-reload any changes in the framework. As we've discussed, long-running cable connections mean long-running objects. We don't yet have a way of reloading the classes of those objects in a safe manner. So when you change your channels, or the model your channels use, you must restart the cable server.
We'll get all this abstracted properly when the framework is integrated into Rails.
diff --git a/actioncable/app/assets/javascripts/action_cable.coffee.erb b/actioncable/app/assets/javascripts/action_cable.coffee.erb
index 210a3ae17e..e0758dae72 100644
--- a/actioncable/app/assets/javascripts/action_cable.coffee.erb
+++ b/actioncable/app/assets/javascripts/action_cable.coffee.erb
@@ -4,6 +4,8 @@
@ActionCable =
INTERNAL: <%= ActionCable::INTERNAL.to_json %>
+ WebSocket: window.WebSocket
+ logger: window.console
createConsumer: (url) ->
url ?= @getConfig("url") ? @INTERNAL.default_mount_path
@@ -33,4 +35,4 @@
log: (messages...) ->
if @debugging
messages.push(Date.now())
- console.log("[ActionCable]", messages...)
+ @logger.log("[ActionCable]", messages...)
diff --git a/actioncable/app/assets/javascripts/action_cable/connection.coffee b/actioncable/app/assets/javascripts/action_cable/connection.coffee
index d6a6397804..29ad676290 100644
--- a/actioncable/app/assets/javascripts/action_cable/connection.coffee
+++ b/actioncable/app/assets/javascripts/action_cable/connection.coffee
@@ -27,7 +27,7 @@ class ActionCable.Connection
else
ActionCable.log("Opening WebSocket, current state is #{@getState()}, subprotocols: #{protocols}")
@uninstallEventHandlers() if @webSocket?
- @webSocket = new WebSocket(@consumer.url, protocols)
+ @webSocket = new ActionCable.WebSocket(@consumer.url, protocols)
@installEventHandlers()
@monitor.start()
true
diff --git a/actioncable/blade.yml b/actioncable/blade.yml
index e21151099a..e38e9b2f1d 100644
--- a/actioncable/blade.yml
+++ b/actioncable/blade.yml
@@ -17,18 +17,18 @@ plugins:
browsers:
Google Chrome:
os: Mac, Windows
- version: -2
+ version: -1
Firefox:
os: Mac, Windows
- version: -2
+ version: -1
Safari:
platform: Mac
- version: -3
+ version: -1
Microsoft Edge:
- version: -2
+ version: -1
Internet Explorer:
version: 11
iPhone:
- version: [9.2, 8.4]
+ version: -1
Motorola Droid 4 Emulator:
- version: [5.1, 4.4]
+ version: -1
diff --git a/actioncable/lib/action_cable/channel/streams.rb b/actioncable/lib/action_cable/channel/streams.rb
index 0a0a95f453..561750d713 100644
--- a/actioncable/lib/action_cable/channel/streams.rb
+++ b/actioncable/lib/action_cable/channel/streams.rb
@@ -138,7 +138,7 @@ module ActionCable
end
# May be overridden to change the default stream handling behavior
- # which decodes JSON and transmits to client.
+ # which decodes JSON and transmits to the client.
#
# TODO: Tests demonstrating this.
#
diff --git a/actioncable/test/javascript/src/test.coffee b/actioncable/test/javascript/src/test.coffee
index 3ce88c7789..eb95fb2604 100644
--- a/actioncable/test/javascript/src/test.coffee
+++ b/actioncable/test/javascript/src/test.coffee
@@ -1,3 +1,3 @@
#= require action_cable
-#= require_tree ./test_helpers
+#= require ./test_helpers
#= require_tree ./unit
diff --git a/actioncable/test/javascript/src/test_helpers/consumer_test_helper.coffee b/actioncable/test/javascript/src/test_helpers/consumer_test_helper.coffee
new file mode 100644
index 0000000000..6b145dede8
--- /dev/null
+++ b/actioncable/test/javascript/src/test_helpers/consumer_test_helper.coffee
@@ -0,0 +1,37 @@
+#= require mock-socket
+
+{TestHelpers} = ActionCable
+
+TestHelpers.consumerTest = (name, options = {}, callback) ->
+ unless callback?
+ callback = options
+ options = {}
+
+ options.url ?= TestHelpers.testURL
+
+ QUnit.test name, (assert) ->
+ doneAsync = assert.async()
+
+ ActionCable.WebSocket = MockWebSocket
+ server = new MockServer options.url
+ consumer = ActionCable.createConsumer(options.url)
+
+ server.on "connection", ->
+ clients = server.clients()
+ assert.equal clients.length, 1
+ assert.equal clients[0].readyState, WebSocket.OPEN
+
+ done = ->
+ consumer.disconnect()
+ server.close()
+ doneAsync()
+
+ testData = {assert, consumer, server, done}
+
+ if options.connect is false
+ callback(testData)
+ else
+ server.on "connection", ->
+ testData.client = server.clients()[0]
+ callback(testData)
+ consumer.connect()
diff --git a/actioncable/test/javascript/src/test_helpers/index.coffee b/actioncable/test/javascript/src/test_helpers/index.coffee
index e0d1e412cd..d36524d9cc 100644
--- a/actioncable/test/javascript/src/test_helpers/index.coffee
+++ b/actioncable/test/javascript/src/test_helpers/index.coffee
@@ -3,3 +3,6 @@
ActionCable.TestHelpers =
testURL: "ws://cable.example.com/"
+
+originalWebSocket = ActionCable.WebSocket
+QUnit.testDone -> ActionCable.WebSocket = originalWebSocket
diff --git a/actioncable/test/javascript/src/test_helpers/mock_websocket.coffee b/actioncable/test/javascript/src/test_helpers/mock_websocket.coffee
deleted file mode 100644
index b7f86f18f6..0000000000
--- a/actioncable/test/javascript/src/test_helpers/mock_websocket.coffee
+++ /dev/null
@@ -1,21 +0,0 @@
-#= require mock-socket
-
-NativeWebSocket = window.WebSocket
-
-server = null
-consumer = null
-
-ActionCable.TestHelpers.createConsumer = (url, callback) ->
- window.WebSocket = MockWebSocket
- server = new MockServer url
- consumer = ActionCable.createConsumer(url)
- callback(consumer, server)
-
-QUnit.testDone ->
- if consumer?
- consumer.disconnect()
-
- if server?
- server.clients().forEach (client) -> client.close()
- server.close()
- window.WebSocket = NativeWebSocket
diff --git a/actioncable/test/javascript/src/unit/action_cable_test.coffee b/actioncable/test/javascript/src/unit/action_cable_test.coffee
index f9eff64769..3944f3a7f6 100644
--- a/actioncable/test/javascript/src/unit/action_cable_test.coffee
+++ b/actioncable/test/javascript/src/unit/action_cable_test.coffee
@@ -2,6 +2,23 @@
{testURL} = ActionCable.TestHelpers
module "ActionCable", ->
+ module "Adapters", ->
+ module "WebSocket", ->
+ test "default is window.WebSocket", (assert) ->
+ assert.equal ActionCable.WebSocket, window.WebSocket
+
+ test "configurable", (assert) ->
+ ActionCable.WebSocket = ""
+ assert.equal ActionCable.WebSocket, ""
+
+ module "logger", ->
+ test "default is window.console", (assert) ->
+ assert.equal ActionCable.logger, window.console
+
+ test "configurable", (assert) ->
+ ActionCable.logger = ""
+ assert.equal ActionCable.logger, ""
+
module "#createConsumer", ->
test "uses specified URL", (assert) ->
consumer = ActionCable.createConsumer(testURL)
diff --git a/actioncable/test/javascript/src/unit/consumer_test.coffee b/actioncable/test/javascript/src/unit/consumer_test.coffee
index d8b1450ad8..cf8a592255 100644
--- a/actioncable/test/javascript/src/unit/consumer_test.coffee
+++ b/actioncable/test/javascript/src/unit/consumer_test.coffee
@@ -1,31 +1,11 @@
{module, test} = QUnit
-{testURL, createConsumer} = ActionCable.TestHelpers
+{consumerTest} = ActionCable.TestHelpers
module "ActionCable.Consumer", ->
- test "#connect", (assert) ->
- done = assert.async()
+ consumerTest "#connect", connect: false, ({consumer, server, done}) ->
+ server.on("connection", done)
+ consumer.connect()
- createConsumer testURL, (consumer, server) ->
- server.on "connection", ->
- clients = server.clients()
- assert.equal clients.length, 1
- assert.equal clients[0].readyState, WebSocket.OPEN
- done()
-
- consumer.connect()
-
- test "#disconnect", (assert) ->
- done = assert.async()
-
- createConsumer testURL, (consumer, server) ->
- server.on "connection", ->
- clients = server.clients()
- assert.equal clients.length, 1
-
- clients[0].addEventListener "close", (event) ->
- assert.equal event.type, "close"
- done()
-
- consumer.disconnect()
-
- consumer.connect()
+ consumerTest "#disconnect", ({consumer, client, done}) ->
+ client.addEventListener("close", done)
+ consumer.disconnect()
diff --git a/actionmailer/lib/action_mailer/base.rb b/actionmailer/lib/action_mailer/base.rb
index ea5af9e4f2..6e0ae8a0a9 100644
--- a/actionmailer/lib/action_mailer/base.rb
+++ b/actionmailer/lib/action_mailer/base.rb
@@ -488,7 +488,7 @@ module ActionMailer
end
private :observer_class_for
- # Returns the name of current mailer. This method is also being used as a path for a view lookup.
+ # Returns the name of the current mailer. This method is also being used as a path for a view lookup.
# If this is an anonymous mailer, this method will return +anonymous+ instead.
def mailer_name
@mailer_name ||= anonymous? ? "anonymous" : name.underscore
diff --git a/actionpack/lib/action_controller/test_case.rb b/actionpack/lib/action_controller/test_case.rb
index ed2edcbe06..b1b3e87934 100644
--- a/actionpack/lib/action_controller/test_case.rb
+++ b/actionpack/lib/action_controller/test_case.rb
@@ -527,34 +527,37 @@ module ActionController
@request.set_header k, @controller.config.relative_url_root
end
- @controller.recycle!
- @controller.dispatch(action, @request, @response)
- @request = @controller.request
- @response = @controller.response
-
- @request.delete_header 'HTTP_COOKIE'
+ begin
+ @controller.recycle!
+ @controller.dispatch(action, @request, @response)
+ ensure
+ @request = @controller.request
+ @response = @controller.response
+
+ @request.delete_header 'HTTP_COOKIE'
+
+ if @request.have_cookie_jar?
+ unless @request.cookie_jar.committed?
+ @request.cookie_jar.write(@response)
+ self.cookies.update(@request.cookie_jar.instance_variable_get(:@cookies))
+ end
+ end
+ @response.prepare!
- if @request.have_cookie_jar?
- unless @request.cookie_jar.committed?
- @request.cookie_jar.write(@response)
- self.cookies.update(@request.cookie_jar.instance_variable_get(:@cookies))
+ if flash_value = @request.flash.to_session_value
+ @request.session['flash'] = flash_value
+ else
+ @request.session.delete('flash')
end
- end
- @response.prepare!
- if flash_value = @request.flash.to_session_value
- @request.session['flash'] = flash_value
- else
- @request.session.delete('flash')
- end
+ if xhr
+ @request.delete_header 'HTTP_X_REQUESTED_WITH'
+ @request.delete_header 'HTTP_ACCEPT'
+ end
+ @request.query_string = ''
- if xhr
- @request.delete_header 'HTTP_X_REQUESTED_WITH'
- @request.delete_header 'HTTP_ACCEPT'
+ @response.sent!
end
- @request.query_string = ''
-
- @response.sent!
@response
end
diff --git a/actionpack/test/abstract_unit.rb b/actionpack/test/abstract_unit.rb
index 618df930c9..1e1d6f5429 100644
--- a/actionpack/test/abstract_unit.rb
+++ b/actionpack/test/abstract_unit.rb
@@ -34,7 +34,6 @@ require 'action_dispatch'
require 'active_support/dependencies'
require 'active_model'
require 'active_record'
-require 'action_controller/caching'
require 'pp' # require 'pp' early to prevent hidden_methods from not picking up the pretty-print methods until too late
@@ -58,10 +57,6 @@ ActiveSupport::Deprecation.debug = true
# Disable available locale checks to avoid warnings running the test suite.
I18n.enforce_available_locales = false
-# Register danish language for testing
-I18n.backend.store_translations 'da', {}
-I18n.backend.store_translations 'pt-BR', {}
-
FIXTURE_LOAD_PATH = File.join(File.dirname(__FILE__), 'fixtures')
SharedTestRoutes = ActionDispatch::Routing::RouteSet.new
@@ -359,37 +354,15 @@ module RoutingTestHelpers
end
end
-class MetalRenderingController < ActionController::Metal
- include AbstractController::Rendering
- include ActionController::Rendering
- include ActionController::Renderers
-end
-
class ResourcesController < ActionController::Base
def index() head :ok end
alias_method :show, :index
end
-class ThreadsController < ResourcesController; end
-class MessagesController < ResourcesController; end
class CommentsController < ResourcesController; end
-class ReviewsController < ResourcesController; end
-
class AccountsController < ResourcesController; end
-class AdminController < ResourcesController; end
-class ProductsController < ResourcesController; end
class ImagesController < ResourcesController; end
-module Backoffice
- class ProductsController < ResourcesController; end
- class ImagesController < ResourcesController; end
-
- module Admin
- class ProductsController < ResourcesController; end
- class ImagesController < ResourcesController; end
- end
-end
-
# Skips the current run on Rubinius using Minitest::Assertions#skip
def rubinius_skip(message = '')
skip message if RUBY_ENGINE == 'rbx'
diff --git a/actionpack/test/controller/metal/renderers_test.rb b/actionpack/test/controller/metal/renderers_test.rb
index 007866a559..247e872674 100644
--- a/actionpack/test/controller/metal/renderers_test.rb
+++ b/actionpack/test/controller/metal/renderers_test.rb
@@ -1,6 +1,12 @@
require 'abstract_unit'
require 'active_support/core_ext/hash/conversions'
+class MetalRenderingController < ActionController::Metal
+ include AbstractController::Rendering
+ include ActionController::Rendering
+ include ActionController::Renderers
+end
+
class MetalRenderingJsonController < MetalRenderingController
class Model
def to_json(options = {})
diff --git a/actionpack/test/controller/resources_test.rb b/actionpack/test/controller/resources_test.rb
index 4490abf7b2..8e38af5025 100644
--- a/actionpack/test/controller/resources_test.rb
+++ b/actionpack/test/controller/resources_test.rb
@@ -3,8 +3,22 @@ require 'active_support/core_ext/object/try'
require 'active_support/core_ext/object/with_options'
require 'active_support/core_ext/array/extract_options'
-class ResourcesTest < ActionController::TestCase
+class AdminController < ResourcesController; end
+class MessagesController < ResourcesController; end
+class ProductsController < ResourcesController; end
+class ThreadsController < ResourcesController; end
+
+module Backoffice
+ class ProductsController < ResourcesController; end
+ class ImagesController < ResourcesController; end
+
+ module Admin
+ class ProductsController < ResourcesController; end
+ class ImagesController < ResourcesController; end
+ end
+end
+class ResourcesTest < ActionController::TestCase
def test_default_restful_routes
with_restful_routing :messages do
assert_simply_restful_for :messages
diff --git a/actionpack/test/controller/test_case_test.rb b/actionpack/test/controller/test_case_test.rb
index 6160b3395a..ea59156f65 100644
--- a/actionpack/test/controller/test_case_test.rb
+++ b/actionpack/test/controller/test_case_test.rb
@@ -154,6 +154,10 @@ XML
render html: '<body class="foo"></body>'.html_safe
end
+ def boom
+ raise 'boom!'
+ end
+
private
def generate_url(opts)
@@ -981,6 +985,26 @@ XML
assert_redirected_to 'created resource'
end
end
+
+ def test_exception_in_action_reaches_test
+ assert_raise(RuntimeError) do
+ process :boom, method: "GET"
+ end
+ end
+
+ def test_request_state_is_cleared_after_exception
+ assert_raise(RuntimeError) do
+ process :boom,
+ method: "GET",
+ params: { q: 'test1' }
+ end
+
+ process :test_query_string,
+ method: "GET",
+ params: { q: 'test2' }
+
+ assert_equal "q=test2", @response.body
+ end
end
class ResponseDefaultHeadersTest < ActionController::TestCase
diff --git a/actionpack/test/dispatch/routing/concerns_test.rb b/actionpack/test/dispatch/routing/concerns_test.rb
index 7ef513b0c8..6934271846 100644
--- a/actionpack/test/dispatch/routing/concerns_test.rb
+++ b/actionpack/test/dispatch/routing/concerns_test.rb
@@ -1,5 +1,7 @@
require 'abstract_unit'
+class ReviewsController < ResourcesController; end
+
class RoutingConcernsTest < ActionDispatch::IntegrationTest
class Reviewable
def self.call(mapper, options = {})
diff --git a/activemodel/test/cases/helper.rb b/activemodel/test/cases/helper.rb
index 44c26e4f10..c589fd2c33 100644
--- a/activemodel/test/cases/helper.rb
+++ b/activemodel/test/cases/helper.rb
@@ -1,5 +1,4 @@
require 'active_model'
-require 'active_support/core_ext/string/access'
# Show backtraces for deprecated behavior for quicker cleanup.
ActiveSupport::Deprecation.debug = true
diff --git a/activemodel/test/models/project.rb b/activemodel/test/models/project.rb
deleted file mode 100644
index 581b6dc0b3..0000000000
--- a/activemodel/test/models/project.rb
+++ /dev/null
@@ -1,3 +0,0 @@
-class Project
- include ActiveModel::DeprecatedMassAssignmentSecurity
-end
diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md
index 929f241b1b..a1a4d2646f 100644
--- a/activerecord/CHANGELOG.md
+++ b/activerecord/CHANGELOG.md
@@ -1,3 +1,8 @@
+* Ensure hashes can be assigned to attributes created using `composed_of`.
+ Fixes #25210.
+
+ *Sean Griffin*
+
* Fix logging edge case where if an attribute was of the binary type and
was provided as a Hash.
diff --git a/activerecord/lib/active_record/aggregations.rb b/activerecord/lib/active_record/aggregations.rb
index 3ff41ed81b..8bed5bca28 100644
--- a/activerecord/lib/active_record/aggregations.rb
+++ b/activerecord/lib/active_record/aggregations.rb
@@ -256,15 +256,16 @@ module ActiveRecord
def writer_method(name, class_name, mapping, allow_nil, converter)
define_method("#{name}=") do |part|
klass = class_name.constantize
- if part.is_a?(Hash)
- raise ArgumentError unless part.size == part.keys.max
- part = klass.new(*part.sort.map(&:last))
- end
unless part.is_a?(klass) || converter.nil? || part.nil?
part = converter.respond_to?(:call) ? converter.call(part) : klass.send(converter, part)
end
+ if part.is_a?(Hash)
+ raise ArgumentError unless part.size == part.keys.max
+ part = klass.new(*part.sort.map(&:last))
+ end
+
if part.nil? && allow_nil
mapping.each { |key, _| self[key] = nil }
@aggregation_cache[name] = nil
diff --git a/activerecord/lib/active_record/attribute.rb b/activerecord/lib/active_record/attribute.rb
index 24231dc9e1..701d24da88 100644
--- a/activerecord/lib/active_record/attribute.rb
+++ b/activerecord/lib/active_record/attribute.rb
@@ -108,6 +108,22 @@ module ActiveRecord
[self.class, name, value_before_type_cast, type].hash
end
+ def init_with(coder)
+ @name = coder["name"]
+ @value_before_type_cast = coder["value_before_type_cast"]
+ @type = coder["type"]
+ @original_attribute = coder["original_attribute"]
+ @value = coder["value"] if coder.map.key?("value")
+ end
+
+ def encode_with(coder)
+ coder["name"] = name
+ coder["value_before_type_cast"] = value_before_type_cast if value_before_type_cast
+ coder["type"] = type if type
+ coder["original_attribute"] = original_attribute if original_attribute
+ coder["value"] = value if defined?(@value)
+ end
+
protected
attr_reader :original_attribute
@@ -201,6 +217,10 @@ module ActiveRecord
def initialized?
false
end
+
+ def with_type(type)
+ self.class.new(name, type)
+ end
end
private_constant :FromDatabase, :FromUser, :Null, :Uninitialized, :WithCastValue
end
diff --git a/activerecord/lib/active_record/attribute_set.rb b/activerecord/lib/active_record/attribute_set.rb
index be581ac2a9..720d5f8b7c 100644
--- a/activerecord/lib/active_record/attribute_set.rb
+++ b/activerecord/lib/active_record/attribute_set.rb
@@ -1,7 +1,10 @@
require 'active_record/attribute_set/builder'
+require 'active_record/attribute_set/yaml_encoder'
module ActiveRecord
class AttributeSet # :nodoc:
+ delegate :each_value, to: :attributes
+
def initialize(attributes)
@attributes = attributes
end
diff --git a/activerecord/lib/active_record/attribute_set/builder.rb b/activerecord/lib/active_record/attribute_set/builder.rb
index 3bd7c7997b..24a255efc1 100644
--- a/activerecord/lib/active_record/attribute_set/builder.rb
+++ b/activerecord/lib/active_record/attribute_set/builder.rb
@@ -22,7 +22,7 @@ module ActiveRecord
end
class LazyAttributeHash # :nodoc:
- delegate :transform_values, :each_key, to: :materialize
+ delegate :transform_values, :each_key, :each_value, to: :materialize
def initialize(types, values, additional_types)
@types = types
diff --git a/activerecord/lib/active_record/attribute_set/yaml_encoder.rb b/activerecord/lib/active_record/attribute_set/yaml_encoder.rb
new file mode 100644
index 0000000000..6208048231
--- /dev/null
+++ b/activerecord/lib/active_record/attribute_set/yaml_encoder.rb
@@ -0,0 +1,39 @@
+module ActiveRecord
+ class AttributeSet
+ # Attempts to do more intelligent YAML dumping of an
+ # ActiveRecord::AttributeSet to reduce the size of the resulting string
+ class YAMLEncoder
+ def initialize(default_types)
+ @default_types = default_types
+ end
+
+ def encode(attribute_set, coder)
+ coder['concise_attributes'] = attribute_set.each_value.map do |attr|
+ if attr.type.equal?(default_types[attr.name])
+ attr.with_type(nil)
+ else
+ attr
+ end
+ end
+ end
+
+ def decode(coder)
+ if coder['attributes']
+ coder['attributes']
+ else
+ attributes_hash = Hash[coder['concise_attributes'].map do |attr|
+ if attr.type.nil?
+ attr = attr.with_type(default_types[attr.name])
+ end
+ [attr.name, attr]
+ end]
+ AttributeSet.new(attributes_hash)
+ end
+ end
+
+ protected
+
+ attr_reader :default_types
+ end
+ end
+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 99a3e99bdc..5939ee9956 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb
@@ -847,14 +847,19 @@ module ActiveRecord
#
# remove_reference(:products, :user, index: true, foreign_key: true)
#
- def remove_reference(table_name, ref_name, options = {})
- if options[:foreign_key]
+ def remove_reference(table_name, ref_name, foreign_key: false, polymorphic: false, **options)
+ if foreign_key
reference_name = Base.pluralize_table_names ? ref_name.to_s.pluralize : ref_name
- remove_foreign_key(table_name, reference_name)
+ if foreign_key.is_a?(Hash)
+ foreign_key_options = foreign_key
+ else
+ foreign_key_options = { to_table: reference_name }
+ end
+ remove_foreign_key(table_name, **foreign_key_options)
end
remove_column(table_name, "#{ref_name}_id")
- remove_column(table_name, "#{ref_name}_type") if options[:polymorphic]
+ remove_column(table_name, "#{ref_name}_type") if polymorphic
end
alias :remove_belongs_to :remove_reference
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 44b4b547f3..718a6c5b91 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb
@@ -41,14 +41,14 @@ module ActiveRecord
NATIVE_DATABASE_TYPES = {
primary_key: "int auto_increment PRIMARY KEY",
string: { name: "varchar", limit: 255 },
- text: { name: "text" },
+ text: { name: "text", limit: 65535 },
integer: { name: "int", limit: 4 },
float: { name: "float" },
decimal: { name: "decimal" },
datetime: { name: "datetime" },
time: { name: "time" },
date: { name: "date" },
- binary: { name: "blob" },
+ binary: { name: "blob", limit: 65535 },
boolean: { name: "tinyint", limit: 1 },
json: { name: "json" },
}
diff --git a/activerecord/lib/active_record/core.rb b/activerecord/lib/active_record/core.rb
index f936e865e4..de337b24d6 100644
--- a/activerecord/lib/active_record/core.rb
+++ b/activerecord/lib/active_record/core.rb
@@ -338,7 +338,7 @@ module ActiveRecord
# post.title # => 'hello world'
def init_with(coder)
coder = LegacyYamlAdapter.convert(self.class, coder)
- @attributes = coder['attributes']
+ @attributes = self.class.yaml_encoder.decode(coder)
init_internals
@@ -404,11 +404,9 @@ module ActiveRecord
# Post.new.encode_with(coder)
# coder # => {"attributes" => {"id" => nil, ... }}
def encode_with(coder)
- # FIXME: Remove this when we better serialize attributes
- coder['raw_attributes'] = attributes_before_type_cast
- coder['attributes'] = @attributes
+ self.class.yaml_encoder.encode(@attributes, coder)
coder['new_record'] = new_record?
- coder['active_record_yaml_version'] = 1
+ coder['active_record_yaml_version'] = 2
end
# Returns true if +comparison_object+ is the same exact object, or +comparison_object+
@@ -432,7 +430,7 @@ module ActiveRecord
# [ Person.find(1), Person.find(2), Person.find(3) ] & [ Person.find(1), Person.find(4) ] # => [ Person.find(1) ]
def hash
if id
- id.hash
+ [self.class, id].hash
else
super
end
diff --git a/activerecord/lib/active_record/legacy_yaml_adapter.rb b/activerecord/lib/active_record/legacy_yaml_adapter.rb
index 89dee58423..c7683f68c7 100644
--- a/activerecord/lib/active_record/legacy_yaml_adapter.rb
+++ b/activerecord/lib/active_record/legacy_yaml_adapter.rb
@@ -4,7 +4,7 @@ module ActiveRecord
return coder unless coder.is_a?(Psych::Coder)
case coder["active_record_yaml_version"]
- when 1 then coder
+ when 1, 2 then coder
else
if coder["attributes"].is_a?(AttributeSet)
Rails420.convert(klass, coder)
diff --git a/activerecord/lib/active_record/model_schema.rb b/activerecord/lib/active_record/model_schema.rb
index f691a8319d..7996c32bbc 100644
--- a/activerecord/lib/active_record/model_schema.rb
+++ b/activerecord/lib/active_record/model_schema.rb
@@ -267,6 +267,10 @@ module ActiveRecord
@attribute_types ||= Hash.new(Type::Value.new)
end
+ def yaml_encoder # :nodoc:
+ @yaml_encoder ||= AttributeSet::YAMLEncoder.new(attribute_types)
+ end
+
# Returns the type of the attribute with the given name, after applying
# all modifiers. This method is the only valid source of information for
# anything related to the types of a model's attributes. This method will
@@ -375,6 +379,7 @@ module ActiveRecord
@columns = nil
@columns_hash = nil
@attribute_names = nil
+ @yaml_encoder = nil
direct_descendants.each do |descendant|
descendant.send(:reload_schema_from_cache)
end
diff --git a/activerecord/test/cases/adapters/mysql2/charset_collation_test.rb b/activerecord/test/cases/adapters/mysql2/charset_collation_test.rb
index 668c07dacb..c8028b6b36 100644
--- a/activerecord/test/cases/adapters/mysql2/charset_collation_test.rb
+++ b/activerecord/test/cases/adapters/mysql2/charset_collation_test.rb
@@ -49,6 +49,6 @@ class Mysql2CharsetCollationTest < ActiveRecord::Mysql2TestCase
test "schema dump includes collation" do
output = dump_table_schema("charset_collations")
assert_match %r{t.string\s+"string_ascii_bin",\s+collation: "ascii_bin"$}, output
- assert_match %r{t.text\s+"text_ucs2_unicode_ci",\s+limit: 65535,\s+collation: "ucs2_unicode_ci"$}, output
+ assert_match %r{t.text\s+"text_ucs2_unicode_ci",\s+collation: "ucs2_unicode_ci"$}, output
end
end
diff --git a/activerecord/test/cases/aggregations_test.rb b/activerecord/test/cases/aggregations_test.rb
index 5536702f58..8a728902a8 100644
--- a/activerecord/test/cases/aggregations_test.rb
+++ b/activerecord/test/cases/aggregations_test.rb
@@ -138,6 +138,11 @@ class AggregationsTest < ActiveRecord::TestCase
assert_equal 'Barnoit GUMBLEAU', customers(:barney).fullname.to_s
assert_kind_of Fullname, customers(:barney).fullname
end
+
+ def test_assigning_hash_to_custom_converter
+ customers(:barney).fullname = { first: "Barney", last: "Stinson" }
+ assert_equal "Barney STINSON", customers(:barney).name
+ end
end
class OverridingAggregationsTest < ActiveRecord::TestCase
diff --git a/activerecord/test/cases/base_test.rb b/activerecord/test/cases/base_test.rb
index 3191393a41..80dcba1cf4 100644
--- a/activerecord/test/cases/base_test.rb
+++ b/activerecord/test/cases/base_test.rb
@@ -1504,6 +1504,10 @@ class BasicsTest < ActiveRecord::TestCase
assert_not_equal Post.new.hash, Post.new.hash
end
+ test "records of different classes have different hashes" do
+ assert_not_equal Post.new(id: 1).hash, Developer.new(id: 1).hash
+ end
+
test "resetting column information doesn't remove attribute methods" do
topic = topics(:first)
diff --git a/activerecord/test/cases/invertible_migration_test.rb b/activerecord/test/cases/invertible_migration_test.rb
index e030f6c588..aba854820b 100644
--- a/activerecord/test/cases/invertible_migration_test.rb
+++ b/activerecord/test/cases/invertible_migration_test.rb
@@ -151,6 +151,14 @@ module ActiveRecord
end
end
+ class RevertCustomForeignKeyTable < SilentMigration
+ def change
+ change_table(:horses) do |t|
+ t.references :owner, foreign_key: { to_table: :developers }
+ end
+ end
+ end
+
setup do
@verbose_was, ActiveRecord::Migration.verbose = ActiveRecord::Migration.verbose, false
end
@@ -353,6 +361,13 @@ module ActiveRecord
ActiveRecord::Base.table_name_prefix = ActiveRecord::Base.table_name_suffix = ''
end
+ def test_migrations_can_handle_foreign_keys_to_specific_tables
+ migration = RevertCustomForeignKeyTable.new
+ InvertibleMigration.migrate(:up)
+ migration.migrate(:up)
+ migration.migrate(:down)
+ end
+
# MySQL 5.7 and Oracle do not allow to create duplicate indexes on the same columns
unless current_adapter?(:Mysql2Adapter, :OracleAdapter)
def test_migrate_revert_add_index_with_name
diff --git a/activerecord/test/cases/schema_dumper_test.rb b/activerecord/test/cases/schema_dumper_test.rb
index 9dc1f5e2c2..12f4196724 100644
--- a/activerecord/test/cases/schema_dumper_test.rb
+++ b/activerecord/test/cases/schema_dumper_test.rb
@@ -218,12 +218,17 @@ class SchemaDumperTest < ActiveRecord::TestCase
assert_match %r{t\.boolean\s+"has_fun",.+default: false}, output
end
- if current_adapter?(:Mysql2Adapter)
- def test_schema_dump_should_add_default_value_for_mysql_text_field
- output = standard_dump
- assert_match %r{t\.text\s+"body",\s+limit: 65535,\s+null: false$}, output
- end
+ def test_schema_dump_does_not_include_limit_for_text_field
+ output = standard_dump
+ assert_match %r{t\.text\s+"params"$}, output
+ end
+ def test_schema_dump_does_not_include_limit_for_binary_field
+ output = standard_dump
+ assert_match %r{t\.binary\s+"data"$}, output
+ end
+
+ if current_adapter?(:Mysql2Adapter)
def test_schema_dump_includes_length_for_mysql_binary_fields
output = standard_dump
assert_match %r{t\.binary\s+"var_binary",\s+limit: 255$}, output
@@ -233,11 +238,11 @@ class SchemaDumperTest < ActiveRecord::TestCase
def test_schema_dump_includes_length_for_mysql_blob_and_text_fields
output = standard_dump
assert_match %r{t\.blob\s+"tiny_blob",\s+limit: 255$}, output
- assert_match %r{t\.binary\s+"normal_blob",\s+limit: 65535$}, output
+ assert_match %r{t\.binary\s+"normal_blob"$}, output
assert_match %r{t\.binary\s+"medium_blob",\s+limit: 16777215$}, output
assert_match %r{t\.binary\s+"long_blob",\s+limit: 4294967295$}, output
assert_match %r{t\.text\s+"tiny_text",\s+limit: 255$}, output
- assert_match %r{t\.text\s+"normal_text",\s+limit: 65535$}, output
+ assert_match %r{t\.text\s+"normal_text"$}, output
assert_match %r{t\.text\s+"medium_text",\s+limit: 16777215$}, output
assert_match %r{t\.text\s+"long_text",\s+limit: 4294967295$}, output
end
diff --git a/activerecord/test/cases/yaml_serialization_test.rb b/activerecord/test/cases/yaml_serialization_test.rb
index 56909a8630..d1c9a00786 100644
--- a/activerecord/test/cases/yaml_serialization_test.rb
+++ b/activerecord/test/cases/yaml_serialization_test.rb
@@ -109,6 +109,16 @@ class YamlSerializationTest < ActiveRecord::TestCase
assert_equal("Have a nice day", topic.content)
end
+ def test_yaml_encoding_keeps_mutations
+ author = Author.first
+ author.name = "Sean"
+ dumped = YAML.load(YAML.dump(author))
+
+ assert_equal "Sean", dumped.name
+ assert_equal author.name_was, dumped.name_was
+ assert_equal author.changes, dumped.changes
+ end
+
private
def yaml_fixture(file_name)
diff --git a/activerecord/test/models/customer.rb b/activerecord/test/models/customer.rb
index afe4b3d707..3338aaf7e1 100644
--- a/activerecord/test/models/customer.rb
+++ b/activerecord/test/models/customer.rb
@@ -64,7 +64,12 @@ class Fullname
def self.parse(str)
return nil unless str
- new(*str.to_s.split)
+
+ if str.is_a?(Hash)
+ new(str[:first], str[:last])
+ else
+ new(*str.to_s.split)
+ end
end
def initialize(first, last = nil)
diff --git a/railties/lib/rails/generators/app_base.rb b/railties/lib/rails/generators/app_base.rb
index 7aee28c74a..f0a3289563 100644
--- a/railties/lib/rails/generators/app_base.rb
+++ b/railties/lib/rails/generators/app_base.rb
@@ -308,7 +308,7 @@ module Rails
def jbuilder_gemfile_entry
comment = 'Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder'
- GemfileEntry.new 'jbuilder', '~> 2.0', comment, {}, options[:api]
+ GemfileEntry.new 'jbuilder', '~> 2.5', comment, {}, options[:api]
end
def coffee_gemfile_entry
diff --git a/railties/lib/rails/generators/rails/app/app_generator.rb b/railties/lib/rails/generators/rails/app/app_generator.rb
index 3bc66f55fb..c288b3dfce 100644
--- a/railties/lib/rails/generators/rails/app/app_generator.rb
+++ b/railties/lib/rails/generators/rails/app/app_generator.rb
@@ -90,41 +90,26 @@ module Rails
def config_when_updating
cookie_serializer_config_exist = File.exist?('config/initializers/cookies_serializer.rb')
- callback_terminator_config_exist = File.exist?('config/initializers/new_framework_defaults/callback_terminator.rb')
- active_record_belongs_to_required_by_default_config_exist = File.exist?('config/initializers/new_framework_defaults/active_record_belongs_to_required_by_default.rb')
- to_time_preserves_timezone_config_exist = File.exist?('config/initializers/new_framework_defaults/to_time_preserves_timezone.rb')
+ new_framework_defaults_config_exist = File.exist?('config/initializers/new_framework_defaults.rb')
action_cable_config_exist = File.exist?('config/cable.yml')
- ssl_options_exist = File.exist?('config/initializers/new_framework_defaults/ssl_options.rb')
rack_cors_config_exist = File.exist?('config/initializers/cors.rb')
config
gsub_file 'config/environments/development.rb', /^(\s+)config\.file_watcher/, '\1# config.file_watcher'
- unless callback_terminator_config_exist
- remove_file 'config/initializers/new_framework_defaults/callback_terminator.rb'
- end
-
unless cookie_serializer_config_exist
gsub_file 'config/initializers/cookies_serializer.rb', /json(?!,)/, 'marshal'
end
- unless active_record_belongs_to_required_by_default_config_exist
- remove_file 'config/initializers/new_framework_defaults/active_record_belongs_to_required_by_default.rb'
- end
-
- unless to_time_preserves_timezone_config_exist
- remove_file 'config/initializers/new_framework_defaults/to_time_preserves_timezone.rb'
+ unless new_framework_defaults_config_exist
+ remove_file 'config/initializers/new_framework_defaults.rb'
end
unless action_cable_config_exist
template 'config/cable.yml'
end
- unless ssl_options_exist
- remove_file 'config/initializers/new_framework_defaults/ssl_options.rb'
- end
-
unless rack_cors_config_exist
remove_file 'config/initializers/cors.rb'
end
@@ -342,12 +327,6 @@ module Rails
end
end
- def delete_active_record_initializers_skipping_active_record
- if options[:skip_active_record]
- remove_file 'config/initializers/new_framework_defaults/active_record_belongs_to_required_by_default.rb'
- end
- end
-
def delete_action_cable_files_skipping_action_cable
if options[:skip_action_cable]
remove_file 'config/cable.yml'
@@ -360,8 +339,6 @@ module Rails
if options[:api]
remove_file 'config/initializers/session_store.rb'
remove_file 'config/initializers/cookies_serializer.rb'
- remove_file 'config/initializers/new_framework_defaults/request_forgery_protection.rb'
- remove_file 'config/initializers/new_framework_defaults/per_form_csrf_tokens.rb'
end
end
diff --git a/railties/lib/rails/generators/rails/app/templates/config/initializers/new_framework_defaults.rb.tt b/railties/lib/rails/generators/rails/app/templates/config/initializers/new_framework_defaults.rb.tt
new file mode 100644
index 0000000000..730938a1ba
--- /dev/null
+++ b/railties/lib/rails/generators/rails/app/templates/config/initializers/new_framework_defaults.rb.tt
@@ -0,0 +1,37 @@
+# Be sure to restart your server when you modify this file.
+# This file contains all the new default configuration options from
+# Rails 5.0.
+<%- unless options[:skip_active_record] -%>
+
+# Require `belongs_to` associations by default. This is a new Rails 5.0
+# default, so it is introduced as a configuration option to ensure that apps
+# made on earlier versions of Rails are not affected when upgrading.
+Rails.application.config.active_record.belongs_to_required_by_default = true
+<%- end -%>
+
+# Do not halt callback chains when a callback returns false. This is a new
+# Rails 5.0 default, so it is introduced as a configuration option to ensure
+# that apps made with earlier versions of Rails are not affected when upgrading.
+ActiveSupport.halt_callback_chains_on_return_false = false
+<%- unless options[:api] -%>
+
+# Enable per-form CSRF tokens.
+Rails.application.config.action_controller.per_form_csrf_tokens = true
+
+# Enable origin-checking CSRF mitigation.
+Rails.application.config.action_controller.forgery_protection_origin_check = true
+<%- end -%>
+
+# Configure SSL options to enable HSTS with subdomains. This is a new
+# Rails 5.0 default, so it is introduced as a configuration option to ensure
+# that apps made on earlier versions of Rails are not affected when upgrading.
+Rails.application.config.ssl_options = { hsts: { subdomains: true } }
+
+# Preserve the timezone of the receiver when calling to `to_time`.
+# Ruby 2.4 will change the behavior of `to_time` to preserve the timezone
+# when converting to an instance of `Time` instead of the previous behavior
+# of converting to the local system timezone.
+#
+# Rails 5.0 introduced this config option so that apps made with earlier
+# versions of Rails are not affected when upgrading.
+ActiveSupport.to_time_preserves_timezone = true
diff --git a/railties/lib/rails/generators/rails/app/templates/config/initializers/new_framework_defaults/active_record_belongs_to_required_by_default.rb b/railties/lib/rails/generators/rails/app/templates/config/initializers/new_framework_defaults/active_record_belongs_to_required_by_default.rb
deleted file mode 100644
index f613b40f80..0000000000
--- a/railties/lib/rails/generators/rails/app/templates/config/initializers/new_framework_defaults/active_record_belongs_to_required_by_default.rb
+++ /dev/null
@@ -1,6 +0,0 @@
-# Be sure to restart your server when you modify this file.
-
-# Require `belongs_to` associations by default. This is a new Rails 5.0
-# default, so it is introduced as a configuration option to ensure that apps
-# made on earlier versions of Rails are not affected when upgrading.
-Rails.application.config.active_record.belongs_to_required_by_default = true
diff --git a/railties/lib/rails/generators/rails/app/templates/config/initializers/new_framework_defaults/callback_terminator.rb b/railties/lib/rails/generators/rails/app/templates/config/initializers/new_framework_defaults/callback_terminator.rb
deleted file mode 100644
index 649e82280e..0000000000
--- a/railties/lib/rails/generators/rails/app/templates/config/initializers/new_framework_defaults/callback_terminator.rb
+++ /dev/null
@@ -1,6 +0,0 @@
-# Be sure to restart your server when you modify this file.
-
-# Do not halt callback chains when a callback returns false. This is a new
-# Rails 5.0 default, so it is introduced as a configuration option to ensure
-# that apps made with earlier versions of Rails are not affected when upgrading.
-ActiveSupport.halt_callback_chains_on_return_false = false
diff --git a/railties/lib/rails/generators/rails/app/templates/config/initializers/new_framework_defaults/per_form_csrf_tokens.rb b/railties/lib/rails/generators/rails/app/templates/config/initializers/new_framework_defaults/per_form_csrf_tokens.rb
deleted file mode 100644
index 1f569dedfd..0000000000
--- a/railties/lib/rails/generators/rails/app/templates/config/initializers/new_framework_defaults/per_form_csrf_tokens.rb
+++ /dev/null
@@ -1,4 +0,0 @@
-# Be sure to restart your server when you modify this file.
-
-# Enable per-form CSRF tokens.
-Rails.application.config.action_controller.per_form_csrf_tokens = true
diff --git a/railties/lib/rails/generators/rails/app/templates/config/initializers/new_framework_defaults/request_forgery_protection.rb b/railties/lib/rails/generators/rails/app/templates/config/initializers/new_framework_defaults/request_forgery_protection.rb
deleted file mode 100644
index 3eab78a885..0000000000
--- a/railties/lib/rails/generators/rails/app/templates/config/initializers/new_framework_defaults/request_forgery_protection.rb
+++ /dev/null
@@ -1,4 +0,0 @@
-# Be sure to restart your server when you modify this file.
-
-# Enable origin-checking CSRF mitigation.
-Rails.application.config.action_controller.forgery_protection_origin_check = true
diff --git a/railties/lib/rails/generators/rails/app/templates/config/initializers/new_framework_defaults/ssl_options.rb b/railties/lib/rails/generators/rails/app/templates/config/initializers/new_framework_defaults/ssl_options.rb
deleted file mode 100644
index 53dfcd7466..0000000000
--- a/railties/lib/rails/generators/rails/app/templates/config/initializers/new_framework_defaults/ssl_options.rb
+++ /dev/null
@@ -1,6 +0,0 @@
-# Be sure to restart your server when you modify this file.
-
-# Configure SSL options to enable HSTS with subdomains. This is a new
-# Rails 5.0 default, so it is introduced as a configuration option to ensure
-# that apps made on earlier versions of Rails are not affected when upgrading.
-Rails.application.config.ssl_options = { hsts: { subdomains: true } }
diff --git a/railties/lib/rails/generators/rails/app/templates/config/initializers/new_framework_defaults/to_time_preserves_timezone.rb b/railties/lib/rails/generators/rails/app/templates/config/initializers/new_framework_defaults/to_time_preserves_timezone.rb
deleted file mode 100644
index 8674be3227..0000000000
--- a/railties/lib/rails/generators/rails/app/templates/config/initializers/new_framework_defaults/to_time_preserves_timezone.rb
+++ /dev/null
@@ -1,10 +0,0 @@
-# Be sure to restart your server when you modify this file.
-
-# Preserve the timezone of the receiver when calling to `to_time`.
-# Ruby 2.4 will change the behavior of `to_time` to preserve the timezone
-# when converting to an instance of `Time` instead of the previous behavior
-# of converting to the local system timezone.
-#
-# Rails 5.0 introduced this config option so that apps made with earlier
-# versions of Rails are not affected when upgrading.
-ActiveSupport.to_time_preserves_timezone = true
diff --git a/railties/test/generators/api_app_generator_test.rb b/railties/test/generators/api_app_generator_test.rb
index 505c1be9fc..92779452e1 100644
--- a/railties/test/generators/api_app_generator_test.rb
+++ b/railties/test/generators/api_app_generator_test.rb
@@ -62,6 +62,15 @@ class ApiAppGeneratorTest < Rails::Generators::TestCase
end
end
+ def test_generator_skips_per_form_csrf_token_and_origin_check_configs_for_api_apps
+ run_generator
+
+ assert_file "config/initializers/new_framework_defaults.rb" do |initializer_content|
+ assert_no_match(/per_form_csrf_tokens/, initializer_content)
+ assert_no_match(/forgery_protection_origin_check/, initializer_content)
+ end
+ end
+
private
def default_files
@@ -100,8 +109,6 @@ class ApiAppGeneratorTest < Rails::Generators::TestCase
config/initializers/assets.rb
config/initializers/cookies_serializer.rb
config/initializers/session_store.rb
- config/initializers/new_framework_defaults/request_forgery_protection.rb
- config/initializers/new_framework_defaults/per_form_csrf_tokens.rb
lib/assets
vendor/assets
test/helpers
diff --git a/railties/test/generators/app_generator_test.rb b/railties/test/generators/app_generator_test.rb
index cb656cc94c..bea8db087f 100644
--- a/railties/test/generators/app_generator_test.rb
+++ b/railties/test/generators/app_generator_test.rb
@@ -172,34 +172,6 @@ class AppGeneratorTest < Rails::Generators::TestCase
end
end
- def test_rails_update_does_not_create_callback_terminator_initializer
- app_root = File.join(destination_root, 'myapp')
- run_generator [app_root]
-
- FileUtils.rm("#{app_root}/config/initializers/new_framework_defaults/callback_terminator.rb")
-
- 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_no_file "#{app_root}/config/initializers/new_framework_defaults/callback_terminator.rb"
- end
- end
-
- def test_rails_update_does_not_remove_callback_terminator_initializer_if_already_present
- app_root = File.join(destination_root, 'myapp')
- run_generator [app_root]
-
- FileUtils.touch("#{app_root}/config/initializers/new_framework_defaults/callback_terminator.rb")
-
- 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/initializers/new_framework_defaults/callback_terminator.rb"
- end
- end
-
def test_rails_update_set_the_cookie_serializer_to_marshal_if_it_is_not_already_configured
app_root = File.join(destination_root, 'myapp')
run_generator [app_root]
@@ -229,87 +201,31 @@ class AppGeneratorTest < Rails::Generators::TestCase
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]
-
- FileUtils.rm("#{app_root}/config/initializers/new_framework_defaults/active_record_belongs_to_required_by_default.rb")
-
- 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_no_file "#{app_root}/config/initializers/new_framework_defaults/active_record_belongs_to_required_by_default.rb"
- end
- end
-
- def test_rails_update_does_not_remove_active_record_belongs_to_required_by_default_if_already_present
- app_root = File.join(destination_root, 'myapp')
- run_generator [app_root]
-
- FileUtils.touch("#{app_root}/config/initializers/new_framework_defaults/active_record_belongs_to_required_by_default.rb")
-
- 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/initializers/new_framework_defaults/active_record_belongs_to_required_by_default.rb"
- end
- end
-
- def test_rails_update_does_not_create_to_time_preserves_timezone
- app_root = File.join(destination_root, 'myapp')
- run_generator [app_root]
-
- FileUtils.rm("#{app_root}/config/initializers/new_framework_defaults/to_time_preserves_timezone.rb")
-
- 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_no_file "#{app_root}/config/initializers/new_framework_defaults/to_time_preserves_timezone.rb"
- end
- end
-
- def test_rails_update_does_not_remove_to_time_preserves_timezone_if_already_present
+ def test_rails_update_does_not_create_new_framework_defaults_by_default
app_root = File.join(destination_root, 'myapp')
run_generator [app_root]
- FileUtils.touch("#{app_root}/config/initializers/new_framework_defaults/to_time_preserves_timezone.rb")
+ FileUtils.rm("#{app_root}/config/initializers/new_framework_defaults.rb")
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/initializers/new_framework_defaults/to_time_preserves_timezone.rb"
+ assert_no_file "#{app_root}/config/initializers/new_framework_defaults.rb"
end
end
- def test_rails_update_does_not_create_ssl_options_by_default
+ def test_rails_update_does_not_new_framework_defaults_if_already_present
app_root = File.join(destination_root, 'myapp')
run_generator [app_root]
- FileUtils.rm("#{app_root}/config/initializers/new_framework_defaults/ssl_options.rb")
+ FileUtils.touch("#{app_root}/config/initializers/new_framework_defaults.rb")
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_no_file "#{app_root}/config/initializers/new_framework_defaults/ssl_options.rb"
- end
- end
-
- def test_rails_update_does_not_remove_ssl_options_if_already_present
- app_root = File.join(destination_root, 'myapp')
- run_generator [app_root]
-
- FileUtils.touch("#{app_root}/config/initializers/new_framework_defaults/ssl_options.rb")
-
- 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/initializers/new_framework_defaults/ssl_options.rb"
+ assert_file "#{app_root}/config/initializers/new_framework_defaults.rb"
end
end
@@ -452,12 +368,15 @@ class AppGeneratorTest < Rails::Generators::TestCase
def test_generator_if_skip_active_record_is_given
run_generator [destination_root, "--skip-active-record"]
assert_no_file "config/database.yml"
- assert_no_file "config/initializers/new_framework_defaults/active_record_belongs_to_required_by_default.rb"
assert_no_file "app/models/application_record.rb"
assert_file "config/application.rb", /#\s+require\s+["']active_record\/railtie["']/
assert_file "test/test_helper.rb" do |helper_content|
assert_no_match(/fixtures :all/, helper_content)
end
+
+ assert_file "config/initializers/new_framework_defaults.rb" do |initializer_content|
+ assert_no_match(/belongs_to_required_by_default/, initializer_content)
+ end
end
def test_generator_if_skip_action_mailer_is_given