aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Gemfile.lock2
-rw-r--r--actionpack/lib/action_controller/test_case.rb1
-rw-r--r--actionview/lib/action_view/helpers/form_helper.rb35
-rw-r--r--actionview/lib/action_view/helpers/form_tag_helper.rb2
-rw-r--r--actionview/lib/action_view/helpers/tags/base.rb14
-rw-r--r--actionview/lib/action_view/helpers/tags/label.rb4
-rw-r--r--actionview/test/template/form_helper/form_with_test.rb410
-rw-r--r--activemodel/test/cases/errors_test.rb1
-rw-r--r--activerecord/CHANGELOG.md25
-rw-r--r--activerecord/lib/active_record/associations/singular_association.rb2
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb4
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract_adapter.rb7
-rw-r--r--activerecord/lib/active_record/connection_adapters/column.rb22
-rw-r--r--activerecord/lib/active_record/connection_adapters/schema_cache.rb16
-rw-r--r--activerecord/lib/active_record/railtie.rb6
-rw-r--r--activerecord/lib/active_record/railties/databases.rake16
-rw-r--r--activerecord/test/assets/schema_dump_5_1.yml345
-rw-r--r--activerecord/test/cases/adapter_test.rb4
-rw-r--r--activerecord/test/cases/adapters/mysql2/reserved_word_test.rb2
-rw-r--r--activerecord/test/cases/associations/belongs_to_associations_test.rb2
-rw-r--r--activerecord/test/cases/connection_adapters/schema_cache_test.rb43
-rw-r--r--activerecord/test/cases/finder_test.rb1
-rw-r--r--activerecord/test/cases/query_cache_test.rb14
-rw-r--r--activesupport/CHANGELOG.md6
-rw-r--r--activesupport/lib/active_support/callbacks.rb12
-rw-r--r--activesupport/lib/active_support/core_ext/object/duplicable.rb91
-rw-r--r--activesupport/lib/active_support/inflector/methods.rb2
-rw-r--r--activesupport/lib/active_support/xml_mini.rb12
-rw-r--r--activesupport/test/autoloading_fixtures/prepend.rb8
-rw-r--r--activesupport/test/autoloading_fixtures/prepend/sub_class_conflict.rb2
-rw-r--r--activesupport/test/caching_test.rb2
-rw-r--r--activesupport/test/callbacks_test.rb83
-rw-r--r--activesupport/test/constantize_test_cases.rb5
-rw-r--r--activesupport/test/core_ext/object/duplicable_test.rb10
-rw-r--r--guides/source/development_dependencies_install.md4
-rw-r--r--guides/source/security.md2
-rw-r--r--railties/CHANGELOG.md12
-rw-r--r--railties/lib/rails/commands/plugin/plugin_command.rb2
-rw-r--r--railties/lib/rails/generators/app_base.rb7
-rw-r--r--railties/lib/rails/generators/named_base.rb4
-rw-r--r--railties/lib/rails/generators/rails/controller/controller_generator.rb6
-rw-r--r--railties/test/application/rake_test.rb4
42 files changed, 946 insertions, 306 deletions
diff --git a/Gemfile.lock b/Gemfile.lock
index eb14330c2b..0763efc001 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -162,7 +162,7 @@ GEM
coffee-script (2.4.1)
coffee-script-source
execjs
- coffee-script-source (1.10.0)
+ coffee-script-source (1.12.2)
concurrent-ruby (1.0.2)
connection_pool (2.2.0)
cookiejar (0.3.3)
diff --git a/actionpack/lib/action_controller/test_case.rb b/actionpack/lib/action_controller/test_case.rb
index 85f2501d42..c639178776 100644
--- a/actionpack/lib/action_controller/test_case.rb
+++ b/actionpack/lib/action_controller/test_case.rb
@@ -3,6 +3,7 @@ require "active_support/core_ext/hash/conversions"
require "active_support/core_ext/object/to_query"
require "active_support/core_ext/module/anonymous"
require "active_support/core_ext/hash/keys"
+require "active_support/testing/constant_lookup"
require "action_controller/template_assertions"
require "rails-dom-testing"
diff --git a/actionview/lib/action_view/helpers/form_helper.rb b/actionview/lib/action_view/helpers/form_helper.rb
index e7ea267211..6c632b8e75 100644
--- a/actionview/lib/action_view/helpers/form_helper.rb
+++ b/actionview/lib/action_view/helpers/form_helper.rb
@@ -595,6 +595,16 @@ module ActionView
#
# Where <tt>@document = Document.find(params[:id])</tt>.
#
+ # When using labels +form_with+ requires setting the id on the field being
+ # labelled:
+ #
+ # <%= form_with(model: @post) do |form| %>
+ # <%= form.label :title %>
+ # <%= form.text_field :title, id: :post_title %>
+ # <% end %>
+ #
+ # See +label+ for more on how the +for+ attribute is derived.
+ #
# === Mixing with other form helpers
#
# While +form_with+ uses a FormBuilder object it's possible to mix and
@@ -690,6 +700,8 @@ module ActionView
# form_with(**options.merge(builder: LabellingFormBuilder), &block)
# end
def form_with(model: nil, scope: nil, url: nil, format: nil, **options)
+ options[:skip_default_ids] = true
+
if model
url ||= polymorphic_path(model, format: format)
@@ -986,6 +998,16 @@ module ActionView
# or model is yielded, so any generated field names are prefixed with
# either the passed scope or the scope inferred from the <tt>:model</tt>.
#
+ # When using labels +fields+ requires setting the id on the field being
+ # labelled:
+ #
+ # <%= fields :comment do |fields| %>
+ # <%= fields.label :body %>
+ # <%= fields.text_field :body, id: :comment_body %>
+ # <% end %>
+ #
+ # See +label+ for more on how the +for+ attribute is derived.
+ #
# === Mixing with other form helpers
#
# While +form_with+ uses a FormBuilder object it's possible to mix and
@@ -1003,7 +1025,8 @@ module ActionView
# to work with an object as a base, like
# FormOptionHelper#collection_select and DateHelper#datetime_select.
def fields(scope = nil, model: nil, **options, &block)
- # TODO: Remove when ids and classes are no longer output by default.
+ options[:skip_default_ids] = true
+
if model
scope ||= model_name_from_record_or_class(model).param_key
end
@@ -1469,7 +1492,7 @@ module ActionView
private
def html_options_for_form_with(url_for_options = nil, model = nil, html: {}, local: false,
skip_enforcing_utf8: false, **options)
- html_options = options.except(:index, :include_id, :builder).merge(html)
+ html_options = options.except(:index, :include_id, :skip_default_ids, :builder).merge(html)
html_options[:method] ||= :patch if model.respond_to?(:persisted?) && model.persisted?
html_options[:enforce_utf8] = !skip_enforcing_utf8
@@ -1603,7 +1626,7 @@ module ActionView
def initialize(object_name, object, template, options)
@nested_child_index = {}
@object_name, @object, @template, @options = object_name, object, template, options
- @default_options = @options ? @options.slice(:index, :namespace) : {}
+ @default_options = @options ? @options.slice(:index, :namespace, :skip_default_ids) : {}
convert_to_legacy_options(@options)
@@ -1910,6 +1933,8 @@ module ActionView
# See the docs for the <tt>ActionView::FormHelper.fields</tt> helper method.
def fields(scope = nil, model: nil, **options, &block)
+ options[:skip_default_ids] = true
+
convert_to_legacy_options(options)
fields_for(scope || model, model, **options, &block)
@@ -2268,10 +2293,6 @@ module ActionView
if options.key?(:skip_id)
options[:include_id] = !options.delete(:skip_id)
end
-
- if options.key?(:local)
- options[:remote] = !options.delete(:local)
- end
end
end
end
diff --git a/actionview/lib/action_view/helpers/form_tag_helper.rb b/actionview/lib/action_view/helpers/form_tag_helper.rb
index 7bd473507b..ffc52569f2 100644
--- a/actionview/lib/action_view/helpers/form_tag_helper.rb
+++ b/actionview/lib/action_view/helpers/form_tag_helper.rb
@@ -461,7 +461,7 @@ module ActionView
end
# Creates a button element that defines a <tt>submit</tt> button,
- # <tt>reset</tt>button or a generic button which can be used in
+ # <tt>reset</tt> button or a generic button which can be used in
# JavaScript, for example. You can use the button tag as a regular
# submit tag but it isn't supported in legacy browsers. However,
# the button tag does allow for richer labels such as images and emphasis,
diff --git a/actionview/lib/action_view/helpers/tags/base.rb b/actionview/lib/action_view/helpers/tags/base.rb
index cf8a6d6028..b8c446cbed 100644
--- a/actionview/lib/action_view/helpers/tags/base.rb
+++ b/actionview/lib/action_view/helpers/tags/base.rb
@@ -13,6 +13,7 @@ module ActionView
@object_name.sub!(/\[\]$/, "") || @object_name.sub!(/\[\]\]$/, "]")
@object = retrieve_object(options.delete(:object))
+ @skip_default_ids = options.delete(:skip_default_ids)
@options = options
@auto_index = Regexp.last_match ? retrieve_autoindex(Regexp.last_match.pre_match) : nil
end
@@ -81,9 +82,12 @@ module ActionView
def add_default_name_and_id(options)
index = name_and_id_index(options)
options["name"] = options.fetch("name") { tag_name(options["multiple"], index) }
- options["id"] = options.fetch("id") { tag_id(index) }
- if namespace = options.delete("namespace")
- options["id"] = options["id"] ? "#{namespace}_#{options['id']}" : namespace
+
+ unless skip_default_ids?
+ options["id"] = options.fetch("id") { tag_id(index) }
+ if namespace = options.delete("namespace")
+ options["id"] = options["id"] ? "#{namespace}_#{options['id']}" : namespace
+ end
end
end
@@ -154,6 +158,10 @@ module ActionView
def name_and_id_index(options)
options.key?("index") ? options.delete("index") || "" : @auto_index
end
+
+ def skip_default_ids?
+ @skip_default_ids
+ end
end
end
end
diff --git a/actionview/lib/action_view/helpers/tags/label.rb b/actionview/lib/action_view/helpers/tags/label.rb
index b31d5fda66..cab15ae201 100644
--- a/actionview/lib/action_view/helpers/tags/label.rb
+++ b/actionview/lib/action_view/helpers/tags/label.rb
@@ -73,6 +73,10 @@ module ActionView
def render_component(builder)
builder.translation
end
+
+ def skip_default_ids?
+ false # The id is used as the `for` attribute.
+ end
end
end
end
diff --git a/actionview/test/template/form_helper/form_with_test.rb b/actionview/test/template/form_helper/form_with_test.rb
index c80a2f61b9..c078b47e14 100644
--- a/actionview/test/template/form_helper/form_with_test.rb
+++ b/actionview/test/template/form_helper/form_with_test.rb
@@ -116,6 +116,16 @@ class FormWithActsLikeFormTagTest < FormWithTest
assert_dom_equal expected, output_buffer
end
+
+ def test_form_with_with_block_in_erb_and_local_true
+ output_buffer = render_erb("<%= form_with(url: 'http://www.example.com', local: true) do %>Hello world!<% end %>")
+
+ expected = whole_form("http://www.example.com", local: true) do
+ "Hello world!"
+ end
+
+ assert_dom_equal expected, output_buffer
+ end
end
class FormWithActsLikeFormForTest < FormWithTest
@@ -301,10 +311,10 @@ class FormWithActsLikeFormForTest < FormWithTest
expected = whole_form("/posts/123", "create-post", method: "patch") do
"<label for='post_title'>The Title</label>" +
- "<input name='post[title]' type='text' id='post_title' value='Hello World' />" +
- "<textarea name='post[body]' id='post_body'>\nBack to the hill and over it again!</textarea>" +
+ "<input name='post[title]' type='text' value='Hello World' />" +
+ "<textarea name='post[body]'>\nBack to the hill and over it again!</textarea>" +
"<input name='post[secret]' type='hidden' value='0' />" +
- "<input name='post[secret]' checked='checked' type='checkbox' id='post_secret' value='1' />" +
+ "<input name='post[secret]' checked='checked' type='checkbox' value='1' />" +
"<input name='commit' data-disable-with='Create post' type='submit' value='Create post' />" +
"<button name='button' type='submit'>Create post</button>" +
"<button name='button' type='submit'><span>Create post</span></button>"
@@ -322,9 +332,9 @@ class FormWithActsLikeFormForTest < FormWithTest
expected = whole_form("/posts") do
"<input type='hidden' name='post[active]' value='' />" +
- "<input id='post_active_true' name='post[active]' type='radio' value='true' />" +
+ "<input name='post[active]' type='radio' value='true' />" +
"<label for='post_active_true'>true</label>" +
- "<input checked='checked' id='post_active_false' name='post[active]' type='radio' value='false' />" +
+ "<input checked='checked' name='post[active]' type='radio' value='false' />" +
"<label for='post_active_false'>false</label>"
end
@@ -345,10 +355,10 @@ class FormWithActsLikeFormForTest < FormWithTest
expected = whole_form("/posts") do
"<input type='hidden' name='post[active]' value='' />" +
"<label for='post_active_true'>" +
- "<input id='post_active_true' name='post[active]' type='radio' value='true' />" +
+ "<input name='post[active]' type='radio' value='true' />" +
"true</label>" +
"<label for='post_active_false'>" +
- "<input checked='checked' id='post_active_false' name='post[active]' type='radio' value='false' />" +
+ "<input checked='checked' name='post[active]' type='radio' value='false' />" +
"false</label>"
end
@@ -371,12 +381,12 @@ class FormWithActsLikeFormForTest < FormWithTest
expected = whole_form("/posts") do
"<input type='hidden' name='post[active]' value='' />" +
"<label for='post_active_true'>" +
- "<input id='post_active_true' name='post[active]' type='radio' value='true' />" +
+ "<input name='post[active]' type='radio' value='true' />" +
"true</label>" +
"<label for='post_active_false'>" +
- "<input checked='checked' id='post_active_false' name='post[active]' type='radio' value='false' />" +
+ "<input checked='checked' name='post[active]' type='radio' value='false' />" +
"false</label>" +
- "<input id='post_id' name='post[id]' type='hidden' value='1' />"
+ "<input name='post[id]' type='hidden' value='1' />"
end
assert_dom_equal expected, output_buffer
@@ -392,9 +402,9 @@ class FormWithActsLikeFormForTest < FormWithTest
expected = whole_form("/posts") do
"<input type='hidden' name='post[1][active]' value='' />" +
- "<input id='post_1_active_true' name='post[1][active]' type='radio' value='true' />" +
+ "<input name='post[1][active]' type='radio' value='true' />" +
"<label for='post_1_active_true'>true</label>" +
- "<input checked='checked' id='post_1_active_false' name='post[1][active]' type='radio' value='false' />" +
+ "<input checked='checked' name='post[1][active]' type='radio' value='false' />" +
"<label for='post_1_active_false'>false</label>"
end
@@ -411,11 +421,11 @@ class FormWithActsLikeFormForTest < FormWithTest
expected = whole_form("/posts") do
"<input name='post[tag_ids][]' type='hidden' value='' />" +
- "<input checked='checked' id='post_tag_ids_1' name='post[tag_ids][]' type='checkbox' value='1' />" +
+ "<input checked='checked' name='post[tag_ids][]' type='checkbox' value='1' />" +
"<label for='post_tag_ids_1'>Tag 1</label>" +
- "<input id='post_tag_ids_2' name='post[tag_ids][]' type='checkbox' value='2' />" +
+ "<input name='post[tag_ids][]' type='checkbox' value='2' />" +
"<label for='post_tag_ids_2'>Tag 2</label>" +
- "<input checked='checked' id='post_tag_ids_3' name='post[tag_ids][]' type='checkbox' value='3' />" +
+ "<input checked='checked' name='post[tag_ids][]' type='checkbox' value='3' />" +
"<label for='post_tag_ids_3'>Tag 3</label>"
end
@@ -436,13 +446,13 @@ class FormWithActsLikeFormForTest < FormWithTest
expected = whole_form("/posts") do
"<input name='post[tag_ids][]' type='hidden' value='' />" +
"<label for='post_tag_ids_1'>" +
- "<input checked='checked' id='post_tag_ids_1' name='post[tag_ids][]' type='checkbox' value='1' />" +
+ "<input checked='checked' name='post[tag_ids][]' type='checkbox' value='1' />" +
"Tag 1</label>" +
"<label for='post_tag_ids_2'>" +
- "<input id='post_tag_ids_2' name='post[tag_ids][]' type='checkbox' value='2' />" +
+ "<input name='post[tag_ids][]' type='checkbox' value='2' />" +
"Tag 2</label>" +
"<label for='post_tag_ids_3'>" +
- "<input checked='checked' id='post_tag_ids_3' name='post[tag_ids][]' type='checkbox' value='3' />" +
+ "<input checked='checked' name='post[tag_ids][]' type='checkbox' value='3' />" +
"Tag 3</label>"
end
@@ -466,15 +476,15 @@ class FormWithActsLikeFormForTest < FormWithTest
expected = whole_form("/posts") do
"<input name='post[tag_ids][]' type='hidden' value='' />" +
"<label for='post_tag_ids_1'>" +
- "<input checked='checked' id='post_tag_ids_1' name='post[tag_ids][]' type='checkbox' value='1' />" +
+ "<input checked='checked' name='post[tag_ids][]' type='checkbox' value='1' />" +
"Tag 1</label>" +
"<label for='post_tag_ids_2'>" +
- "<input id='post_tag_ids_2' name='post[tag_ids][]' type='checkbox' value='2' />" +
+ "<input name='post[tag_ids][]' type='checkbox' value='2' />" +
"Tag 2</label>" +
"<label for='post_tag_ids_3'>" +
- "<input checked='checked' id='post_tag_ids_3' name='post[tag_ids][]' type='checkbox' value='3' />" +
+ "<input checked='checked' name='post[tag_ids][]' type='checkbox' value='3' />" +
"Tag 3</label>" +
- "<input id='post_id' name='post[id]' type='hidden' value='1' />"
+ "<input name='post[id]' type='hidden' value='1' />"
end
assert_dom_equal expected, output_buffer
@@ -491,7 +501,7 @@ class FormWithActsLikeFormForTest < FormWithTest
expected = whole_form("/posts") do
"<input name='post[1][tag_ids][]' type='hidden' value='' />" +
- "<input checked='checked' id='post_1_tag_ids_1' name='post[1][tag_ids][]' type='checkbox' value='1' />" +
+ "<input checked='checked' name='post[1][tag_ids][]' type='checkbox' value='1' />" +
"<label for='post_1_tag_ids_1'>Tag 1</label>"
end
@@ -506,7 +516,7 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/posts/123", "create-post", method: "patch", multipart: true) do
- "<input name='post[file]' type='file' id='post_file' />"
+ "<input name='post[file]' type='file' />"
end
assert_dom_equal expected, output_buffer
@@ -522,7 +532,7 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/posts/123", method: "patch", multipart: true) do
- "<input name='post[comment][file]' type='file' id='post_comment_file' />"
+ "<input name='post[comment][file]' type='file' />"
end
assert_dom_equal expected, output_buffer
@@ -561,7 +571,7 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/posts/44", method: "patch") do
- "<input name='post[title]' type='text' id='post_title' value='And his name will be forty and four.' />" +
+ "<input name='post[title]' type='text' value='And his name will be forty and four.' />" +
"<input name='commit' data-disable-with='Edit post' type='submit' value='Edit post' />"
end
@@ -579,10 +589,10 @@ class FormWithActsLikeFormForTest < FormWithTest
expected = whole_form("/posts/123", "create-post", method: "patch") do
"<label for='other_name_title' class='post_title'>Title</label>" +
- "<input name='other_name[title]' id='other_name_title' value='Hello World' type='text' />" +
- "<textarea name='other_name[body]' id='other_name_body'>\nBack to the hill and over it again!</textarea>" +
+ "<input name='other_name[title]' value='Hello World' type='text' />" +
+ "<textarea name='other_name[body]'>\nBack to the hill and over it again!</textarea>" +
"<input name='other_name[secret]' value='0' type='hidden' />" +
- "<input name='other_name[secret]' checked='checked' id='other_name_secret' value='1' type='checkbox' />" +
+ "<input name='other_name[secret]' checked='checked' value='1' type='checkbox' />" +
"<input name='commit' value='Create post' data-disable-with='Create post' type='submit' />"
end
@@ -609,10 +619,10 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/", "create-post", method: "delete") do
- "<input name='post[title]' type='text' id='post_title' value='Hello World' />" +
- "<textarea name='post[body]' id='post_body'>\nBack to the hill and over it again!</textarea>" +
+ "<input name='post[title]' type='text' value='Hello World' />" +
+ "<textarea name='post[body]'>\nBack to the hill and over it again!</textarea>" +
"<input name='post[secret]' type='hidden' value='0' />" +
- "<input name='post[secret]' checked='checked' type='checkbox' id='post_secret' value='1' />"
+ "<input name='post[secret]' checked='checked' type='checkbox' value='1' />"
end
assert_dom_equal expected, output_buffer
@@ -626,10 +636,10 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/", "create-post", method: "delete") do
- "<input name='post[title]' type='text' id='post_title' value='Hello World' />" +
- "<textarea name='post[body]' id='post_body'>\nBack to the hill and over it again!</textarea>" +
+ "<input name='post[title]' type='text' value='Hello World' />" +
+ "<textarea name='post[body]'>\nBack to the hill and over it again!</textarea>" +
"<input name='post[secret]' type='hidden' value='0' />" +
- "<input name='post[secret]' checked='checked' type='checkbox' id='post_secret' value='1' />"
+ "<input name='post[secret]' checked='checked' type='checkbox' value='1' />"
end
assert_dom_equal expected, output_buffer
@@ -643,7 +653,7 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/search", "search-post", method: "get") do
- "<input name='post[title]' type='search' id='post_title' />"
+ "<input name='post[title]' type='search' />"
end
assert_dom_equal expected, output_buffer
@@ -657,10 +667,10 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/", "create-post", method: "patch") do
- "<input name='post[title]' type='text' id='post_title' value='Hello World' />" +
- "<textarea name='post[body]' id='post_body'>\nBack to the hill and over it again!</textarea>" +
+ "<input name='post[title]' type='text' value='Hello World' />" +
+ "<textarea name='post[body]'>\nBack to the hill and over it again!</textarea>" +
"<input name='post[secret]' type='hidden' value='0' />" +
- "<input name='post[secret]' checked='checked' type='checkbox' id='post_secret' value='1' />"
+ "<input name='post[secret]' checked='checked' type='checkbox' value='1' />"
end
assert_dom_equal expected, output_buffer
@@ -672,7 +682,7 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/", skip_enforcing_utf8: true) do
- "<input name='post[title]' type='text' id='post_title' value='Hello World' />"
+ "<input name='post[title]' type='text' value='Hello World' />"
end
assert_dom_equal expected, output_buffer
@@ -684,7 +694,7 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/", skip_enforcing_utf8: false) do
- "<input name='post[title]' type='text' id='post_title' value='Hello World' />"
+ "<input name='post[title]' type='text' value='Hello World' />"
end
assert_dom_equal expected, output_buffer
@@ -698,10 +708,10 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/", "create-post") do
- "<input name='post[title]' type='text' id='post_title' value='Hello World' />" +
- "<textarea name='post[body]' id='post_body'>\nBack to the hill and over it again!</textarea>" +
+ "<input name='post[title]' type='text' value='Hello World' />" +
+ "<textarea name='post[body]'>\nBack to the hill and over it again!</textarea>" +
"<input name='post[secret]' type='hidden' value='0' />" +
- "<input name='post[secret]' checked='checked' type='checkbox' id='post_secret' value='1' />"
+ "<input name='post[secret]' checked='checked' type='checkbox' value='1' />"
end
assert_dom_equal expected, output_buffer
@@ -717,10 +727,10 @@ class FormWithActsLikeFormForTest < FormWithTest
expected = whole_form("/posts/123", method: "patch") do
"<label for='post_123_title'>Title</label>" +
- "<input name='post[123][title]' type='text' id='post_123_title' value='Hello World' />" +
- "<textarea name='post[123][body]' id='post_123_body'>\nBack to the hill and over it again!</textarea>" +
+ "<input name='post[123][title]' type='text' value='Hello World' />" +
+ "<textarea name='post[123][body]'>\nBack to the hill and over it again!</textarea>" +
"<input name='post[123][secret]' type='hidden' value='0' />" +
- "<input name='post[123][secret]' checked='checked' type='checkbox' id='post_123_secret' value='1' />"
+ "<input name='post[123][secret]' checked='checked' type='checkbox' value='1' />"
end
assert_dom_equal expected, output_buffer
@@ -734,10 +744,10 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/posts/123", method: "patch") do
- "<input name='post[][title]' type='text' id='post__title' value='Hello World' />" +
- "<textarea name='post[][body]' id='post__body'>\nBack to the hill and over it again!</textarea>" +
+ "<input name='post[][title]' type='text' value='Hello World' />" +
+ "<textarea name='post[][body]'>\nBack to the hill and over it again!</textarea>" +
"<input name='post[][secret]' type='hidden' value='0' />" +
- "<input name='post[][secret]' checked='checked' type='checkbox' id='post__secret' value='1' />"
+ "<input name='post[][secret]' checked='checked' type='checkbox' value='1' />"
end
assert_dom_equal expected, output_buffer
@@ -752,7 +762,7 @@ class FormWithActsLikeFormForTest < FormWithTest
expected = whole_form("/posts/123", method: "patch") do
"<div class='field_with_errors'><label for='post_author_name' class='label'>Author name</label></div>" +
- "<div class='field_with_errors'><input name='post[author_name]' type='text' id='post_author_name' value='' /></div>" +
+ "<div class='field_with_errors'><input name='post[author_name]' type='text' value='' /></div>" +
"<input name='commit' data-disable-with='Create post' type='submit' value='Create post' />"
end
@@ -770,7 +780,7 @@ class FormWithActsLikeFormForTest < FormWithTest
expected = whole_form("/posts/123", method: "patch") do
"<div class='field_with_errors'><label for='post_author_name' class='label'>Author name</label></div>" +
- "<div class='field_with_errors'><input name='post[author_name]' type='text' id='post_author_name' value='' /></div>" +
+ "<div class='field_with_errors'><input name='post[author_name]' type='text' value='' /></div>" +
"<input name='commit' data-disable-with='Create post' type='submit' value='Create post' />"
end
@@ -800,10 +810,10 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/posts/123", "namespace_edit_post_123", "edit_post", method: "patch") do
- "<input name='post[title]' type='text' id='namespace_post_title' value='Hello World' />" +
- "<textarea name='post[body]' id='namespace_post_body'>\nBack to the hill and over it again!</textarea>" +
+ "<input name='post[title]' type='text' value='Hello World' />" +
+ "<textarea name='post[body]'>\nBack to the hill and over it again!</textarea>" +
"<input name='post[secret]' type='hidden' value='0' />" +
- "<input name='post[secret]' checked='checked' type='checkbox' id='namespace_post_secret' value='1' />"
+ "<input name='post[secret]' checked='checked' type='checkbox' value='1' />"
end
assert_dom_equal expected, output_buffer
@@ -877,7 +887,7 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/posts/123", method: "patch") do
- "<input name='post[comment][body]' type='text' id='post_comment_body' value='Hello World' />"
+ "<input name='post[comment][body]' type='text' value='Hello World' />"
end
assert_dom_equal expected, output_buffer
@@ -897,7 +907,7 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form do
- "<input name='posts[post][0][comment][1][name]' type='text' id='posts_post_0_comment_1_name' value='comment #1' />"
+ "<input name='posts[post][0][comment][1][name]' type='text' value='comment #1' />"
end
assert_dom_equal expected, output_buffer
@@ -912,8 +922,8 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/posts/123", method: "patch") do
- "<input name='post[123][title]' type='text' id='post_123_title' value='Hello World' />" +
- "<input name='post[123][comment][][name]' type='text' id='post_123_comment__name' value='new comment' />"
+ "<input name='post[123][title]' type='text' value='Hello World' />" +
+ "<input name='post[123][comment][][name]' type='text' value='new comment' />"
end
assert_dom_equal expected, output_buffer
@@ -928,8 +938,8 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/posts/123", method: "patch") do
- "<input name='post[1][title]' type='text' id='post_1_title' value='Hello World' />" +
- "<input name='post[1][comment][1][name]' type='text' id='post_1_comment_1_name' value='new comment' />"
+ "<input name='post[1][title]' type='text' value='Hello World' />" +
+ "<input name='post[1][comment][1][name]' type='text' value='new comment' />"
end
assert_dom_equal expected, output_buffer
@@ -943,7 +953,7 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/posts/123", method: "patch") do
- "<input name='post[1][comment][title]' type='text' id='post_1_comment_title' value='Hello World' />"
+ "<input name='post[1][comment][title]' type='text' value='Hello World' />"
end
assert_dom_equal expected, output_buffer
@@ -957,7 +967,7 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/posts/123", method: "patch") do
- "<input name='post[1][comment][5][title]' type='text' id='post_1_comment_5_title' value='Hello World' />"
+ "<input name='post[1][comment][5][title]' type='text' value='Hello World' />"
end
assert_dom_equal expected, output_buffer
@@ -971,7 +981,7 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/posts/123", method: "patch") do
- "<input name='post[123][comment][title]' type='text' id='post_123_comment_title' value='Hello World' />"
+ "<input name='post[123][comment][title]' type='text' value='Hello World' />"
end
assert_dom_equal expected, output_buffer
@@ -985,7 +995,7 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/posts/123", method: "patch") do
- "<input name='post[comment][5][title]' type='radio' id='post_comment_5_title_hello' value='hello' />"
+ "<input name='post[comment][5][title]' type='radio' value='hello' />"
end
assert_dom_equal expected, output_buffer
@@ -999,7 +1009,7 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/posts/123", method: "patch") do
- "<input name='post[123][comment][123][title]' type='text' id='post_123_comment_123_title' value='Hello World' />"
+ "<input name='post[123][comment][123][title]' type='text' value='Hello World' />"
end
assert_dom_equal expected, output_buffer
@@ -1019,9 +1029,9 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/posts/123", method: "patch") do
- "<input name='post[123][comment][5][title]' type='text' id='post_123_comment_5_title' value='Hello World' />"
+ "<input name='post[123][comment][5][title]' type='text' value='Hello World' />"
end + whole_form("/posts/123", method: "patch") do
- "<input name='post[1][comment][123][title]' type='text' id='post_1_comment_123_title' value='Hello World' />"
+ "<input name='post[1][comment][123][title]' type='text' value='Hello World' />"
end
assert_dom_equal expected, output_buffer
@@ -1038,8 +1048,8 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/posts/123", method: "patch") do
- '<input name="post[title]" type="text" id="post_title" value="Hello World" />' +
- '<input id="post_author_attributes_name" name="post[author_attributes][name]" type="text" value="new author" />'
+ '<input name="post[title]" type="text" value="Hello World" />' +
+ '<input name="post[author_attributes][name]" type="text" value="new author" />'
end
assert_dom_equal expected, output_buffer
@@ -1065,9 +1075,9 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/posts/123", method: "patch") do
- '<input name="post[title]" type="text" id="post_title" value="Hello World" />' +
- '<input id="post_author_attributes_name" name="post[author_attributes][name]" type="text" value="author #321" />' +
- '<input id="post_author_attributes_id" name="post[author_attributes][id]" type="hidden" value="321" />'
+ '<input name="post[title]" type="text" value="Hello World" />' +
+ '<input name="post[author_attributes][name]" type="text" value="author #321" />' +
+ '<input name="post[author_attributes][id]" type="hidden" value="321" />'
end
assert_dom_equal expected, output_buffer
@@ -1084,9 +1094,9 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/posts/123", method: "patch") do
- '<input name="post[title]" type="text" id="post_title" value="Hello World" />' +
- '<input id="post_author_attributes_name" name="post[author_attributes][name]" type="text" value="author #321" />' +
- '<input id="post_author_attributes_id" name="post[author_attributes][id]" type="hidden" value="321" />'
+ '<input name="post[title]" type="text" value="Hello World" />' +
+ '<input name="post[author_attributes][name]" type="text" value="author #321" />' +
+ '<input name="post[author_attributes][id]" type="hidden" value="321" />'
end
assert_dom_equal expected, output_buffer
@@ -1103,8 +1113,8 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/posts/123", method: "patch") do
- '<input name="post[title]" type="text" id="post_title" value="Hello World" />' +
- '<input id="post_author_attributes_name" name="post[author_attributes][name]" type="text" value="author #321" />'
+ '<input name="post[title]" type="text" value="Hello World" />' +
+ '<input name="post[author_attributes][name]" type="text" value="author #321" />'
end
assert_dom_equal expected, output_buffer
@@ -1121,8 +1131,8 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/posts/123", method: "patch") do
- '<input name="post[title]" type="text" id="post_title" value="Hello World" />' +
- '<input id="post_author_attributes_name" name="post[author_attributes][name]" type="text" value="author #321" />'
+ '<input name="post[title]" type="text" value="Hello World" />' +
+ '<input name="post[author_attributes][name]" type="text" value="author #321" />'
end
assert_dom_equal expected, output_buffer
@@ -1139,9 +1149,9 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/posts/123", method: "patch") do
- '<input name="post[title]" type="text" id="post_title" value="Hello World" />' +
- '<input id="post_author_attributes_name" name="post[author_attributes][name]" type="text" value="author #321" />' +
- '<input id="post_author_attributes_id" name="post[author_attributes][id]" type="hidden" value="321" />'
+ '<input name="post[title]" type="text" value="Hello World" />' +
+ '<input name="post[author_attributes][name]" type="text" value="author #321" />' +
+ '<input name="post[author_attributes][id]" type="hidden" value="321" />'
end
assert_dom_equal expected, output_buffer
@@ -1159,9 +1169,9 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/posts/123", method: "patch") do
- '<input name="post[title]" type="text" id="post_title" value="Hello World" />' +
- '<input id="post_author_attributes_id" name="post[author_attributes][id]" type="hidden" value="321" />' +
- '<input id="post_author_attributes_name" name="post[author_attributes][name]" type="text" value="author #321" />'
+ '<input name="post[title]" type="text" value="Hello World" />' +
+ '<input name="post[author_attributes][id]" type="hidden" value="321" />' +
+ '<input name="post[author_attributes][name]" type="text" value="author #321" />'
end
assert_dom_equal expected, output_buffer
@@ -1180,11 +1190,11 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/posts/123", method: "patch") do
- '<input name="post[title]" type="text" id="post_title" value="Hello World" />' +
- '<input id="post_comments_attributes_0_name" name="post[comments_attributes][0][name]" type="text" value="comment #1" />' +
- '<input id="post_comments_attributes_0_id" name="post[comments_attributes][0][id]" type="hidden" value="1" />' +
- '<input id="post_comments_attributes_1_name" name="post[comments_attributes][1][name]" type="text" value="comment #2" />' +
- '<input id="post_comments_attributes_1_id" name="post[comments_attributes][1][id]" type="hidden" value="2" />'
+ '<input name="post[title]" type="text" value="Hello World" />' +
+ '<input name="post[comments_attributes][0][name]" type="text" value="comment #1" />' +
+ '<input name="post[comments_attributes][0][id]" type="hidden" value="1" />' +
+ '<input name="post[comments_attributes][1][name]" type="text" value="comment #2" />' +
+ '<input name="post[comments_attributes][1][id]" type="hidden" value="2" />'
end
assert_dom_equal expected, output_buffer
@@ -1207,11 +1217,11 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/posts/123", method: "patch") do
- '<input name="post[title]" type="text" id="post_title" value="Hello World" />' +
- '<input id="post_author_attributes_name" name="post[author_attributes][name]" type="text" value="author #321" />' +
- '<input id="post_author_attributes_id" name="post[author_attributes][id]" type="hidden" value="321" />' +
- '<input id="post_comments_attributes_0_name" name="post[comments_attributes][0][name]" type="text" value="comment #1" />' +
- '<input id="post_comments_attributes_1_name" name="post[comments_attributes][1][name]" type="text" value="comment #2" />'
+ '<input name="post[title]" type="text" value="Hello World" />' +
+ '<input name="post[author_attributes][name]" type="text" value="author #321" />' +
+ '<input name="post[author_attributes][id]" type="hidden" value="321" />' +
+ '<input name="post[comments_attributes][0][name]" type="text" value="comment #1" />' +
+ '<input name="post[comments_attributes][1][name]" type="text" value="comment #2" />'
end
assert_dom_equal expected, output_buffer
@@ -1234,10 +1244,10 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/posts/123", method: "patch") do
- '<input name="post[title]" type="text" id="post_title" value="Hello World" />' +
- '<input id="post_author_attributes_name" name="post[author_attributes][name]" type="text" value="author #321" />' +
- '<input id="post_comments_attributes_0_name" name="post[comments_attributes][0][name]" type="text" value="comment #1" />' +
- '<input id="post_comments_attributes_1_name" name="post[comments_attributes][1][name]" type="text" value="comment #2" />'
+ '<input name="post[title]" type="text" value="Hello World" />' +
+ '<input name="post[author_attributes][name]" type="text" value="author #321" />' +
+ '<input name="post[comments_attributes][0][name]" type="text" value="comment #1" />' +
+ '<input name="post[comments_attributes][1][name]" type="text" value="comment #2" />'
end
assert_dom_equal expected, output_buffer
@@ -1260,11 +1270,11 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/posts/123", method: "patch") do
- '<input name="post[title]" type="text" id="post_title" value="Hello World" />' +
- '<input id="post_author_attributes_name" name="post[author_attributes][name]" type="text" value="author #321" />' +
- '<input id="post_author_attributes_id" name="post[author_attributes][id]" type="hidden" value="321" />' +
- '<input id="post_comments_attributes_0_name" name="post[comments_attributes][0][name]" type="text" value="comment #1" />' +
- '<input id="post_comments_attributes_1_name" name="post[comments_attributes][1][name]" type="text" value="comment #2" />'
+ '<input name="post[title]" type="text" value="Hello World" />' +
+ '<input name="post[author_attributes][name]" type="text" value="author #321" />' +
+ '<input name="post[author_attributes][id]" type="hidden" value="321" />' +
+ '<input name="post[comments_attributes][0][name]" type="text" value="comment #1" />' +
+ '<input name="post[comments_attributes][1][name]" type="text" value="comment #2" />'
end
assert_dom_equal expected, output_buffer
@@ -1283,11 +1293,11 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/posts/123", method: "patch") do
- '<input name="post[title]" type="text" id="post_title" value="Hello World" />' +
- '<input id="post_comments_attributes_0_name" name="post[comments_attributes][0][name]" type="text" value="comment #1" />' +
- '<input id="post_comments_attributes_0_id" name="post[comments_attributes][0][id]" type="hidden" value="1" />' +
- '<input id="post_comments_attributes_1_name" name="post[comments_attributes][1][name]" type="text" value="comment #2" />' +
- '<input id="post_comments_attributes_1_id" name="post[comments_attributes][1][id]" type="hidden" value="2" />'
+ '<input name="post[title]" type="text" value="Hello World" />' +
+ '<input name="post[comments_attributes][0][name]" type="text" value="comment #1" />' +
+ '<input name="post[comments_attributes][0][id]" type="hidden" value="1" />' +
+ '<input name="post[comments_attributes][1][name]" type="text" value="comment #2" />' +
+ '<input name="post[comments_attributes][1][id]" type="hidden" value="2" />'
end
assert_dom_equal expected, output_buffer
@@ -1307,11 +1317,11 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/posts/123", method: "patch") do
- '<input name="post[title]" type="text" id="post_title" value="Hello World" />' +
- '<input id="post_comments_attributes_0_id" name="post[comments_attributes][0][id]" type="hidden" value="1" />' +
- '<input id="post_comments_attributes_0_name" name="post[comments_attributes][0][name]" type="text" value="comment #1" />' +
- '<input id="post_comments_attributes_1_id" name="post[comments_attributes][1][id]" type="hidden" value="2" />' +
- '<input id="post_comments_attributes_1_name" name="post[comments_attributes][1][name]" type="text" value="comment #2" />'
+ '<input name="post[title]" type="text" value="Hello World" />' +
+ '<input name="post[comments_attributes][0][id]" type="hidden" value="1" />' +
+ '<input name="post[comments_attributes][0][name]" type="text" value="comment #1" />' +
+ '<input name="post[comments_attributes][1][id]" type="hidden" value="2" />' +
+ '<input name="post[comments_attributes][1][name]" type="text" value="comment #2" />'
end
assert_dom_equal expected, output_buffer
@@ -1330,9 +1340,9 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/posts/123", method: "patch") do
- '<input name="post[title]" type="text" id="post_title" value="Hello World" />' +
- '<input id="post_comments_attributes_0_name" name="post[comments_attributes][0][name]" type="text" value="new comment" />' +
- '<input id="post_comments_attributes_1_name" name="post[comments_attributes][1][name]" type="text" value="new comment" />'
+ '<input name="post[title]" type="text" value="Hello World" />' +
+ '<input name="post[comments_attributes][0][name]" type="text" value="new comment" />' +
+ '<input name="post[comments_attributes][1][name]" type="text" value="new comment" />'
end
assert_dom_equal expected, output_buffer
@@ -1351,10 +1361,10 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/posts/123", method: "patch") do
- '<input name="post[title]" type="text" id="post_title" value="Hello World" />' +
- '<input id="post_comments_attributes_0_name" name="post[comments_attributes][0][name]" type="text" value="comment #321" />' +
- '<input id="post_comments_attributes_0_id" name="post[comments_attributes][0][id]" type="hidden" value="321" />' +
- '<input id="post_comments_attributes_1_name" name="post[comments_attributes][1][name]" type="text" value="new comment" />'
+ '<input name="post[title]" type="text" value="Hello World" />' +
+ '<input name="post[comments_attributes][0][name]" type="text" value="comment #321" />' +
+ '<input name="post[comments_attributes][0][id]" type="hidden" value="321" />' +
+ '<input name="post[comments_attributes][1][name]" type="text" value="new comment" />'
end
assert_dom_equal expected, output_buffer
@@ -1369,7 +1379,7 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/posts/123", method: "patch") do
- '<input name="post[title]" type="text" id="post_title" value="Hello World" />'
+ '<input name="post[title]" type="text" value="Hello World" />'
end
assert_dom_equal expected, output_buffer
@@ -1386,11 +1396,11 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/posts/123", method: "patch") do
- '<input name="post[title]" type="text" id="post_title" value="Hello World" />' +
- '<input id="post_comments_attributes_0_name" name="post[comments_attributes][0][name]" type="text" value="comment #1" />' +
- '<input id="post_comments_attributes_0_id" name="post[comments_attributes][0][id]" type="hidden" value="1" />' +
- '<input id="post_comments_attributes_1_name" name="post[comments_attributes][1][name]" type="text" value="comment #2" />' +
- '<input id="post_comments_attributes_1_id" name="post[comments_attributes][1][id]" type="hidden" value="2" />'
+ '<input name="post[title]" type="text" value="Hello World" />' +
+ '<input name="post[comments_attributes][0][name]" type="text" value="comment #1" />' +
+ '<input name="post[comments_attributes][0][id]" type="hidden" value="1" />' +
+ '<input name="post[comments_attributes][1][name]" type="text" value="comment #2" />' +
+ '<input name="post[comments_attributes][1][id]" type="hidden" value="2" />'
end
assert_dom_equal expected, output_buffer
@@ -1407,11 +1417,11 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/posts/123", method: "patch") do
- '<input name="post[title]" type="text" id="post_title" value="Hello World" />' +
- '<input id="post_comments_attributes_0_name" name="post[comments_attributes][0][name]" type="text" value="comment #1" />' +
- '<input id="post_comments_attributes_0_id" name="post[comments_attributes][0][id]" type="hidden" value="1" />' +
- '<input id="post_comments_attributes_1_name" name="post[comments_attributes][1][name]" type="text" value="comment #2" />' +
- '<input id="post_comments_attributes_1_id" name="post[comments_attributes][1][id]" type="hidden" value="2" />'
+ '<input name="post[title]" type="text" value="Hello World" />' +
+ '<input name="post[comments_attributes][0][name]" type="text" value="comment #1" />' +
+ '<input name="post[comments_attributes][0][id]" type="hidden" value="1" />' +
+ '<input name="post[comments_attributes][1][name]" type="text" value="comment #2" />' +
+ '<input name="post[comments_attributes][1][id]" type="hidden" value="2" />'
end
assert_dom_equal expected, output_buffer
@@ -1442,11 +1452,11 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/posts/123", method: "patch") do
- '<input name="post[title]" type="text" id="post_title" value="Hello World" />' +
- '<input id="post_comments_attributes_0_name" name="post[comments_attributes][0][name]" type="text" value="comment #1" />' +
- '<input id="post_comments_attributes_0_id" name="post[comments_attributes][0][id]" type="hidden" value="1" />' +
- '<input id="post_comments_attributes_1_name" name="post[comments_attributes][1][name]" type="text" value="comment #2" />' +
- '<input id="post_comments_attributes_1_id" name="post[comments_attributes][1][id]" type="hidden" value="2" />'
+ '<input name="post[title]" type="text" value="Hello World" />' +
+ '<input name="post[comments_attributes][0][name]" type="text" value="comment #1" />' +
+ '<input name="post[comments_attributes][0][id]" type="hidden" value="1" />' +
+ '<input name="post[comments_attributes][1][name]" type="text" value="comment #2" />' +
+ '<input name="post[comments_attributes][1][id]" type="hidden" value="2" />'
end
assert_dom_equal expected, output_buffer
@@ -1465,10 +1475,10 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/posts/123", method: "patch") do
- '<input name="post[title]" type="text" id="post_title" value="Hello World" />' +
- '<input id="post_comments_attributes_0_name" name="post[comments_attributes][0][name]" type="text" value="comment #321" />' +
- '<input id="post_comments_attributes_0_id" name="post[comments_attributes][0][id]" type="hidden" value="321" />' +
- '<input id="post_comments_attributes_1_name" name="post[comments_attributes][1][name]" type="text" value="new comment" />'
+ '<input name="post[title]" type="text" value="Hello World" />' +
+ '<input name="post[comments_attributes][0][name]" type="text" value="comment #321" />' +
+ '<input name="post[comments_attributes][0][id]" type="hidden" value="321" />' +
+ '<input name="post[comments_attributes][1][name]" type="text" value="new comment" />'
end
assert_dom_equal expected, output_buffer
@@ -1485,8 +1495,8 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/posts/123", method: "patch") do
- '<input id="post_comments_attributes_abc_name" name="post[comments_attributes][abc][name]" type="text" value="comment #321" />' +
- '<input id="post_comments_attributes_abc_id" name="post[comments_attributes][abc][id]" type="hidden" value="321" />'
+ '<input name="post[comments_attributes][abc][name]" type="text" value="comment #321" />' +
+ '<input name="post[comments_attributes][abc][id]" type="hidden" value="321" />'
end
assert_dom_equal expected, output_buffer
@@ -1502,8 +1512,8 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/posts/123", method: "patch") do
- '<input id="post_comments_attributes_abc_name" name="post[comments_attributes][abc][name]" type="text" value="comment #321" />' +
- '<input id="post_comments_attributes_abc_id" name="post[comments_attributes][abc][id]" type="hidden" value="321" />'
+ '<input name="post[comments_attributes][abc][name]" type="text" value="comment #321" />' +
+ '<input name="post[comments_attributes][abc][id]" type="hidden" value="321" />'
end
assert_dom_equal expected, output_buffer
@@ -1525,8 +1535,8 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/posts/123", method: "patch") do
- '<input id="post_comments_attributes_abc_name" name="post[comments_attributes][abc][name]" type="text" value="comment #321" />' +
- '<input id="post_comments_attributes_abc_id" name="post[comments_attributes][abc][id]" type="hidden" value="321" />'
+ '<input name="post[comments_attributes][abc][name]" type="text" value="comment #321" />' +
+ '<input name="post[comments_attributes][abc][id]" type="hidden" value="321" />'
end
assert_dom_equal expected, output_buffer
@@ -1611,18 +1621,18 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/posts/123", method: "patch") do
- '<input id="post_comments_attributes_0_name" name="post[comments_attributes][0][name]" type="text" value="comment #321" />' +
- '<input id="post_comments_attributes_0_relevances_attributes_0_value" name="post[comments_attributes][0][relevances_attributes][0][value]" type="text" value="commentrelevance #314" />' +
- '<input id="post_comments_attributes_0_relevances_attributes_0_id" name="post[comments_attributes][0][relevances_attributes][0][id]" type="hidden" value="314" />' +
- '<input id="post_comments_attributes_0_id" name="post[comments_attributes][0][id]" type="hidden" value="321" />' +
- '<input id="post_tags_attributes_0_value" name="post[tags_attributes][0][value]" type="text" value="tag #123" />' +
- '<input id="post_tags_attributes_0_relevances_attributes_0_value" name="post[tags_attributes][0][relevances_attributes][0][value]" type="text" value="tagrelevance #3141" />' +
- '<input id="post_tags_attributes_0_relevances_attributes_0_id" name="post[tags_attributes][0][relevances_attributes][0][id]" type="hidden" value="3141" />' +
- '<input id="post_tags_attributes_0_id" name="post[tags_attributes][0][id]" type="hidden" value="123" />' +
- '<input id="post_tags_attributes_1_value" name="post[tags_attributes][1][value]" type="text" value="tag #456" />' +
- '<input id="post_tags_attributes_1_relevances_attributes_0_value" name="post[tags_attributes][1][relevances_attributes][0][value]" type="text" value="tagrelevance #31415" />' +
- '<input id="post_tags_attributes_1_relevances_attributes_0_id" name="post[tags_attributes][1][relevances_attributes][0][id]" type="hidden" value="31415" />' +
- '<input id="post_tags_attributes_1_id" name="post[tags_attributes][1][id]" type="hidden" value="456" />'
+ '<input name="post[comments_attributes][0][name]" type="text" value="comment #321" />' +
+ '<input name="post[comments_attributes][0][relevances_attributes][0][value]" type="text" value="commentrelevance #314" />' +
+ '<input name="post[comments_attributes][0][relevances_attributes][0][id]" type="hidden" value="314" />' +
+ '<input name="post[comments_attributes][0][id]" type="hidden" value="321" />' +
+ '<input name="post[tags_attributes][0][value]" type="text" value="tag #123" />' +
+ '<input name="post[tags_attributes][0][relevances_attributes][0][value]" type="text" value="tagrelevance #3141" />' +
+ '<input name="post[tags_attributes][0][relevances_attributes][0][id]" type="hidden" value="3141" />' +
+ '<input name="post[tags_attributes][0][id]" type="hidden" value="123" />' +
+ '<input name="post[tags_attributes][1][value]" type="text" value="tag #456" />' +
+ '<input name="post[tags_attributes][1][relevances_attributes][0][value]" type="text" value="tagrelevance #31415" />' +
+ '<input name="post[tags_attributes][1][relevances_attributes][0][id]" type="hidden" value="31415" />' +
+ '<input name="post[tags_attributes][1][id]" type="hidden" value="456" />'
end
assert_dom_equal expected, output_buffer
@@ -1638,7 +1648,7 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/posts/123", method: "patch") do
- '<input id="post_author_attributes_name" name="post[author_attributes][name]" type="text" value="hash backed author" />'
+ '<input name="post[author_attributes][name]" type="text" value="hash backed author" />'
end
assert_dom_equal expected, output_buffer
@@ -1652,10 +1662,10 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected =
- "<input name='post[title]' type='text' id='post_title' value='Hello World' />" +
- "<textarea name='post[body]' id='post_body'>\nBack to the hill and over it again!</textarea>" +
+ "<input name='post[title]' type='text' value='Hello World' />" +
+ "<textarea name='post[body]'>\nBack to the hill and over it again!</textarea>" +
"<input name='post[secret]' type='hidden' value='0' />" +
- "<input name='post[secret]' checked='checked' type='checkbox' id='post_secret' value='1' />"
+ "<input name='post[secret]' checked='checked' type='checkbox' value='1' />"
assert_dom_equal expected, output_buffer
end
@@ -1668,10 +1678,10 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected =
- "<input name='post[123][title]' type='text' id='post_123_title' value='Hello World' />" +
- "<textarea name='post[123][body]' id='post_123_body'>\nBack to the hill and over it again!</textarea>" +
+ "<input name='post[123][title]' type='text' value='Hello World' />" +
+ "<textarea name='post[123][body]'>\nBack to the hill and over it again!</textarea>" +
"<input name='post[123][secret]' type='hidden' value='0' />" +
- "<input name='post[123][secret]' checked='checked' type='checkbox' id='post_123_secret' value='1' />"
+ "<input name='post[123][secret]' checked='checked' type='checkbox' value='1' />"
assert_dom_equal expected, output_buffer
end
@@ -1684,10 +1694,10 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected =
- "<input name='post[][title]' type='text' id='post__title' value='Hello World' />" +
- "<textarea name='post[][body]' id='post__body'>\nBack to the hill and over it again!</textarea>" +
+ "<input name='post[][title]' type='text' value='Hello World' />" +
+ "<textarea name='post[][body]'>\nBack to the hill and over it again!</textarea>" +
"<input name='post[][secret]' type='hidden' value='0' />" +
- "<input name='post[][secret]' checked='checked' type='checkbox' id='post__secret' value='1' />"
+ "<input name='post[][secret]' checked='checked' type='checkbox' value='1' />"
assert_dom_equal expected, output_buffer
end
@@ -1700,10 +1710,10 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected =
- "<input name='post[abc][title]' type='text' id='post_abc_title' value='Hello World' />" +
- "<textarea name='post[abc][body]' id='post_abc_body'>\nBack to the hill and over it again!</textarea>" +
+ "<input name='post[abc][title]' type='text' value='Hello World' />" +
+ "<textarea name='post[abc][body]'>\nBack to the hill and over it again!</textarea>" +
"<input name='post[abc][secret]' type='hidden' value='0' />" +
- "<input name='post[abc][secret]' checked='checked' type='checkbox' id='post_abc_secret' value='1' />"
+ "<input name='post[abc][secret]' checked='checked' type='checkbox' value='1' />"
assert_dom_equal expected, output_buffer
end
@@ -1716,10 +1726,10 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected =
- "<input name='post[title]' type='text' id='post_title' value='Hello World' />" +
- "<textarea name='post[body]' id='post_body'>\nBack to the hill and over it again!</textarea>" +
+ "<input name='post[title]' type='text' value='Hello World' />" +
+ "<textarea name='post[body]'>\nBack to the hill and over it again!</textarea>" +
"<input name='post[secret]' type='hidden' value='0' />" +
- "<input name='post[secret]' checked='checked' type='checkbox' id='post_secret' value='1' />"
+ "<input name='post[secret]' checked='checked' type='checkbox' value='1' />"
assert_dom_equal expected, output_buffer
end
@@ -1732,10 +1742,10 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected =
- "<input name='post[title]' type='text' id='post_title' value='Hello World' />" +
- "<textarea name='post[body]' id='post_body'>\nBack to the hill and over it again!</textarea>" +
+ "<input name='post[title]' type='text' value='Hello World' />" +
+ "<textarea name='post[body]'>\nBack to the hill and over it again!</textarea>" +
"<input name='post[secret]' type='hidden' value='0' />" +
- "<input name='post[secret]' checked='checked' type='checkbox' id='post_secret' value='1' />"
+ "<input name='post[secret]' checked='checked' type='checkbox' value='1' />"
assert_dom_equal expected, output_buffer
end
@@ -1747,7 +1757,7 @@ class FormWithActsLikeFormForTest < FormWithTest
end
assert_dom_equal "<label for=\"author_post_title\">Title</label>" +
- "<input name='author[post][title]' type='text' id='author_post_title' value='Hello World' />",
+ "<input name='author[post][title]' type='text' value='Hello World' />",
output_buffer
end
@@ -1758,7 +1768,7 @@ class FormWithActsLikeFormForTest < FormWithTest
end
assert_dom_equal "<label for=\"author_post_1_title\">Title</label>" +
- "<input name='author[post][1][title]' type='text' id='author_post_1_title' value='Hello World' />",
+ "<input name='author[post][1][title]' type='text' value='Hello World' />",
output_buffer
end
@@ -1777,10 +1787,10 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/posts/123", "create-post", method: "patch") do
- "<input name='post[title]' type='text' id='post_title' value='Hello World' />" +
- "<textarea name='post[body]' id='post_body'>\nBack to the hill and over it again!</textarea>" +
+ "<input name='post[title]' type='text' value='Hello World' />" +
+ "<textarea name='post[body]'>\nBack to the hill and over it again!</textarea>" +
"<input name='parent_post[secret]' type='hidden' value='0' />" +
- "<input name='parent_post[secret]' checked='checked' type='checkbox' id='parent_post_secret' value='1' />"
+ "<input name='parent_post[secret]' checked='checked' type='checkbox' value='1' />"
end
assert_dom_equal expected, output_buffer
@@ -1797,9 +1807,9 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/posts/123", "create-post", method: "patch") do
- "<input name='post[title]' type='text' id='post_title' value='Hello World' />" +
- "<textarea name='post[body]' id='post_body'>\nBack to the hill and over it again!</textarea>" +
- "<input name='post[comment][name]' type='text' id='post_comment_name' value='new comment' />"
+ "<input name='post[title]' type='text' value='Hello World' />" +
+ "<textarea name='post[body]'>\nBack to the hill and over it again!</textarea>" +
+ "<input name='post[comment][name]' type='text' value='new comment' />"
end
assert_dom_equal expected, output_buffer
@@ -1813,7 +1823,7 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/posts/123", method: "patch") do
- "<input name='post[category][name]' type='text' id='post_category_name' />"
+ "<input name='post[category][name]' type='text' />"
end
assert_dom_equal expected, output_buffer
@@ -1837,9 +1847,9 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/posts/123", method: "patch") do
- "<label for='title'>Title:</label> <input name='post[title]' type='text' id='post_title' value='Hello World' /><br/>" +
- "<label for='body'>Body:</label> <textarea name='post[body]' id='post_body'>\nBack to the hill and over it again!</textarea><br/>" +
- "<label for='secret'>Secret:</label> <input name='post[secret]' type='hidden' value='0' /><input name='post[secret]' checked='checked' type='checkbox' id='post_secret' value='1' /><br/>"
+ "<label for='title'>Title:</label> <input name='post[title]' type='text' value='Hello World' /><br/>" +
+ "<label for='body'>Body:</label> <textarea name='post[body]'>\nBack to the hill and over it again!</textarea><br/>" +
+ "<label for='secret'>Secret:</label> <input name='post[secret]' type='hidden' value='0' /><input name='post[secret]' checked='checked' type='checkbox' value='1' /><br/>"
end
assert_dom_equal expected, output_buffer
@@ -1856,9 +1866,9 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/posts/123", method: "patch") do
- "<label for='title'>Title:</label> <input name='post[title]' type='text' id='post_title' value='Hello World' /><br/>" +
- "<label for='body'>Body:</label> <textarea name='post[body]' id='post_body'>\nBack to the hill and over it again!</textarea><br/>" +
- "<label for='secret'>Secret:</label> <input name='post[secret]' type='hidden' value='0' /><input name='post[secret]' checked='checked' type='checkbox' id='post_secret' value='1' /><br/>"
+ "<label for='title'>Title:</label> <input name='post[title]' type='text' value='Hello World' /><br/>" +
+ "<label for='body'>Body:</label> <textarea name='post[body]'>\nBack to the hill and over it again!</textarea><br/>" +
+ "<label for='secret'>Secret:</label> <input name='post[secret]' type='hidden' value='0' /><input name='post[secret]' checked='checked' type='checkbox' value='1' /><br/>"
end
assert_dom_equal expected, output_buffer
@@ -1875,7 +1885,7 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/posts/123", method: "patch") do
- "<label for='title'>Title:</label> <input name='post[title]' type='text' id='post_title' value='Hello World' /><br/>"
+ "<label for='title'>Title:</label> <input name='post[title]' type='text' value='Hello World' /><br/>"
end
assert_dom_equal expected, output_buffer
@@ -1890,7 +1900,7 @@ class FormWithActsLikeFormForTest < FormWithTest
concat f.text_field(:title)
end
- expected = "<label for='title'>Title:</label> <input name='post[title]' type='text' id='post_title' value='Hello World' /><br/>"
+ expected = "<label for='title'>Title:</label> <input name='post[title]' type='text' value='Hello World' /><br/>"
assert_dom_equal expected, output_buffer
end
@@ -1902,7 +1912,7 @@ class FormWithActsLikeFormForTest < FormWithTest
concat f.text_field(:title)
end
- expected = "<label for='title'>Title:</label> <input name='post[title]' type='text' id='post_title' value='Hello World' /><br/>"
+ expected = "<label for='title'>Title:</label> <input name='post[title]' type='text' value='Hello World' /><br/>"
assert_dom_equal expected, output_buffer
end
@@ -1915,9 +1925,9 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected =
- "<label for='title'>Title:</label> <input name='post[title]' type='text' id='post_title' value='Hello World' /><br/>" +
- "<label for='body'>Body:</label> <textarea name='post[body]' id='post_body'>\nBack to the hill and over it again!</textarea><br/>" +
- "<label for='secret'>Secret:</label> <input name='post[secret]' type='hidden' value='0' /><input name='post[secret]' checked='checked' type='checkbox' id='post_secret' value='1' /><br/>"
+ "<label for='title'>Title:</label> <input name='post[title]' type='text' value='Hello World' /><br/>" +
+ "<label for='body'>Body:</label> <textarea name='post[body]'>\nBack to the hill and over it again!</textarea><br/>" +
+ "<label for='secret'>Secret:</label> <input name='post[secret]' type='hidden' value='0' /><input name='post[secret]' checked='checked' type='checkbox' value='1' /><br/>"
assert_dom_equal expected, output_buffer
end
diff --git a/activemodel/test/cases/errors_test.rb b/activemodel/test/cases/errors_test.rb
index e868d20fc8..e6ba06301d 100644
--- a/activemodel/test/cases/errors_test.rb
+++ b/activemodel/test/cases/errors_test.rb
@@ -1,4 +1,5 @@
require "cases/helper"
+require "yaml"
class ErrorsTest < ActiveModel::TestCase
class Person
diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md
index e377ad85c9..eac54e7566 100644
--- a/activerecord/CHANGELOG.md
+++ b/activerecord/CHANGELOG.md
@@ -1,3 +1,28 @@
+* Notifications see frozen SQL string.
+
+ Fixes #23774
+
+ *Richard Monette*
+
+* RuntimeErrors are no longer translated to ActiveRecord::StatementInvalid.
+
+ *Richard Monette*
+
+* Change the schema cache format to use YAML instead of Marshal.
+
+ *Kir Shatrov*
+
+* Support index length and order options using both string and symbol
+ column names.
+
+ Fixes #27243.
+
+ *Ryuta Kamizono*
+
+* Raise `ActiveRecord::RangeError` when values that executed are out of range.
+
+ *Ryuta Kamizono*
+
* Raise `ActiveRecord::NotNullViolation` when a record cannot be inserted
or updated because it would violate a not null constraint.
diff --git a/activerecord/lib/active_record/associations/singular_association.rb b/activerecord/lib/active_record/associations/singular_association.rb
index 6d69f757eb..ee7b7c8bea 100644
--- a/activerecord/lib/active_record/associations/singular_association.rb
+++ b/activerecord/lib/active_record/associations/singular_association.rb
@@ -58,7 +58,7 @@ module ActiveRecord
sc.execute(binds, klass, conn) do |record|
set_inverse_instance record
end.first
- rescue RangeError
+ rescue ::RangeError
nil
end
diff --git a/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb b/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb
index faccd1d641..947796eea0 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb
@@ -10,9 +10,9 @@ module ActiveRecord
def to_sql(arel, binds = [])
if arel.respond_to?(:ast)
collected = visitor.accept(arel.ast, collector)
- collected.compile(binds, self)
+ collected.compile(binds, self).freeze
else
- arel
+ arel.dup.freeze
end
end
diff --git a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb
index 237367c8b3..284529b46e 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb
@@ -598,7 +598,12 @@ module ActiveRecord
def translate_exception(exception, message)
# override in derived class
- ActiveRecord::StatementInvalid.new(message)
+ case exception
+ when RuntimeError
+ exception
+ else
+ ActiveRecord::StatementInvalid.new(message)
+ end
end
def without_prepared_statement?(binds)
diff --git a/activerecord/lib/active_record/connection_adapters/column.rb b/activerecord/lib/active_record/connection_adapters/column.rb
index 02d546209d..61cd7ae4cc 100644
--- a/activerecord/lib/active_record/connection_adapters/column.rb
+++ b/activerecord/lib/active_record/connection_adapters/column.rb
@@ -40,6 +40,28 @@ module ActiveRecord
Base.human_attribute_name(@name)
end
+ def init_with(coder)
+ @name = coder["name"]
+ @table_name = coder["table_name"]
+ @sql_type_metadata = coder["sql_type_metadata"]
+ @null = coder["null"]
+ @default = coder["default"]
+ @default_function = coder["default_function"]
+ @collation = coder["collation"]
+ @comment = coder["comment"]
+ end
+
+ def encode_with(coder)
+ coder["name"] = @name
+ coder["table_name"] = @table_name
+ coder["sql_type_metadata"] = @sql_type_metadata
+ coder["null"] = @null
+ coder["default"] = @default
+ coder["default_function"] = @default_function
+ coder["collation"] = @collation
+ coder["comment"] = @comment
+ end
+
def ==(other)
other.is_a?(Column) &&
attributes_for_hash == other.attributes_for_hash
diff --git a/activerecord/lib/active_record/connection_adapters/schema_cache.rb b/activerecord/lib/active_record/connection_adapters/schema_cache.rb
index 8219f132c3..3a319c4029 100644
--- a/activerecord/lib/active_record/connection_adapters/schema_cache.rb
+++ b/activerecord/lib/active_record/connection_adapters/schema_cache.rb
@@ -21,6 +21,22 @@ module ActiveRecord
@data_sources = @data_sources.dup
end
+ def encode_with(coder)
+ coder["columns"] = @columns
+ coder["columns_hash"] = @columns_hash
+ coder["primary_keys"] = @primary_keys
+ coder["data_sources"] = @data_sources
+ coder["version"] = ActiveRecord::Migrator.current_version
+ end
+
+ def init_with(coder)
+ @columns = coder["columns"]
+ @columns_hash = coder["columns_hash"]
+ @primary_keys = coder["primary_keys"]
+ @data_sources = coder["data_sources"]
+ @version = coder["version"]
+ end
+
def primary_keys(table_name)
@primary_keys[table_name] ||= data_source_exists?(table_name) ? connection.primary_key(table_name) : nil
end
diff --git a/activerecord/lib/active_record/railtie.rb b/activerecord/lib/active_record/railtie.rb
index 7ce10df6d4..2701c5bca9 100644
--- a/activerecord/lib/active_record/railtie.rb
+++ b/activerecord/lib/active_record/railtie.rb
@@ -82,15 +82,15 @@ module ActiveRecord
if config.active_record.delete(:use_schema_cache_dump)
config.after_initialize do |app|
ActiveSupport.on_load(:active_record) do
- filename = File.join(app.config.paths["db"].first, "schema_cache.dump")
+ filename = File.join(app.config.paths["db"].first, "schema_cache.yml")
if File.file?(filename)
- cache = Marshal.load File.binread filename
+ cache = YAML.load(File.read(filename))
if cache.version == ActiveRecord::Migrator.current_version
self.connection.schema_cache = cache
self.connection_pool.schema_cache = cache.dup
else
- warn "Ignoring db/schema_cache.dump because it has expired. The current schema version is #{ActiveRecord::Migrator.current_version}, but the one in the cache is #{cache.version}."
+ warn "Ignoring db/schema_cache.yml because it has expired. The current schema version is #{ActiveRecord::Migrator.current_version}, but the one in the cache is #{cache.version}."
end
end
end
diff --git a/activerecord/lib/active_record/railties/databases.rake b/activerecord/lib/active_record/railties/databases.rake
index 46235ab922..25d79a6c7d 100644
--- a/activerecord/lib/active_record/railties/databases.rake
+++ b/activerecord/lib/active_record/railties/databases.rake
@@ -265,19 +265,19 @@ db_namespace = namespace :db do
end
namespace :cache do
- desc "Creates a db/schema_cache.dump file."
+ desc "Creates a db/schema_cache.yml file."
task dump: [:environment, :load_config] do
- con = ActiveRecord::Base.connection
- filename = File.join(ActiveRecord::Tasks::DatabaseTasks.db_dir, "schema_cache.dump")
+ conn = ActiveRecord::Base.connection
+ filename = File.join(ActiveRecord::Tasks::DatabaseTasks.db_dir, "schema_cache.yml")
- con.schema_cache.clear!
- con.data_sources.each { |table| con.schema_cache.add(table) }
- open(filename, "wb") { |f| f.write(Marshal.dump(con.schema_cache)) }
+ conn.schema_cache.clear!
+ conn.data_sources.each { |table| conn.schema_cache.add(table) }
+ open(filename, "wb") { |f| f.write(YAML.dump(conn.schema_cache)) }
end
- desc "Clears a db/schema_cache.dump file."
+ desc "Clears a db/schema_cache.yml file."
task clear: [:environment, :load_config] do
- filename = File.join(ActiveRecord::Tasks::DatabaseTasks.db_dir, "schema_cache.dump")
+ filename = File.join(ActiveRecord::Tasks::DatabaseTasks.db_dir, "schema_cache.yml")
rm_f filename, verbose: false
end
end
diff --git a/activerecord/test/assets/schema_dump_5_1.yml b/activerecord/test/assets/schema_dump_5_1.yml
new file mode 100644
index 0000000000..f37977daf2
--- /dev/null
+++ b/activerecord/test/assets/schema_dump_5_1.yml
@@ -0,0 +1,345 @@
+--- !ruby/object:ActiveRecord::ConnectionAdapters::SchemaCache
+columns:
+ posts:
+ - &1 !ruby/object:ActiveRecord::ConnectionAdapters::Column
+ name: id
+ table_name: posts
+ sql_type_metadata: !ruby/object:ActiveRecord::ConnectionAdapters::SqlTypeMetadata
+ sql_type: INTEGER
+ type: :integer
+ limit:
+ precision:
+ scale:
+ 'null': false
+ default:
+ default_function:
+ collation:
+ comment:
+ - &2 !ruby/object:ActiveRecord::ConnectionAdapters::Column
+ name: author_id
+ table_name: posts
+ sql_type_metadata: !ruby/object:ActiveRecord::ConnectionAdapters::SqlTypeMetadata
+ sql_type: integer
+ type: :integer
+ limit:
+ precision:
+ scale:
+ 'null': true
+ default:
+ default_function:
+ collation:
+ comment:
+ - &3 !ruby/object:ActiveRecord::ConnectionAdapters::Column
+ name: title
+ table_name: posts
+ sql_type_metadata: !ruby/object:ActiveRecord::ConnectionAdapters::SqlTypeMetadata
+ sql_type: varchar
+ type: :string
+ limit:
+ precision:
+ scale:
+ 'null': false
+ default:
+ default_function:
+ collation:
+ comment:
+ - &4 !ruby/object:ActiveRecord::ConnectionAdapters::Column
+ name: body
+ table_name: posts
+ sql_type_metadata: !ruby/object:ActiveRecord::ConnectionAdapters::SqlTypeMetadata
+ sql_type: text
+ type: :text
+ limit:
+ precision:
+ scale:
+ 'null': false
+ default:
+ default_function:
+ collation:
+ comment:
+ - &5 !ruby/object:ActiveRecord::ConnectionAdapters::Column
+ name: type
+ table_name: posts
+ sql_type_metadata: !ruby/object:ActiveRecord::ConnectionAdapters::SqlTypeMetadata
+ sql_type: varchar
+ type: :string
+ limit:
+ precision:
+ scale:
+ 'null': true
+ default:
+ default_function:
+ collation:
+ comment:
+ - &6 !ruby/object:ActiveRecord::ConnectionAdapters::Column
+ name: comments_count
+ table_name: posts
+ sql_type_metadata: !ruby/object:ActiveRecord::ConnectionAdapters::SqlTypeMetadata
+ sql_type: integer
+ type: :integer
+ limit:
+ precision:
+ scale:
+ 'null': true
+ default: '0'
+ default_function:
+ collation:
+ comment:
+ - &7 !ruby/object:ActiveRecord::ConnectionAdapters::Column
+ name: taggings_with_delete_all_count
+ table_name: posts
+ sql_type_metadata: !ruby/object:ActiveRecord::ConnectionAdapters::SqlTypeMetadata
+ sql_type: integer
+ type: :integer
+ limit:
+ precision:
+ scale:
+ 'null': true
+ default: '0'
+ default_function:
+ collation:
+ comment:
+ - &8 !ruby/object:ActiveRecord::ConnectionAdapters::Column
+ name: taggings_with_destroy_count
+ table_name: posts
+ sql_type_metadata: !ruby/object:ActiveRecord::ConnectionAdapters::SqlTypeMetadata
+ sql_type: integer
+ type: :integer
+ limit:
+ precision:
+ scale:
+ 'null': true
+ default: '0'
+ default_function:
+ collation:
+ comment:
+ - &9 !ruby/object:ActiveRecord::ConnectionAdapters::Column
+ name: tags_count
+ table_name: posts
+ sql_type_metadata: !ruby/object:ActiveRecord::ConnectionAdapters::SqlTypeMetadata
+ sql_type: integer
+ type: :integer
+ limit:
+ precision:
+ scale:
+ 'null': true
+ default: '0'
+ default_function:
+ collation:
+ comment:
+ - &10 !ruby/object:ActiveRecord::ConnectionAdapters::Column
+ name: tags_with_destroy_count
+ table_name: posts
+ sql_type_metadata: !ruby/object:ActiveRecord::ConnectionAdapters::SqlTypeMetadata
+ sql_type: integer
+ type: :integer
+ limit:
+ precision:
+ scale:
+ 'null': true
+ default: '0'
+ default_function:
+ collation:
+ comment:
+ - &11 !ruby/object:ActiveRecord::ConnectionAdapters::Column
+ name: tags_with_nullify_count
+ table_name: posts
+ sql_type_metadata: !ruby/object:ActiveRecord::ConnectionAdapters::SqlTypeMetadata
+ sql_type: integer
+ type: :integer
+ limit:
+ precision:
+ scale:
+ 'null': true
+ default: '0'
+ default_function:
+ collation:
+ comment:
+columns_hash:
+ posts:
+ id: *1
+ author_id: *2
+ title: *3
+ body: *4
+ type: *5
+ comments_count: *6
+ taggings_with_delete_all_count: *7
+ taggings_with_destroy_count: *8
+ tags_count: *9
+ tags_with_destroy_count: *10
+ tags_with_nullify_count: *11
+primary_keys:
+ posts: id
+data_sources:
+ ar_internal_metadata: true
+ table_with_autoincrement: true
+ accounts: true
+ admin_accounts: true
+ admin_users: true
+ aircraft: true
+ articles: true
+ articles_magazines: true
+ articles_tags: true
+ audit_logs: true
+ authors: true
+ author_addresses: true
+ author_favorites: true
+ auto_id_tests: true
+ binaries: true
+ birds: true
+ books: true
+ booleans: true
+ bulbs: true
+ CamelCase: true
+ cars: true
+ carriers: true
+ categories: true
+ categories_posts: true
+ categorizations: true
+ citations: true
+ clubs: true
+ collections: true
+ colnametests: true
+ columns: true
+ comments: true
+ companies: true
+ content: true
+ content_positions: true
+ vegetables: true
+ computers: true
+ computers_developers: true
+ contracts: true
+ customers: true
+ customer_carriers: true
+ dashboards: true
+ developers: true
+ developers_projects: true
+ dog_lovers: true
+ dogs: true
+ doubloons: true
+ edges: true
+ engines: true
+ entrants: true
+ essays: true
+ events: true
+ eyes: true
+ funny_jokes: true
+ cold_jokes: true
+ friendships: true
+ goofy_string_id: true
+ having: true
+ guids: true
+ guitars: true
+ inept_wizards: true
+ integer_limits: true
+ invoices: true
+ iris: true
+ items: true
+ jobs: true
+ jobs_pool: true
+ keyboards: true
+ legacy_things: true
+ lessons: true
+ lessons_students: true
+ students: true
+ lint_models: true
+ line_items: true
+ lions: true
+ lock_without_defaults: true
+ lock_without_defaults_cust: true
+ magazines: true
+ mateys: true
+ members: true
+ member_details: true
+ member_friends: true
+ memberships: true
+ member_types: true
+ mentors: true
+ minivans: true
+ minimalistics: true
+ mixed_case_monkeys: true
+ mixins: true
+ movies: true
+ notifications: true
+ numeric_data: true
+ orders: true
+ organizations: true
+ owners: true
+ paint_colors: true
+ paint_textures: true
+ parrots: true
+ parrots_pirates: true
+ parrots_treasures: true
+ people: true
+ peoples_treasures: true
+ personal_legacy_things: true
+ pets: true
+ pets_treasures: true
+ pirates: true
+ posts: true
+ serialized_posts: true
+ images: true
+ price_estimates: true
+ products: true
+ product_types: true
+ projects: true
+ randomly_named_table1: true
+ randomly_named_table2: true
+ randomly_named_table3: true
+ ratings: true
+ readers: true
+ references: true
+ shape_expressions: true
+ ships: true
+ ship_parts: true
+ prisoners: true
+ shop_accounts: true
+ speedometers: true
+ sponsors: true
+ string_key_objects: true
+ subscribers: true
+ subscriptions: true
+ tags: true
+ taggings: true
+ tasks: true
+ topics: true
+ toys: true
+ traffic_lights: true
+ treasures: true
+ tuning_pegs: true
+ tyres: true
+ variants: true
+ vertices: true
+ warehouse-things: true
+ circles: true
+ squares: true
+ triangles: true
+ non_poly_ones: true
+ non_poly_twos: true
+ men: true
+ faces: true
+ interests: true
+ zines: true
+ wheels: true
+ countries: true
+ treaties: true
+ countries_treaties: true
+ liquid: true
+ molecules: true
+ electrons: true
+ weirds: true
+ nodes: true
+ trees: true
+ hotels: true
+ departments: true
+ cake_designers: true
+ drink_designers: true
+ chefs: true
+ recipes: true
+ records: true
+ overloaded_types: true
+ users: true
+ test_with_keyword_column_name: true
+ fk_test_has_pk: true
+ fk_test_has_fk: true
+version: 0
diff --git a/activerecord/test/cases/adapter_test.rb b/activerecord/test/cases/adapter_test.rb
index 8de69869a4..3fce0a1df1 100644
--- a/activerecord/test/cases/adapter_test.rb
+++ b/activerecord/test/cases/adapter_test.rb
@@ -285,13 +285,13 @@ module ActiveRecord
unless current_adapter?(:PostgreSQLAdapter)
def test_log_invalid_encoding
- error = assert_raise ActiveRecord::StatementInvalid do
+ error = assert_raises RuntimeError do
@connection.send :log, "SELECT 'ы' FROM DUAL" do
raise "ы".force_encoding(Encoding::ASCII_8BIT)
end
end
- assert_not_nil error.cause
+ assert_not_nil error.message
end
end
diff --git a/activerecord/test/cases/adapters/mysql2/reserved_word_test.rb b/activerecord/test/cases/adapters/mysql2/reserved_word_test.rb
index b400f4d2f9..2c778b1150 100644
--- a/activerecord/test/cases/adapters/mysql2/reserved_word_test.rb
+++ b/activerecord/test/cases/adapters/mysql2/reserved_word_test.rb
@@ -143,7 +143,7 @@ class Mysql2ReservedWordTest < ActiveRecord::Mysql2TestCase
end
# custom create table, uses execute on connection to create a table, note: escapes table_name, does NOT escape columns
- def create_tables_directly (tables, connection = @connection)
+ def create_tables_directly(tables, connection = @connection)
tables.each do |table_name, column_properties|
connection.execute("CREATE TABLE `#{table_name}` ( #{column_properties} )")
end
diff --git a/activerecord/test/cases/associations/belongs_to_associations_test.rb b/activerecord/test/cases/associations/belongs_to_associations_test.rb
index 2b8d01743f..81a2a161f2 100644
--- a/activerecord/test/cases/associations/belongs_to_associations_test.rb
+++ b/activerecord/test/cases/associations/belongs_to_associations_test.rb
@@ -1079,7 +1079,7 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase
end
comment = model.new
- comment.post_id = 10_000_000_000
+ comment.post_id = 9223372036854775808 # out of range in the bigint
assert_nil comment.post
assert_not comment.valid?
diff --git a/activerecord/test/cases/connection_adapters/schema_cache_test.rb b/activerecord/test/cases/connection_adapters/schema_cache_test.rb
index d4459603af..1b4f80fc67 100644
--- a/activerecord/test/cases/connection_adapters/schema_cache_test.rb
+++ b/activerecord/test/cases/connection_adapters/schema_cache_test.rb
@@ -12,6 +12,33 @@ module ActiveRecord
assert_equal "id", @cache.primary_keys("posts")
end
+ def test_yaml_dump_and_load
+ @cache.columns("posts")
+ @cache.columns_hash("posts")
+ @cache.data_sources("posts")
+ @cache.primary_keys("posts")
+
+ new_cache = YAML.load(YAML.dump(@cache))
+ assert_no_queries do
+ assert_equal 11, new_cache.columns("posts").size
+ assert_equal 11, new_cache.columns_hash("posts").size
+ assert new_cache.data_sources("posts")
+ assert_equal "id", new_cache.primary_keys("posts")
+ end
+ end
+
+ def test_yaml_loads_5_1_dump
+ body = File.open(schema_dump_path).read
+ cache = YAML.load(body)
+
+ assert_no_queries do
+ assert_equal 11, cache.columns("posts").size
+ assert_equal 11, cache.columns_hash("posts").size
+ assert cache.data_sources("posts")
+ assert_equal "id", cache.primary_keys("posts")
+ end
+ end
+
def test_primary_key_for_non_existent_table
assert_nil @cache.primary_keys("omgponies")
end
@@ -45,10 +72,12 @@ module ActiveRecord
@cache = Marshal.load(Marshal.dump(@cache))
- assert_equal 11, @cache.columns("posts").size
- assert_equal 11, @cache.columns_hash("posts").size
- assert @cache.data_sources("posts")
- assert_equal "id", @cache.primary_keys("posts")
+ assert_no_queries do
+ assert_equal 11, @cache.columns("posts").size
+ assert_equal 11, @cache.columns_hash("posts").size
+ assert @cache.data_sources("posts")
+ assert_equal "id", @cache.primary_keys("posts")
+ end
end
def test_table_methods_deprecation
@@ -56,6 +85,12 @@ module ActiveRecord
assert_deprecated { assert @cache.tables("posts") }
assert_deprecated { @cache.clear_table_cache!("posts") }
end
+
+ private
+
+ def schema_dump_path
+ "test/assets/schema_dump_5_1.yml"
+ end
end
end
end
diff --git a/activerecord/test/cases/finder_test.rb b/activerecord/test/cases/finder_test.rb
index 7eaf31aa24..f8724b0993 100644
--- a/activerecord/test/cases/finder_test.rb
+++ b/activerecord/test/cases/finder_test.rb
@@ -983,7 +983,6 @@ class FinderTest < ActiveRecord::TestCase
assert_equal devs[2], Developer.offset(2).first
assert_equal devs[-3], Developer.offset(2).last
- assert_equal devs[-3], Developer.offset(2).last
assert_equal devs[-3], Developer.offset(2).order("id DESC").first
end
diff --git a/activerecord/test/cases/query_cache_test.rb b/activerecord/test/cases/query_cache_test.rb
index 90054ce83d..4a49bfe9b1 100644
--- a/activerecord/test/cases/query_cache_test.rb
+++ b/activerecord/test/cases/query_cache_test.rb
@@ -202,6 +202,20 @@ class QueryCacheTest < ActiveRecord::TestCase
ActiveSupport::Notifications.unsubscribe subscriber
end
+ def test_query_cache_does_not_allow_sql_key_mutation
+ subscriber = ActiveSupport::Notifications.subscribe("sql.active_record") do |_, _, _, _, payload|
+ payload[:sql].downcase!
+ end
+
+ assert_raises RuntimeError do
+ ActiveRecord::Base.cache do
+ assert_queries(1) { Task.find(1); Task.find(1) }
+ end
+ end
+ ensure
+ ActiveSupport::Notifications.unsubscribe subscriber
+ end
+
def test_cache_is_flat
Task.cache do
assert_queries(1) { Topic.find(1); Topic.find(1); }
diff --git a/activesupport/CHANGELOG.md b/activesupport/CHANGELOG.md
index 10095ee1bd..2a5c8deb11 100644
--- a/activesupport/CHANGELOG.md
+++ b/activesupport/CHANGELOG.md
@@ -1,3 +1,9 @@
+* Change return value of `NilClass#duplicable?`, `FalseClass#duplicable?`,
+ `TrueClass#duplicable?`, `Symbol#duplicable?` and `Numeric#duplicable?`
+ to true with Ruby 2.4+. These classes can dup with Ruby 2.4+.
+
+ *Yuji Yaginuma*
+
* Remove deprecated class `ActiveSupport::Concurrency::Latch`
*Andrew White*
diff --git a/activesupport/lib/active_support/callbacks.rb b/activesupport/lib/active_support/callbacks.rb
index af8ddb176f..e6c79f2a38 100644
--- a/activesupport/lib/active_support/callbacks.rb
+++ b/activesupport/lib/active_support/callbacks.rb
@@ -109,16 +109,22 @@ module ActiveSupport
invoke_sequence = Proc.new do
skipped = nil
while true
- current, next_sequence = next_sequence, next_sequence.nested
+ current = next_sequence
current.invoke_before(env)
if current.final?
env.value = !env.halted && (!block_given? || yield)
elsif current.skip?(env)
(skipped ||= []) << current
+ next_sequence = next_sequence.nested
next
else
- target, block, method, *arguments = current.expand_call_template(env, invoke_sequence)
- target.send(method, *arguments, &block)
+ next_sequence = next_sequence.nested
+ begin
+ target, block, method, *arguments = current.expand_call_template(env, invoke_sequence)
+ target.send(method, *arguments, &block)
+ ensure
+ next_sequence = current
+ end
end
current.invoke_after(env)
skipped.pop.invoke_after(env) while skipped && skipped.first
diff --git a/activesupport/lib/active_support/core_ext/object/duplicable.rb b/activesupport/lib/active_support/core_ext/object/duplicable.rb
index aa2282cb7e..ebe31b38ca 100644
--- a/activesupport/lib/active_support/core_ext/object/duplicable.rb
+++ b/activesupport/lib/active_support/core_ext/object/duplicable.rb
@@ -1,7 +1,7 @@
#--
-# Most objects are cloneable, but not all. For example you can't dup +nil+:
+# Most objects are cloneable, but not all. For example you can't dup methods:
#
-# nil.dup # => TypeError: can't dup NilClass
+# method(:puts).dup # => TypeError: allocator undefined for Method
#
# Classes may signal their instances are not duplicable removing +dup+/+clone+
# or raising exceptions from them. So, to dup an arbitrary object you normally
@@ -19,7 +19,7 @@
class Object
# Can you safely dup this object?
#
- # False for +nil+, +false+, +true+, symbol, number, method objects;
+ # False for method objects;
# true otherwise.
def duplicable?
true
@@ -27,52 +27,77 @@ class Object
end
class NilClass
- # +nil+ is not duplicable:
- #
- # nil.duplicable? # => false
- # nil.dup # => TypeError: can't dup NilClass
- def duplicable?
- false
+ begin
+ nil.dup
+ rescue TypeError
+
+ # +nil+ is not duplicable:
+ #
+ # nil.duplicable? # => false
+ # nil.dup # => TypeError: can't dup NilClass
+ def duplicable?
+ false
+ end
end
end
class FalseClass
- # +false+ is not duplicable:
- #
- # false.duplicable? # => false
- # false.dup # => TypeError: can't dup FalseClass
- def duplicable?
- false
+ begin
+ false.dup
+ rescue TypeError
+
+ # +false+ is not duplicable:
+ #
+ # false.duplicable? # => false
+ # false.dup # => TypeError: can't dup FalseClass
+ def duplicable?
+ false
+ end
end
end
class TrueClass
- # +true+ is not duplicable:
- #
- # true.duplicable? # => false
- # true.dup # => TypeError: can't dup TrueClass
- def duplicable?
- false
+ begin
+ true.dup
+ rescue TypeError
+
+ # +true+ is not duplicable:
+ #
+ # true.duplicable? # => false
+ # true.dup # => TypeError: can't dup TrueClass
+ def duplicable?
+ false
+ end
end
end
class Symbol
- # Symbols are not duplicable:
- #
- # :my_symbol.duplicable? # => false
- # :my_symbol.dup # => TypeError: can't dup Symbol
- def duplicable?
- false
+ begin
+ :symbol.dup
+ rescue TypeError
+
+ # Symbols are not duplicable:
+ #
+ # :my_symbol.duplicable? # => false
+ # :my_symbol.dup # => TypeError: can't dup Symbol
+ def duplicable?
+ false
+ end
end
end
class Numeric
- # Numbers are not duplicable:
- #
- # 3.duplicable? # => false
- # 3.dup # => TypeError: can't dup Integer
- def duplicable?
- false
+ begin
+ 1.dup
+ rescue TypeError
+
+ # Numbers are not duplicable:
+ #
+ # 3.duplicable? # => false
+ # 3.dup # => TypeError: can't dup Integer
+ def duplicable?
+ false
+ end
end
end
diff --git a/activesupport/lib/active_support/inflector/methods.rb b/activesupport/lib/active_support/inflector/methods.rb
index ef3df1240d..fa063af3f4 100644
--- a/activesupport/lib/active_support/inflector/methods.rb
+++ b/activesupport/lib/active_support/inflector/methods.rb
@@ -274,7 +274,7 @@ module ActiveSupport
# Go down the ancestors to check if it is owned directly. The check
# stops when we reach Object or the end of ancestors tree.
- constant = constant.ancestors.inject do |const, ancestor|
+ constant = constant.ancestors.inject(constant) do |const, ancestor|
break const if ancestor == Object
break ancestor if ancestor.const_defined?(name, false)
const
diff --git a/activesupport/lib/active_support/xml_mini.rb b/activesupport/lib/active_support/xml_mini.rb
index e16581d697..e3203ef076 100644
--- a/activesupport/lib/active_support/xml_mini.rb
+++ b/activesupport/lib/active_support/xml_mini.rb
@@ -68,7 +68,17 @@ module ActiveSupport
"datetime" => Proc.new { |time| Time.xmlschema(time).utc rescue ::DateTime.parse(time).utc },
"integer" => Proc.new { |integer| integer.to_i },
"float" => Proc.new { |float| float.to_f },
- "decimal" => Proc.new { |number| BigDecimal(number) },
+ "decimal" => Proc.new do |number|
+ if String === number
+ begin
+ BigDecimal(number)
+ rescue ArgumentError
+ BigDecimal('0')
+ end
+ else
+ BigDecimal(number)
+ end
+ end,
"boolean" => Proc.new { |boolean| %w(1 true).include?(boolean.to_s.strip) },
"string" => Proc.new { |string| string.to_s },
"yaml" => Proc.new { |yaml| YAML::load(yaml) rescue yaml },
diff --git a/activesupport/test/autoloading_fixtures/prepend.rb b/activesupport/test/autoloading_fixtures/prepend.rb
new file mode 100644
index 0000000000..3134d1df2b
--- /dev/null
+++ b/activesupport/test/autoloading_fixtures/prepend.rb
@@ -0,0 +1,8 @@
+class SubClassConflict
+end
+
+class Prepend
+ module PrependedModule
+ end
+ prepend PrependedModule
+end
diff --git a/activesupport/test/autoloading_fixtures/prepend/sub_class_conflict.rb b/activesupport/test/autoloading_fixtures/prepend/sub_class_conflict.rb
new file mode 100644
index 0000000000..090dda3043
--- /dev/null
+++ b/activesupport/test/autoloading_fixtures/prepend/sub_class_conflict.rb
@@ -0,0 +1,2 @@
+class Prepend::SubClassConflict
+end
diff --git a/activesupport/test/caching_test.rb b/activesupport/test/caching_test.rb
index 551235e9e8..73b5a7d2a8 100644
--- a/activesupport/test/caching_test.rb
+++ b/activesupport/test/caching_test.rb
@@ -983,7 +983,7 @@ class MemoryStoreTest < ActiveSupport::TestCase
end
def test_pruning_is_capped_at_a_max_time
- def @cache.delete_entry (*args)
+ def @cache.delete_entry(*args)
sleep(0.01)
super
end
diff --git a/activesupport/test/callbacks_test.rb b/activesupport/test/callbacks_test.rb
index aadc40ab84..22f66978f8 100644
--- a/activesupport/test/callbacks_test.rb
+++ b/activesupport/test/callbacks_test.rb
@@ -224,10 +224,51 @@ module CallbacksTest
define_callbacks :save
end
- class AroundPerson < MySuper
+ class MySlate < MySuper
attr_reader :history
attr_accessor :save_fails
+ def initialize
+ @history = []
+ end
+
+ def save
+ run_callbacks :save do
+ raise "inside save" if save_fails
+ @history << "running"
+ end
+ end
+
+ def no; false; end
+ def yes; true; end
+
+ def method_missing(sym, *)
+ case sym
+ when /^log_(.*)/
+ @history << $1
+ nil
+ when /^wrap_(.*)/
+ @history << "wrap_#$1"
+ yield
+ @history << "unwrap_#$1"
+ nil
+ when /^double_(.*)/
+ @history << "first_#$1"
+ yield
+ @history << "second_#$1"
+ yield
+ @history << "third_#$1"
+ else
+ super
+ end
+ end
+
+ def respond_to_missing?(sym)
+ sym =~ /^(log|wrap)_/ || super
+ end
+ end
+
+ class AroundPerson < MySlate
set_callback :save, :before, :nope, if: :no
set_callback :save, :before, :nope, unless: :yes
set_callback :save, :after, :tweedle
@@ -242,9 +283,6 @@ module CallbacksTest
set_callback :save, :around, :w0tno, if: :no
set_callback :save, :around, :tweedle_deedle
- def no; false; end
- def yes; true; end
-
def nope
@history << "boom"
end
@@ -283,17 +321,6 @@ module CallbacksTest
yield
@history << "tweedle deedle post"
end
-
- def initialize
- @history = []
- end
-
- def save
- run_callbacks :save do
- raise "inside save" if save_fails
- @history << "running"
- end
- end
end
class AroundPersonResult < MySuper
@@ -408,6 +435,32 @@ module CallbacksTest
end
end
+ class DoubleYieldTest < ActiveSupport::TestCase
+ class DoubleYieldModel < MySlate
+ set_callback :save, :around, :wrap_outer
+ set_callback :save, :around, :double_trouble
+ set_callback :save, :around, :wrap_inner
+ end
+
+ def test_double_save
+ double = DoubleYieldModel.new
+ double.save
+ assert_equal [
+ "wrap_outer",
+ "first_trouble",
+ "wrap_inner",
+ "running",
+ "unwrap_inner",
+ "second_trouble",
+ "wrap_inner",
+ "running",
+ "unwrap_inner",
+ "third_trouble",
+ "unwrap_outer",
+ ], double.history
+ end
+ end
+
class CallStackTest < ActiveSupport::TestCase
def test_tidy_call_stack
around = AroundPerson.new
diff --git a/activesupport/test/constantize_test_cases.rb b/activesupport/test/constantize_test_cases.rb
index af2db8c991..32b720bcbb 100644
--- a/activesupport/test/constantize_test_cases.rb
+++ b/activesupport/test/constantize_test_cases.rb
@@ -73,6 +73,11 @@ module ConstantizeTestCases
yield("RaisesNoMethodError")
end
end
+
+ with_autoloading_fixtures do
+ yield("Prepend::SubClassConflict")
+ assert_equal "constant", defined?(Prepend::SubClassConflict)
+ end
end
def run_safe_constantize_tests_on
diff --git a/activesupport/test/core_ext/object/duplicable_test.rb b/activesupport/test/core_ext/object/duplicable_test.rb
index 677e32db1d..c2a1e68f57 100644
--- a/activesupport/test/core_ext/object/duplicable_test.rb
+++ b/activesupport/test/core_ext/object/duplicable_test.rb
@@ -4,9 +4,13 @@ require "active_support/core_ext/object/duplicable"
require "active_support/core_ext/numeric/time"
class DuplicableTest < ActiveSupport::TestCase
- RAISE_DUP = [nil, false, true, :symbol, 1, 2.3, method(:puts)]
- ALLOW_DUP = ["1", Object.new, /foo/, [], {}, Time.now, Class.new, Module.new]
- ALLOW_DUP << BigDecimal.new("4.56")
+ if RUBY_VERSION >= "2.4.0"
+ RAISE_DUP = [method(:puts)]
+ ALLOW_DUP = ["1", Object.new, /foo/, [], {}, Time.now, Class.new, Module.new, BigDecimal.new("4.56"), nil, false, true, :symbol, 1, 2.3]
+ else
+ RAISE_DUP = [nil, false, true, :symbol, 1, 2.3, method(:puts)]
+ ALLOW_DUP = ["1", Object.new, /foo/, [], {}, Time.now, Class.new, Module.new, BigDecimal.new("4.56")]
+ end
def test_duplicable
rubinius_skip "* Method#dup is allowed at the moment on Rubinius\n" \
diff --git a/guides/source/development_dependencies_install.md b/guides/source/development_dependencies_install.md
index 20cd34c182..16c7e782bc 100644
--- a/guides/source/development_dependencies_install.md
+++ b/guides/source/development_dependencies_install.md
@@ -162,6 +162,10 @@ $ cd actionpack
$ bundle exec ruby -Itest path/to/test.rb -n test_name
```
+### Railties Setup
+
+Some Railties tests depend on a JavaScript runtime environment, such as having [Node.js](https://nodejs.org/) installed.
+
### Active Record Setup
Active Record's test suite runs three times: once for SQLite3, once for MySQL, and once for PostgreSQL. We are going to see now how to set up the environment for them.
diff --git a/guides/source/security.md b/guides/source/security.md
index bb67eb75d9..a81a782cf2 100644
--- a/guides/source/security.md
+++ b/guides/source/security.md
@@ -377,7 +377,7 @@ In 2007 there was the first tailor-made trojan which stole information from an I
Having one single place in the admin interface or Intranet, where the input has not been sanitized, makes the entire application vulnerable. Possible exploits include stealing the privileged administrator's cookie, injecting an iframe to steal the administrator's password or installing malicious software through browser security holes to take over the administrator's computer.
-Refer to the Injection section for countermeasures against XSS. It is _recommended to use the SafeErb plugin_ also in an Intranet or administration interface.
+Refer to the Injection section for countermeasures against XSS.
**CSRF** Cross-Site Request Forgery (CSRF), also known as Cross-Site Reference Forgery (XSRF), is a gigantic attack method, it allows the attacker to do everything the administrator or Intranet user may do. As you have already seen above how CSRF works, here are a few examples of what attackers can do in the Intranet or admin interface.
diff --git a/railties/CHANGELOG.md b/railties/CHANGELOG.md
index 0ba220104a..8a1a440fca 100644
--- a/railties/CHANGELOG.md
+++ b/railties/CHANGELOG.md
@@ -1,3 +1,15 @@
+* Add Webpack support in new apps via the --webpack option, which will delegate to the rails/webpacker gem.
+
+ To generate a new app that has Webpack dependencies configured and binstubs for webpack and webpack-watcher:
+
+ rails new myapp --webpack
+
+ To generate a new app that has Webpack + React configured and an example intalled:
+
+ rails new myapp --webpack=react
+
+ *DHH*
+
* Add Yarn support in new apps with a yarn binstub and vendor/package.json. Skippable via --skip-yarn option.
*Liceth Ovalles*, *Guillermo Iguaran*, *DHH*
diff --git a/railties/lib/rails/commands/plugin/plugin_command.rb b/railties/lib/rails/commands/plugin/plugin_command.rb
index 16587ce067..b40ab006af 100644
--- a/railties/lib/rails/commands/plugin/plugin_command.rb
+++ b/railties/lib/rails/commands/plugin/plugin_command.rb
@@ -11,7 +11,7 @@ module Rails
"#{executable} new [options]"
end
- class_option :rc, type: :boolean, default: File.join("~", ".railsrc"),
+ class_option :rc, type: :string, default: File.join("~", ".railsrc"),
desc: "Initialize the plugin command with previous defaults. Uses .railsrc in your home directory by default."
class_option :no_rc, desc: "Skip evaluating .railsrc."
diff --git a/railties/lib/rails/generators/app_base.rb b/railties/lib/rails/generators/app_base.rb
index 576c36fc86..15cc070e35 100644
--- a/railties/lib/rails/generators/app_base.rb
+++ b/railties/lib/rails/generators/app_base.rb
@@ -33,7 +33,7 @@ module Rails
class_option :javascript, type: :string, aliases: "-j",
desc: "Preconfigure for selected JavaScript library"
- class_option :webpack, type: :boolean, default: false,
+ class_option :webpack, type: :string, default: nil,
desc: "Preconfigure for app-like JavaScript with Webpack"
class_option :skip_yarn, type: :boolean, default: false,
@@ -426,7 +426,10 @@ module Rails
end
def run_webpack
- rails_command "webpacker:install" if options[:webpack]
+ if !(webpack = options[:webpack]).nil?
+ rails_command "webpacker:install"
+ rails_command "webpacker:install:#{webpack}" unless webpack == "webpack"
+ end
end
def generate_spring_binstubs
diff --git a/railties/lib/rails/generators/named_base.rb b/railties/lib/rails/generators/named_base.rb
index 45f2fba5b9..70f63dc672 100644
--- a/railties/lib/rails/generators/named_base.rb
+++ b/railties/lib/rails/generators/named_base.rb
@@ -90,10 +90,6 @@ module Rails
@class_path
end
- def namespaced_file_path
- @namespaced_file_path ||= namespaced_class_path.join("/")
- end
-
def namespaced_class_path
@namespaced_class_path ||= [namespaced_path] + @class_path
end
diff --git a/railties/lib/rails/generators/rails/controller/controller_generator.rb b/railties/lib/rails/generators/rails/controller/controller_generator.rb
index ced3c85c00..01214dc919 100644
--- a/railties/lib/rails/generators/rails/controller/controller_generator.rb
+++ b/railties/lib/rails/generators/rails/controller/controller_generator.rb
@@ -16,7 +16,7 @@ module Rails
unless options[:skip_routes]
actions.reverse_each do |action|
# route prepends two spaces onto the front of the string that is passed, this corrects that.
- route generate_routing_code(action)[2..-1]
+ route generate_routing_code(action)
end
end
end
@@ -40,7 +40,7 @@ module Rails
# namespace :bar do
namespace_ladder = regular_class_path.each_with_index.map do |ns, i|
indent(" namespace :#{ns} do\n", i * 2)
- end.join
+ end.join[2..-1]
# Create route
# get 'baz/index'
@@ -54,7 +54,7 @@ module Rails
end.join
# Combine the 3 parts to generate complete route entry
- namespace_ladder + route + end_ladder
+ "#{namespace_ladder}#{route}#{end_ladder}"
end
end
end
diff --git a/railties/test/application/rake_test.rb b/railties/test/application/rake_test.rb
index cd09270df1..d80a45a83f 100644
--- a/railties/test/application/rake_test.rb
+++ b/railties/test/application/rake_test.rb
@@ -387,14 +387,14 @@ module ApplicationTests
bin/rails generate model product name:string;
bin/rails db:migrate db:schema:cache:dump`
end
- assert File.exist?(File.join(app_path, "db", "schema_cache.dump"))
+ assert File.exist?(File.join(app_path, "db", "schema_cache.yml"))
end
def test_rake_clear_schema_cache
Dir.chdir(app_path) do
`bin/rails db:schema:cache:dump db:schema:cache:clear`
end
- assert !File.exist?(File.join(app_path, "db", "schema_cache.dump"))
+ assert !File.exist?(File.join(app_path, "db", "schema_cache.yml"))
end
def test_copy_templates