diff options
52 files changed, 375 insertions, 316 deletions
@@ -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 |