aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--actionpack/lib/action_controller/metal/http_authentication.rb11
-rw-r--r--actionpack/lib/action_controller/metal/request_forgery_protection.rb4
-rw-r--r--actionview/CHANGELOG.md11
-rw-r--r--actionview/lib/action_view/helpers/form_helper.rb28
-rw-r--r--actionview/lib/action_view/helpers/tags/base.rb6
-rw-r--r--actionview/lib/action_view/helpers/tags/label.rb4
-rw-r--r--actionview/lib/action_view/railtie.rb11
-rw-r--r--actionview/test/template/form_helper/form_with_test.rb408
-rw-r--r--actionview/test/template/form_helper_test.rb32
-rw-r--r--activejob/lib/active_job/queue_adapters/delayed_job_adapter.rb4
-rw-r--r--activejob/test/integration/queuing_test.rb7
-rw-r--r--activerecord/lib/active_record/associations/collection_association.rb8
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb35
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract_adapter.rb13
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb2
-rw-r--r--activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb8
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb5
-rw-r--r--activerecord/lib/active_record/migration/command_recorder.rb2
-rw-r--r--activerecord/lib/active_record/relation.rb1
-rw-r--r--activerecord/lib/active_record/relation/finder_methods.rb14
-rw-r--r--activerecord/lib/active_record/scoping.rb10
-rw-r--r--activerecord/test/cases/associations/inverse_associations_test.rb5
-rw-r--r--activerecord/test/cases/connection_adapters/connection_handler_test.rb32
-rw-r--r--activerecord/test/cases/finder_test.rb31
-rw-r--r--activesupport/CHANGELOG.md8
-rw-r--r--activesupport/lib/active_support/security_utils.rb22
-rw-r--r--activesupport/test/security_utils_test.rb12
-rw-r--r--guides/source/api_app.md6
-rw-r--r--guides/source/configuring.md2
-rw-r--r--guides/source/engines.md6
-rw-r--r--guides/source/layout.html.erb6
-rw-r--r--guides/source/security.md2
-rw-r--r--railties/lib/rails/application.rb12
-rw-r--r--railties/lib/rails/application/configuration.rb7
-rw-r--r--railties/lib/rails/generators/rails/credentials/credentials_generator.rb3
-rw-r--r--railties/test/application/configuration_test.rb62
36 files changed, 565 insertions, 275 deletions
diff --git a/actionpack/lib/action_controller/metal/http_authentication.rb b/actionpack/lib/action_controller/metal/http_authentication.rb
index 0c8132684a..01676f3237 100644
--- a/actionpack/lib/action_controller/metal/http_authentication.rb
+++ b/actionpack/lib/action_controller/metal/http_authentication.rb
@@ -72,10 +72,10 @@ module ActionController
before_action(options.except(:name, :password, :realm)) do
authenticate_or_request_with_http_basic(options[:realm] || "Application") do |name, password|
# This comparison uses & so that it doesn't short circuit and
- # uses `variable_size_secure_compare` so that length information
+ # uses `secure_compare` so that length information
# isn't leaked.
- ActiveSupport::SecurityUtils.variable_size_secure_compare(name, options[:name]) &
- ActiveSupport::SecurityUtils.variable_size_secure_compare(password, options[:password])
+ ActiveSupport::SecurityUtils.secure_compare(name, options[:name]) &
+ ActiveSupport::SecurityUtils.secure_compare(password, options[:password])
end
end
end
@@ -350,10 +350,7 @@ module ActionController
# authenticate_or_request_with_http_token do |token, options|
# # Compare the tokens in a time-constant manner, to mitigate
# # timing attacks.
- # ActiveSupport::SecurityUtils.secure_compare(
- # ::Digest::SHA256.hexdigest(token),
- # ::Digest::SHA256.hexdigest(TOKEN)
- # )
+ # ActiveSupport::SecurityUtils.secure_compare(token, TOKEN)
# end
# end
# end
diff --git a/actionpack/lib/action_controller/metal/request_forgery_protection.rb b/actionpack/lib/action_controller/metal/request_forgery_protection.rb
index 906494ba16..04fadc90e2 100644
--- a/actionpack/lib/action_controller/metal/request_forgery_protection.rb
+++ b/actionpack/lib/action_controller/metal/request_forgery_protection.rb
@@ -369,7 +369,7 @@ module ActionController #:nodoc:
end
def compare_with_real_token(token, session) # :doc:
- ActiveSupport::SecurityUtils.secure_compare(token, real_csrf_token(session))
+ ActiveSupport::SecurityUtils.fixed_length_secure_compare(token, real_csrf_token(session))
end
def valid_per_form_csrf_token?(token, session) # :doc:
@@ -380,7 +380,7 @@ module ActionController #:nodoc:
request.request_method
)
- ActiveSupport::SecurityUtils.secure_compare(token, correct_token)
+ ActiveSupport::SecurityUtils.fixed_length_secure_compare(token, correct_token)
else
false
end
diff --git a/actionview/CHANGELOG.md b/actionview/CHANGELOG.md
index c700cb72ec..e8198926a5 100644
--- a/actionview/CHANGELOG.md
+++ b/actionview/CHANGELOG.md
@@ -1,3 +1,14 @@
+* Change `form_with` to generates ids by default.
+
+ When `form_with` was introduced we disabled the automatic generation of ids
+ that was enabled in `form_for`. This usually is not an good idea since labels don't work
+ when the input doesn't have an id and it made harder to test with Capybara.
+
+ You can still disable the automatic generation of ids setting `config.action_view.form_with_generates_ids`
+ to `false.`
+
+ *Nick Pezza*
+
* Fix issues with `field_error_proc` wrapping `optgroup` and select divider `option`.
Fixes #31088
diff --git a/actionview/lib/action_view/helpers/form_helper.rb b/actionview/lib/action_view/helpers/form_helper.rb
index 6d2ace8cf8..f24e83ad9a 100644
--- a/actionview/lib/action_view/helpers/form_helper.rb
+++ b/actionview/lib/action_view/helpers/form_helper.rb
@@ -478,6 +478,8 @@ module ActionView
mattr_accessor :form_with_generates_remote_forms, default: true
+ mattr_accessor :form_with_generates_ids, default: true
+
# Creates a form tag based on mixing URLs, scopes, or models.
#
# # Using just a URL:
@@ -640,16 +642,6 @@ 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
@@ -746,7 +738,7 @@ module ActionView
# end
def form_with(model: nil, scope: nil, url: nil, format: nil, **options)
options[:allow_method_names_outside_object] = true
- options[:skip_default_ids] = true
+ options[:skip_default_ids] = !form_with_generates_ids
if model
url ||= polymorphic_path(model, format: format)
@@ -1044,16 +1036,6 @@ 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
@@ -1072,7 +1054,7 @@ module ActionView
# FormOptionsHelper#collection_select and DateHelper#datetime_select.
def fields(scope = nil, model: nil, **options, &block)
options[:allow_method_names_outside_object] = true
- options[:skip_default_ids] = true
+ options[:skip_default_ids] = !form_with_generates_ids
if model
scope ||= model_name_from_record_or_class(model).param_key
@@ -1985,7 +1967,7 @@ module ActionView
# See the docs for the <tt>ActionView::FormHelper.fields</tt> helper method.
def fields(scope = nil, model: nil, **options, &block)
options[:allow_method_names_outside_object] = true
- options[:skip_default_ids] = true
+ options[:skip_default_ids] = !FormHelper.form_with_generates_ids
convert_to_legacy_options(options)
diff --git a/actionview/lib/action_view/helpers/tags/base.rb b/actionview/lib/action_view/helpers/tags/base.rb
index 8934a9894c..fed908fcdb 100644
--- a/actionview/lib/action_view/helpers/tags/base.rb
+++ b/actionview/lib/action_view/helpers/tags/base.rb
@@ -97,7 +97,7 @@ module ActionView
index = name_and_id_index(options)
options["name"] = options.fetch("name") { tag_name(options["multiple"], index) }
- unless skip_default_ids?
+ if generate_ids?
options["id"] = options.fetch("id") { tag_id(index) }
if namespace = options.delete("namespace")
options["id"] = options["id"] ? "#{namespace}_#{options['id']}" : namespace
@@ -183,8 +183,8 @@ module ActionView
end
end
- def skip_default_ids?
- @skip_default_ids
+ def generate_ids?
+ !@skip_default_ids
end
end
end
diff --git a/actionview/lib/action_view/helpers/tags/label.rb b/actionview/lib/action_view/helpers/tags/label.rb
index 56b48bbd62..02bd099784 100644
--- a/actionview/lib/action_view/helpers/tags/label.rb
+++ b/actionview/lib/action_view/helpers/tags/label.rb
@@ -75,10 +75,6 @@ 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/lib/action_view/railtie.rb b/actionview/lib/action_view/railtie.rb
index b22347c55c..73dfb267bb 100644
--- a/actionview/lib/action_view/railtie.rb
+++ b/actionview/lib/action_view/railtie.rb
@@ -22,8 +22,15 @@ module ActionView
initializer "action_view.form_with_generates_remote_forms" do |app|
ActiveSupport.on_load(:action_view) do
form_with_generates_remote_forms = app.config.action_view.delete(:form_with_generates_remote_forms)
- unless form_with_generates_remote_forms.nil?
- ActionView::Helpers::FormHelper.form_with_generates_remote_forms = form_with_generates_remote_forms
+ ActionView::Helpers::FormHelper.form_with_generates_remote_forms = form_with_generates_remote_forms
+ end
+ end
+
+ initializer "action_view.form_with_generates_ids" do |app|
+ ActiveSupport.on_load(:action_view) do
+ form_with_generates_ids = app.config.action_view.delete(:form_with_generates_ids)
+ unless form_with_generates_ids.nil?
+ ActionView::Helpers::FormHelper.form_with_generates_ids = form_with_generates_ids
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 c7d49070ce..ad23d31d41 100644
--- a/actionview/test/template/form_helper/form_with_test.rb
+++ b/actionview/test/template/form_helper/form_with_test.rb
@@ -314,17 +314,45 @@ 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' value='Hello World' id='post_title' />" \
+ "<textarea name='post[body]' id='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' value='1' id='post_secret' />" \
+ "<select name='post[category]' id='post_category'><option value='animal'>animal</option>\n<option value='economy'>economy</option>\n<option value='sports'>sports</option></select>" \
+ "<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>"
+ end
+
+ assert_dom_equal expected, output_buffer
+ end
+
+ def test_form_with_not_outputting_ids
+ old_value = ActionView::Helpers::FormHelper.form_with_generates_ids
+ ActionView::Helpers::FormHelper.form_with_generates_ids = false
+
+ form_with(model: @post, id: "create-post") do |f|
+ concat f.label(:title) { "The Title" }
+ concat f.text_field(:title)
+ concat f.text_area(:body)
+ concat f.check_box(:secret)
+ concat f.select(:category, %w( animal economy sports ))
+ concat f.submit("Create post")
+ end
+
+ expected = whole_form("/posts/123", "create-post", method: "patch") do
+ "<label>The Title</label>" \
"<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' value='1' />" \
"<select name='post[category]'><option value='animal'>animal</option>\n<option value='economy'>economy</option>\n<option value='sports'>sports</option></select>" \
- "<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>"
+ "<input name='commit' data-disable-with='Create post' type='submit' value='Create post' />"
end
assert_dom_equal expected, output_buffer
+ ensure
+ ActionView::Helpers::FormHelper.form_with_generates_ids = old_value
end
def test_form_with_only_url_on_create
@@ -335,7 +363,7 @@ class FormWithActsLikeFormForTest < FormWithTest
expected = whole_form("/posts") do
'<label for="title">Label me</label>' \
- '<input type="text" name="title">'
+ '<input type="text" name="title" id="title">'
end
assert_dom_equal expected, output_buffer
@@ -349,7 +377,7 @@ class FormWithActsLikeFormForTest < FormWithTest
expected = whole_form("/posts/123") do
'<label for="title">Label me</label>' \
- '<input type="text" name="title">'
+ '<input type="text" name="title" id="title">'
end
assert_dom_equal expected, output_buffer
@@ -361,7 +389,7 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/posts/123") do
- '<input type="text" name="no_model_to_back_this_badboy">'
+ '<input type="text" name="no_model_to_back_this_badboy" id="no_model_to_back_this_badboy" >'
end
assert_dom_equal expected, output_buffer
@@ -373,7 +401,7 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/posts/123", method: :patch) do
- '<input type="text" name="post[this_dont_exist_on_post]">'
+ '<input type="text" name="post[this_dont_exist_on_post]" id="post_this_dont_exist_on_post" >'
end
assert_dom_equal expected, output_buffer
@@ -391,8 +419,8 @@ class FormWithActsLikeFormForTest < FormWithTest
end.new
form_with(model: obj, scope: "other_name", url: "/", id: "edit-other-name") do |f|
- assert_dom_equal '<input type="hidden" name="other_name[private_property]">', f.hidden_field(:private_property)
- assert_dom_equal '<input type="hidden" name="other_name[protected_property]">', f.hidden_field(:protected_property)
+ assert_dom_equal '<input type="hidden" name="other_name[private_property]" id="other_name_private_property">', f.hidden_field(:private_property)
+ assert_dom_equal '<input type="hidden" name="other_name[protected_property]" id="other_name_protected_property">', f.hidden_field(:protected_property)
end
end
@@ -459,7 +487,7 @@ class FormWithActsLikeFormForTest < FormWithTest
"<label for='post_active_false'>" \
"<input checked='checked' name='post[active]' type='radio' value='false' id='post_active_false' />" \
"false</label>" \
- "<input name='post[id]' type='hidden' value='1' />"
+ "<input name='post[id]' type='hidden' value='1' id='post_id' />"
end
assert_dom_equal expected, output_buffer
@@ -557,7 +585,7 @@ class FormWithActsLikeFormForTest < FormWithTest
"<label for='post_tag_ids_3'>" \
"<input checked='checked' name='post[tag_ids][]' type='checkbox' value='3' id='post_tag_ids_3' />" \
"Tag 3</label>" \
- "<input name='post[id]' type='hidden' value='1' />"
+ "<input name='post[id]' type='hidden' value='1' id='post_id' />"
end
assert_dom_equal expected, output_buffer
@@ -587,7 +615,7 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/posts/123", "create-post", method: "patch", multipart: true) do
- "<input name='post[file]' type='file' />"
+ "<input name='post[file]' type='file' id='post_file' />"
end
assert_dom_equal expected, output_buffer
@@ -601,7 +629,7 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/posts/123", method: "patch", multipart: true) do
- "<input name='post[comment][file]' type='file' />"
+ "<input name='post[comment][file]' type='file' id='post_comment_file'/>"
end
assert_dom_equal expected, output_buffer
@@ -640,7 +668,7 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/posts/44", method: "patch") do
- "<input name='post[title]' type='text' value='And his name will be forty and four.' />" \
+ "<input name='post[title]' type='text' value='And his name will be forty and four.' id='post_title' />" \
"<input name='commit' data-disable-with='Edit post' type='submit' value='Edit post' />"
end
@@ -658,10 +686,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]' value='Hello World' type='text' />" \
- "<textarea name='other_name[body]'>\nBack to the hill and over it again!</textarea>" \
+ "<input name='other_name[title]' value='Hello World' type='text' id='other_name_title' />" \
+ "<textarea name='other_name[body]' id='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' value='1' type='checkbox' />" \
+ "<input name='other_name[secret]' checked='checked' value='1' type='checkbox' id='other_name_secret' />" \
"<input name='commit' value='Create post' data-disable-with='Create post' type='submit' />"
end
@@ -676,10 +704,10 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/", "create-post", method: "delete") do
- "<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[title]' type='text' value='Hello World' id='post_title' />" \
+ "<textarea name='post[body]' id='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' value='1' />"
+ "<input name='post[secret]' checked='checked' type='checkbox' value='1' id='post_secret'/>"
end
assert_dom_equal expected, output_buffer
@@ -693,10 +721,10 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/", "create-post", method: "delete") do
- "<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[title]' type='text' value='Hello World' id='post_title' />" \
+ "<textarea name='post[body]' id='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' value='1' />"
+ "<input name='post[secret]' checked='checked' type='checkbox' value='1' id='post_secret' />"
end
assert_dom_equal expected, output_buffer
@@ -710,7 +738,7 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/search", "search-post", method: "get") do
- "<input name='post[title]' type='search' />"
+ "<input name='post[title]' type='search' id='post_title' />"
end
assert_dom_equal expected, output_buffer
@@ -724,10 +752,10 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/", "create-post", method: "patch") do
- "<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[title]' type='text' value='Hello World' id='post_title' />" \
+ "<textarea name='post[body]' id='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' value='1' />"
+ "<input name='post[secret]' checked='checked' type='checkbox' value='1' id='post_secret' />"
end
assert_dom_equal expected, output_buffer
@@ -744,10 +772,10 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/", "create-post", method: "patch", local: true) do
- "<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[title]' type='text' value='Hello World' id='post_title' />" \
+ "<textarea name='post[body]' id='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' value='1' />"
+ "<input name='post[secret]' checked='checked' type='checkbox' value='1' id='post_secret' />"
end
assert_dom_equal expected, output_buffer
@@ -761,7 +789,7 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/", skip_enforcing_utf8: true) do
- "<input name='post[title]' type='text' value='Hello World' />"
+ "<input name='post[title]' type='text' value='Hello World' id='post_title' />"
end
assert_dom_equal expected, output_buffer
@@ -773,7 +801,7 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/", skip_enforcing_utf8: false) do
- "<input name='post[title]' type='text' value='Hello World' />"
+ "<input name='post[title]' type='text' value='Hello World' id='post_title' />"
end
assert_dom_equal expected, output_buffer
@@ -787,10 +815,10 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/", "create-post") do
- "<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[title]' type='text' value='Hello World' id='post_title' />" \
+ "<textarea name='post[body]' id='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' value='1' />"
+ "<input name='post[secret]' checked='checked' type='checkbox' value='1' id='post_secret' />"
end
assert_dom_equal expected, output_buffer
@@ -806,10 +834,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' value='Hello World' />" \
- "<textarea name='post[123][body]'>\nBack to the hill and over it again!</textarea>" \
+ "<input name='post[123][title]' type='text' value='Hello World' id='post_123_title' />" \
+ "<textarea name='post[123][body]' id='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' value='1' />"
+ "<input name='post[123][secret]' checked='checked' type='checkbox' value='1' id='post_123_secret' />"
end
assert_dom_equal expected, output_buffer
@@ -823,10 +851,10 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/posts/123", method: "patch") do
- "<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[][title]' type='text' value='Hello World' id='post__title' />" \
+ "<textarea name='post[][body]' id='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' value='1' />"
+ "<input name='post[][secret]' checked='checked' type='checkbox' value='1' id='post__secret' />"
end
assert_dom_equal expected, output_buffer
@@ -841,7 +869,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' value='' /></div>" \
+ "<div class='field_with_errors'><input name='post[author_name]' type='text' value='' id='post_author_name' /></div>" \
"<input name='commit' data-disable-with='Create post' type='submit' value='Create post' />"
end
@@ -859,7 +887,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' value='' /></div>" \
+ "<div class='field_with_errors'><input name='post[author_name]' type='text' value='' id='post_author_name' /></div>" \
"<input name='commit' data-disable-with='Create post' type='submit' value='Create post' />"
end
@@ -947,7 +975,7 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/posts/123", method: :patch) do
- '<input type="text" name="post[comment][dont_exist_on_model]">'
+ '<input type="text" name="post[comment][dont_exist_on_model]" id="post_comment_dont_exist_on_model" >'
end
assert_dom_equal expected, output_buffer
@@ -967,7 +995,7 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form do
- '<input name="posts[post][0][comment][1][dont_exist_on_model]" type="text">'
+ '<input name="posts[post][0][comment][1][dont_exist_on_model]" type="text" id="posts_post_0_comment_1_dont_exist_on_model" >'
end
assert_dom_equal expected, output_buffer
@@ -982,7 +1010,7 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/posts/123", method: "patch") do
- "<input name='post[comment][body]' type='text' value='Hello World' />"
+ "<input name='post[comment][body]' type='text' value='Hello World' id='post_comment_body' />"
end
assert_dom_equal expected, output_buffer
@@ -1002,7 +1030,7 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form do
- "<input name='posts[post][0][comment][1][name]' type='text' value='comment #1' />"
+ "<input name='posts[post][0][comment][1][name]' type='text' value='comment #1' id='posts_post_0_comment_1_name' />"
end
assert_dom_equal expected, output_buffer
@@ -1017,8 +1045,8 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/posts/123", method: "patch") do
- "<input name='post[123][title]' type='text' value='Hello World' />" \
- "<input name='post[123][comment][][name]' type='text' value='new comment' />"
+ "<input name='post[123][title]' type='text' value='Hello World' id='post_123_title' />" \
+ "<input name='post[123][comment][][name]' type='text' value='new comment' id='post_123_comment__name' />"
end
assert_dom_equal expected, output_buffer
@@ -1033,8 +1061,8 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/posts/123", method: "patch") do
- "<input name='post[1][title]' type='text' value='Hello World' />" \
- "<input name='post[1][comment][1][name]' type='text' value='new comment' />"
+ "<input name='post[1][title]' type='text' value='Hello World' id='post_1_title' />" \
+ "<input name='post[1][comment][1][name]' type='text' value='new comment' id='post_1_comment_1_name' />"
end
assert_dom_equal expected, output_buffer
@@ -1048,7 +1076,7 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/posts/123", method: "patch") do
- "<input name='post[1][comment][title]' type='text' value='Hello World' />"
+ "<input name='post[1][comment][title]' type='text' value='Hello World' id='post_1_comment_title' />"
end
assert_dom_equal expected, output_buffer
@@ -1062,7 +1090,7 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/posts/123", method: "patch") do
- "<input name='post[1][comment][5][title]' type='text' value='Hello World' />"
+ "<input name='post[1][comment][5][title]' type='text' value='Hello World' id='post_1_comment_5_title' />"
end
assert_dom_equal expected, output_buffer
@@ -1076,7 +1104,7 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/posts/123", method: "patch") do
- "<input name='post[123][comment][title]' type='text' value='Hello World' />"
+ "<input name='post[123][comment][title]' type='text' value='Hello World' id='post_123_comment_title' />"
end
assert_dom_equal expected, output_buffer
@@ -1090,7 +1118,7 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/posts/123", method: "patch") do
- "<input name='post[comment][5][title]' type='radio' value='hello' />"
+ "<input name='post[comment][5][title]' type='radio' value='hello' id='post_comment_5_title_hello' />"
end
assert_dom_equal expected, output_buffer
@@ -1104,7 +1132,7 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/posts/123", method: "patch") do
- "<input name='post[123][comment][123][title]' type='text' value='Hello World' />"
+ "<input name='post[123][comment][123][title]' type='text' value='Hello World' id='post_123_comment_123_title' />"
end
assert_dom_equal expected, output_buffer
@@ -1124,9 +1152,9 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/posts/123", method: "patch") do
- "<input name='post[123][comment][5][title]' type='text' value='Hello World' />"
+ "<input name='post[123][comment][5][title]' type='text' value='Hello World' id='post_123_comment_5_title' />"
end + whole_form("/posts/123", method: "patch") do
- "<input name='post[1][comment][123][title]' type='text' value='Hello World' />"
+ "<input name='post[1][comment][123][title]' type='text' value='Hello World' id='post_1_comment_123_title' />"
end
assert_dom_equal expected, output_buffer
@@ -1143,8 +1171,8 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/posts/123", method: "patch") do
- '<input name="post[title]" type="text" value="Hello World" />' \
- '<input name="post[author_attributes][name]" type="text" value="new author" />'
+ '<input name="post[title]" type="text" value="Hello World" id="post_title" />' \
+ '<input name="post[author_attributes][name]" type="text" value="new author" id="post_author_attributes_name" />'
end
assert_dom_equal expected, output_buffer
@@ -1170,9 +1198,9 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/posts/123", method: "patch") do
- '<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[title]" type="text" value="Hello World" id="post_title" />' \
+ '<input name="post[author_attributes][name]" type="text" value="author #321" id="post_author_attributes_name" />' \
+ '<input name="post[author_attributes][id]" type="hidden" value="321" id="post_author_attributes_id" />'
end
assert_dom_equal expected, output_buffer
@@ -1189,9 +1217,9 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/posts/123", method: "patch") do
- '<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[title]" type="text" value="Hello World" id="post_title" />' \
+ '<input name="post[author_attributes][name]" type="text" value="author #321" id="post_author_attributes_name" />' \
+ '<input name="post[author_attributes][id]" type="hidden" value="321" id="post_author_attributes_id" />'
end
assert_dom_equal expected, output_buffer
@@ -1208,8 +1236,8 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/posts/123", method: "patch") do
- '<input name="post[title]" type="text" value="Hello World" />' \
- '<input name="post[author_attributes][name]" type="text" value="author #321" />'
+ '<input name="post[title]" type="text" value="Hello World" id="post_title" />' \
+ '<input name="post[author_attributes][name]" type="text" value="author #321" id="post_author_attributes_name" />'
end
assert_dom_equal expected, output_buffer
@@ -1226,8 +1254,8 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/posts/123", method: "patch") do
- '<input name="post[title]" type="text" value="Hello World" />' \
- '<input name="post[author_attributes][name]" type="text" value="author #321" />'
+ '<input name="post[title]" type="text" value="Hello World" id="post_title" />' \
+ '<input name="post[author_attributes][name]" type="text" value="author #321" id="post_author_attributes_name" />'
end
assert_dom_equal expected, output_buffer
@@ -1244,9 +1272,9 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/posts/123", method: "patch") do
- '<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[title]" type="text" value="Hello World" id="post_title" />' \
+ '<input name="post[author_attributes][name]" type="text" value="author #321" id="post_author_attributes_name" />' \
+ '<input name="post[author_attributes][id]" type="hidden" value="321" id="post_author_attributes_id" />'
end
assert_dom_equal expected, output_buffer
@@ -1264,9 +1292,9 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/posts/123", method: "patch") do
- '<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" />'
+ '<input name="post[title]" type="text" value="Hello World" id="post_title" />' \
+ '<input name="post[author_attributes][id]" type="hidden" value="321" id="post_author_attributes_id" />' \
+ '<input name="post[author_attributes][name]" type="text" value="author #321" id="post_author_attributes_name" />'
end
assert_dom_equal expected, output_buffer
@@ -1285,11 +1313,11 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/posts/123", method: "patch") do
- '<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" />'
+ '<input name="post[title]" type="text" value="Hello World" id="post_title" />' \
+ '<input name="post[comments_attributes][0][name]" type="text" value="comment #1" id="post_comments_attributes_0_name" />' \
+ '<input name="post[comments_attributes][0][id]" type="hidden" value="1" id="post_comments_attributes_0_id" />' \
+ '<input name="post[comments_attributes][1][name]" type="text" value="comment #2" id="post_comments_attributes_1_name" />' \
+ '<input name="post[comments_attributes][1][id]" type="hidden" value="2" id="post_comments_attributes_1_id" />'
end
assert_dom_equal expected, output_buffer
@@ -1312,11 +1340,11 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/posts/123", method: "patch") do
- '<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" />'
+ '<input name="post[title]" type="text" value="Hello World" id="post_title" />' \
+ '<input name="post[author_attributes][name]" type="text" value="author #321" id="post_author_attributes_name" />' \
+ '<input name="post[author_attributes][id]" type="hidden" value="321" id="post_author_attributes_id" />' \
+ '<input name="post[comments_attributes][0][name]" type="text" value="comment #1" id="post_comments_attributes_0_name" />' \
+ '<input name="post[comments_attributes][1][name]" type="text" value="comment #2" id="post_comments_attributes_1_name" />'
end
assert_dom_equal expected, output_buffer
@@ -1339,10 +1367,10 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/posts/123", method: "patch") do
- '<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" />'
+ '<input name="post[title]" type="text" value="Hello World" id="post_title" />' \
+ '<input name="post[author_attributes][name]" type="text" value="author #321" id="post_author_attributes_name" />' \
+ '<input name="post[comments_attributes][0][name]" type="text" value="comment #1" id="post_comments_attributes_0_name" />' \
+ '<input name="post[comments_attributes][1][name]" type="text" value="comment #2" id="post_comments_attributes_1_name" />'
end
assert_dom_equal expected, output_buffer
@@ -1365,11 +1393,11 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/posts/123", method: "patch") do
- '<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" />'
+ '<input name="post[title]" type="text" value="Hello World" id="post_title" />' \
+ '<input name="post[author_attributes][name]" type="text" value="author #321" id="post_author_attributes_name" />' \
+ '<input name="post[author_attributes][id]" type="hidden" value="321" id="post_author_attributes_id" />' \
+ '<input name="post[comments_attributes][0][name]" type="text" value="comment #1" id="post_comments_attributes_0_name" />' \
+ '<input name="post[comments_attributes][1][name]" type="text" value="comment #2" id="post_comments_attributes_1_name" />'
end
assert_dom_equal expected, output_buffer
@@ -1388,11 +1416,11 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/posts/123", method: "patch") do
- '<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" />'
+ '<input name="post[title]" type="text" value="Hello World" id="post_title" />' \
+ '<input name="post[comments_attributes][0][name]" type="text" value="comment #1" id="post_comments_attributes_0_name" />' \
+ '<input name="post[comments_attributes][0][id]" type="hidden" value="1" id="post_comments_attributes_0_id" />' \
+ '<input name="post[comments_attributes][1][name]" type="text" value="comment #2" id="post_comments_attributes_1_name" />' \
+ '<input name="post[comments_attributes][1][id]" type="hidden" value="2" id="post_comments_attributes_1_id" />'
end
assert_dom_equal expected, output_buffer
@@ -1412,11 +1440,11 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/posts/123", method: "patch") do
- '<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" />'
+ '<input name="post[title]" type="text" value="Hello World" id="post_title" />' \
+ '<input name="post[comments_attributes][0][id]" type="hidden" value="1" id="post_comments_attributes_0_id" />' \
+ '<input name="post[comments_attributes][0][name]" type="text" value="comment #1" id="post_comments_attributes_0_name" />' \
+ '<input name="post[comments_attributes][1][id]" type="hidden" value="2" id="post_comments_attributes_1_id" />' \
+ '<input name="post[comments_attributes][1][name]" type="text" value="comment #2" id="post_comments_attributes_1_name" />'
end
assert_dom_equal expected, output_buffer
@@ -1435,9 +1463,9 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/posts/123", method: "patch") do
- '<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" />'
+ '<input name="post[title]" type="text" value="Hello World" id="post_title" />' \
+ '<input name="post[comments_attributes][0][name]" type="text" value="new comment" id="post_comments_attributes_0_name" />' \
+ '<input name="post[comments_attributes][1][name]" type="text" value="new comment" id="post_comments_attributes_1_name" />'
end
assert_dom_equal expected, output_buffer
@@ -1456,10 +1484,10 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/posts/123", method: "patch") do
- '<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" />'
+ '<input name="post[title]" type="text" value="Hello World" id="post_title" />' \
+ '<input name="post[comments_attributes][0][name]" type="text" value="comment #321" id="post_comments_attributes_0_name" />' \
+ '<input name="post[comments_attributes][0][id]" type="hidden" value="321" id="post_comments_attributes_0_id"/>' \
+ '<input name="post[comments_attributes][1][name]" type="text" value="new comment" id="post_comments_attributes_1_name" />'
end
assert_dom_equal expected, output_buffer
@@ -1474,7 +1502,7 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/posts/123", method: "patch") do
- '<input name="post[title]" type="text" value="Hello World" />'
+ '<input name="post[title]" type="text" value="Hello World" id="post_title" />'
end
assert_dom_equal expected, output_buffer
@@ -1491,11 +1519,11 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/posts/123", method: "patch") do
- '<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" />'
+ '<input name="post[title]" type="text" value="Hello World" id="post_title" />' \
+ '<input name="post[comments_attributes][0][name]" type="text" value="comment #1" id="post_comments_attributes_0_name" />' \
+ '<input name="post[comments_attributes][0][id]" type="hidden" value="1" id="post_comments_attributes_0_id" />' \
+ '<input name="post[comments_attributes][1][name]" type="text" value="comment #2" id="post_comments_attributes_1_name" />' \
+ '<input name="post[comments_attributes][1][id]" type="hidden" value="2" id="post_comments_attributes_1_id" />'
end
assert_dom_equal expected, output_buffer
@@ -1512,11 +1540,11 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/posts/123", method: "patch") do
- '<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" />'
+ '<input name="post[title]" type="text" value="Hello World" id="post_title" />' \
+ '<input name="post[comments_attributes][0][name]" type="text" value="comment #1" id="post_comments_attributes_0_name" />' \
+ '<input name="post[comments_attributes][0][id]" type="hidden" value="1" id="post_comments_attributes_0_id" />' \
+ '<input name="post[comments_attributes][1][name]" type="text" value="comment #2" id="post_comments_attributes_1_name" />' \
+ '<input name="post[comments_attributes][1][id]" type="hidden" value="2" id="post_comments_attributes_1_id" />'
end
assert_dom_equal expected, output_buffer
@@ -1547,11 +1575,11 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/posts/123", method: "patch") do
- '<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" />'
+ '<input name="post[title]" type="text" value="Hello World" id="post_title" />' \
+ '<input name="post[comments_attributes][0][name]" type="text" value="comment #1" id="post_comments_attributes_0_name" />' \
+ '<input name="post[comments_attributes][0][id]" type="hidden" value="1" id="post_comments_attributes_0_id" />' \
+ '<input name="post[comments_attributes][1][name]" type="text" value="comment #2" id="post_comments_attributes_1_name" />' \
+ '<input name="post[comments_attributes][1][id]" type="hidden" value="2" id="post_comments_attributes_1_id" />'
end
assert_dom_equal expected, output_buffer
@@ -1570,10 +1598,10 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/posts/123", method: "patch") do
- '<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" />'
+ '<input name="post[title]" type="text" value="Hello World" id="post_title" />' \
+ '<input name="post[comments_attributes][0][name]" type="text" value="comment #321" id="post_comments_attributes_0_name" />' \
+ '<input name="post[comments_attributes][0][id]" type="hidden" value="321" id="post_comments_attributes_0_id" />' \
+ '<input name="post[comments_attributes][1][name]" type="text" value="new comment" id="post_comments_attributes_1_name" />'
end
assert_dom_equal expected, output_buffer
@@ -1590,8 +1618,8 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/posts/123", method: "patch") do
- '<input name="post[comments_attributes][abc][name]" type="text" value="comment #321" />' \
- '<input name="post[comments_attributes][abc][id]" type="hidden" value="321" />'
+ '<input name="post[comments_attributes][abc][name]" type="text" value="comment #321" id="post_comments_attributes_abc_name" />' \
+ '<input name="post[comments_attributes][abc][id]" type="hidden" value="321" id="post_comments_attributes_abc_id" />'
end
assert_dom_equal expected, output_buffer
@@ -1607,8 +1635,8 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/posts/123", method: "patch") do
- '<input name="post[comments_attributes][abc][name]" type="text" value="comment #321" />' \
- '<input name="post[comments_attributes][abc][id]" type="hidden" value="321" />'
+ '<input name="post[comments_attributes][abc][name]" type="text" value="comment #321" id="post_comments_attributes_abc_name" />' \
+ '<input name="post[comments_attributes][abc][id]" type="hidden" value="321" id="post_comments_attributes_abc_id" />'
end
assert_dom_equal expected, output_buffer
@@ -1630,8 +1658,8 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/posts/123", method: "patch") do
- '<input name="post[comments_attributes][abc][name]" type="text" value="comment #321" />' \
- '<input name="post[comments_attributes][abc][id]" type="hidden" value="321" />'
+ '<input name="post[comments_attributes][abc][name]" type="text" value="comment #321" id="post_comments_attributes_abc_name" />' \
+ '<input name="post[comments_attributes][abc][id]" type="hidden" value="321" id="post_comments_attributes_abc_id" />'
end
assert_dom_equal expected, output_buffer
@@ -1716,18 +1744,18 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/posts/123", method: "patch") do
- '<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" />'
+ '<input name="post[comments_attributes][0][name]" type="text" value="comment #321" id="post_comments_attributes_0_name" />' \
+ '<input name="post[comments_attributes][0][relevances_attributes][0][value]" type="text" value="commentrelevance #314" id="post_comments_attributes_0_relevances_attributes_0_value" />' \
+ '<input name="post[comments_attributes][0][relevances_attributes][0][id]" type="hidden" value="314" id="post_comments_attributes_0_relevances_attributes_0_id"/>' \
+ '<input name="post[comments_attributes][0][id]" type="hidden" value="321" id="post_comments_attributes_0_id"/>' \
+ '<input name="post[tags_attributes][0][value]" type="text" value="tag #123" id="post_tags_attributes_0_value"/>' \
+ '<input name="post[tags_attributes][0][relevances_attributes][0][value]" type="text" value="tagrelevance #3141" id="post_tags_attributes_0_relevances_attributes_0_value"/>' \
+ '<input name="post[tags_attributes][0][relevances_attributes][0][id]" type="hidden" value="3141" id="post_tags_attributes_0_relevances_attributes_0_id"/>' \
+ '<input name="post[tags_attributes][0][id]" type="hidden" value="123" id="post_tags_attributes_0_id"/>' \
+ '<input name="post[tags_attributes][1][value]" type="text" value="tag #456" id="post_tags_attributes_1_value"/>' \
+ '<input name="post[tags_attributes][1][relevances_attributes][0][value]" type="text" value="tagrelevance #31415" id="post_tags_attributes_1_relevances_attributes_0_value"/>' \
+ '<input name="post[tags_attributes][1][relevances_attributes][0][id]" type="hidden" value="31415" id="post_tags_attributes_1_relevances_attributes_0_id"/>' \
+ '<input name="post[tags_attributes][1][id]" type="hidden" value="456" id="post_tags_attributes_1_id"/>'
end
assert_dom_equal expected, output_buffer
@@ -1743,7 +1771,7 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/posts/123", method: "patch") do
- '<input name="post[author_attributes][name]" type="text" value="hash backed author" />'
+ '<input name="post[author_attributes][name]" type="text" value="hash backed author" id="post_author_attributes_name" />'
end
assert_dom_equal expected, output_buffer
@@ -1757,10 +1785,10 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected =
- "<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[title]' type='text' value='Hello World' id='post_title' />" \
+ "<textarea name='post[body]' id='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' value='1' />"
+ "<input name='post[secret]' checked='checked' type='checkbox' value='1' id='post_secret' />"
assert_dom_equal expected, output_buffer
end
@@ -1773,10 +1801,10 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected =
- "<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][title]' type='text' value='Hello World' id='post_123_title' />" \
+ "<textarea name='post[123][body]' id='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' value='1' />"
+ "<input name='post[123][secret]' checked='checked' type='checkbox' value='1' id='post_123_secret' />"
assert_dom_equal expected, output_buffer
end
@@ -1789,10 +1817,10 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected =
- "<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[][title]' type='text' value='Hello World' id='post__title' />" \
+ "<textarea name='post[][body]' id='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' value='1' />"
+ "<input name='post[][secret]' checked='checked' type='checkbox' value='1' id='post__secret' />"
assert_dom_equal expected, output_buffer
end
@@ -1805,10 +1833,10 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected =
- "<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][title]' type='text' value='Hello World' id='post_abc_title' />" \
+ "<textarea name='post[abc][body]' id='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' value='1' />"
+ "<input name='post[abc][secret]' checked='checked' type='checkbox' value='1' id='post_abc_secret' />"
assert_dom_equal expected, output_buffer
end
@@ -1821,10 +1849,10 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected =
- "<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[title]' type='text' value='Hello World' id='post_title' />" \
+ "<textarea name='post[body]' id='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' value='1' />"
+ "<input name='post[secret]' checked='checked' type='checkbox' value='1' id='post_secret' />"
assert_dom_equal expected, output_buffer
end
@@ -1837,10 +1865,10 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected =
- "<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[title]' type='text' value='Hello World' id='post_title' />" \
+ "<textarea name='post[body]' id='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' value='1' />"
+ "<input name='post[secret]' checked='checked' type='checkbox' value='1' id='post_secret' />"
assert_dom_equal expected, output_buffer
end
@@ -1852,7 +1880,7 @@ class FormWithActsLikeFormForTest < FormWithTest
end
assert_dom_equal "<label for=\"author_post_title\">Title</label>" \
- "<input name='author[post][title]' type='text' value='Hello World' />",
+ "<input name='author[post][title]' type='text' value='Hello World' id='author_post_title' id='author_post_1_title' />",
output_buffer
end
@@ -1863,7 +1891,7 @@ class FormWithActsLikeFormForTest < FormWithTest
end
assert_dom_equal "<label for=\"author_post_1_title\">Title</label>" \
- "<input name='author[post][1][title]' type='text' value='Hello World' />",
+ "<input name='author[post][1][title]' type='text' value='Hello World' id='author_post_1_title' />",
output_buffer
end
@@ -1882,10 +1910,10 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/posts/123", "create-post", method: "patch") do
- "<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[title]' type='text' value='Hello World' id='post_title' />" \
+ "<textarea name='post[body]' id='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' value='1' />"
+ "<input name='parent_post[secret]' checked='checked' type='checkbox' value='1' id='parent_post_secret' />"
end
assert_dom_equal expected, output_buffer
@@ -1902,9 +1930,9 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/posts/123", "create-post", method: "patch") do
- "<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' />"
+ "<input name='post[title]' type='text' value='Hello World' id='post_title' />" \
+ "<textarea name='post[body]' id='post_body'>\nBack to the hill and over it again!</textarea>" \
+ "<input name='post[comment][name]' type='text' value='new comment' id='post_comment_name' />"
end
assert_dom_equal expected, output_buffer
@@ -1918,7 +1946,7 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/posts/123", method: "patch") do
- "<input name='post[category][name]' type='text' />"
+ "<input name='post[category][name]' type='text' id='post_category_name' />"
end
assert_dom_equal expected, output_buffer
@@ -1942,9 +1970,9 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/posts/123", method: "patch") do
- "<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/>"
+ "<label for='title'>Title:</label> <input name='post[title]' type='text' value='Hello World' id='post_title'/><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' value='1' id='post_secret' /><br/>"
end
assert_dom_equal expected, output_buffer
@@ -1961,9 +1989,9 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/posts/123", method: "patch") do
- "<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/>"
+ "<label for='title'>Title:</label> <input name='post[title]' type='text' value='Hello World' id='post_title' /><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' value='1' id='post_secret' /><br/>"
end
assert_dom_equal expected, output_buffer
@@ -1980,7 +2008,7 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected = whole_form("/posts/123", method: "patch") do
- "<label for='title'>Title:</label> <input name='post[title]' type='text' value='Hello World' /><br/>"
+ "<label for='title'>Title:</label> <input name='post[title]' type='text' value='Hello World' id='post_title' /><br/>"
end
assert_dom_equal expected, output_buffer
@@ -1995,7 +2023,7 @@ class FormWithActsLikeFormForTest < FormWithTest
concat f.text_field(:title)
end
- expected = "<label for='title'>Title:</label> <input name='post[title]' type='text' value='Hello World' /><br/>"
+ expected = "<label for='title'>Title:</label> <input name='post[title]' type='text' value='Hello World' id='post_title' /><br/>"
assert_dom_equal expected, output_buffer
end
@@ -2007,7 +2035,7 @@ class FormWithActsLikeFormForTest < FormWithTest
concat f.text_field(:title)
end
- expected = "<label for='title'>Title:</label> <input name='post[title]' type='text' value='Hello World' /><br/>"
+ expected = "<label for='title'>Title:</label> <input name='post[title]' type='text' value='Hello World' id='post_title' /><br/>"
assert_dom_equal expected, output_buffer
end
@@ -2020,9 +2048,9 @@ class FormWithActsLikeFormForTest < FormWithTest
end
expected =
- "<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/>"
+ "<label for='title'>Title:</label> <input name='post[title]' type='text' value='Hello World' id='post_title'/><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' value='1' id='post_secret' /><br/>"
assert_dom_equal expected, output_buffer
end
diff --git a/actionview/test/template/form_helper_test.rb b/actionview/test/template/form_helper_test.rb
index ac64096908..4442465047 100644
--- a/actionview/test/template/form_helper_test.rb
+++ b/actionview/test/template/form_helper_test.rb
@@ -1560,6 +1560,38 @@ class FormHelperTest < ActionView::TestCase
assert_dom_equal expected, output_buffer
end
+ def test_form_for_is_not_affected_by_form_with_generates_ids
+ old_value = ActionView::Helpers::FormHelper.form_with_generates_ids
+ ActionView::Helpers::FormHelper.form_with_generates_ids = false
+
+ form_for(@post, html: { id: "create-post" }) do |f|
+ concat f.label(:title) { "The Title" }
+ concat f.text_field(:title)
+ concat f.text_area(:body)
+ concat f.check_box(:secret)
+ concat f.submit("Create post")
+ concat f.button("Create post")
+ concat f.button {
+ concat content_tag(:span, "Create post")
+ }
+ end
+
+ expected = whole_form("/posts/123", "create-post", "edit_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[secret]' type='hidden' value='0' />" \
+ "<input name='post[secret]' checked='checked' type='checkbox' id='post_secret' 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>"
+ end
+
+ assert_dom_equal expected, output_buffer
+ ensure
+ ActionView::Helpers::FormHelper.form_with_generates_ids = old_value
+ end
+
def test_form_for_with_collection_radio_buttons
post = Post.new
def post.active; false; end
diff --git a/activejob/lib/active_job/queue_adapters/delayed_job_adapter.rb b/activejob/lib/active_job/queue_adapters/delayed_job_adapter.rb
index 1978179948..8eeef32b99 100644
--- a/activejob/lib/active_job/queue_adapters/delayed_job_adapter.rb
+++ b/activejob/lib/active_job/queue_adapters/delayed_job_adapter.rb
@@ -34,6 +34,10 @@ module ActiveJob
@job_data = job_data
end
+ def display_name
+ "#{job_data['job_class']} [#{job_data['job_id']}] from DelayedJob(#{job_data['queue_name']}) with arguments: #{job_data['arguments']}"
+ end
+
def perform
Base.execute(job_data)
end
diff --git a/activejob/test/integration/queuing_test.rb b/activejob/test/integration/queuing_test.rb
index 0d8aa336a6..32ef485c45 100644
--- a/activejob/test/integration/queuing_test.rb
+++ b/activejob/test/integration/queuing_test.rb
@@ -45,6 +45,13 @@ class QueuingTest < ActiveSupport::TestCase
end
end
+ test "should supply a wrapped class name to DelayedJob" do
+ skip unless adapter_is?(:delayed_job)
+ ::HelloJob.perform_later
+ job = Delayed::Job.first
+ assert_match(/HelloJob \[[0-9a-f-]+\] from DelayedJob\(default\) with arguments: \[\]/, job.name)
+ end
+
test "resque JobWrapper should have instance variable queue" do
skip unless adapter_is?(:resque)
job = ::HelloJob.set(wait: 5.seconds).perform_later
diff --git a/activerecord/lib/active_record/associations/collection_association.rb b/activerecord/lib/active_record/associations/collection_association.rb
index ed215fb22c..921237a735 100644
--- a/activerecord/lib/active_record/associations/collection_association.rb
+++ b/activerecord/lib/active_record/associations/collection_association.rb
@@ -79,7 +79,13 @@ module ActiveRecord
def find(*args)
if options[:inverse_of] && loaded?
args_flatten = args.flatten
- raise RecordNotFound, "Couldn't find #{scope.klass.name} without an ID" if args_flatten.blank?
+ model = scope.klass
+
+ if args_flatten.blank?
+ error_message = "Couldn't find #{model.name} without an ID"
+ raise RecordNotFound.new(error_message, model.name, model.primary_key, args)
+ end
+
result = find_by_scan(*args)
result_size = Array(result).size
diff --git a/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb b/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb
index 94687b9bb7..9849f9d5d7 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb
@@ -453,6 +453,21 @@ module ActiveRecord
disconnect(false)
end
+ # Discards all connections in the pool (even if they're currently
+ # leased!), along with the pool itself. Any further interaction with the
+ # pool (except #spec and #schema_cache) is undefined.
+ #
+ # See AbstractAdapter#discard!
+ def discard! # :nodoc:
+ synchronize do
+ return if @connections.nil? # already discarded
+ @connections.each do |conn|
+ conn.discard!
+ end
+ @connections = @available = @thread_cached_conns = nil
+ end
+ end
+
# Clears the cache which maps classes and re-connects connections that
# require reloading.
#
@@ -898,11 +913,31 @@ module ActiveRecord
# about the model. The model needs to pass a specification name to the handler,
# in order to look up the correct connection pool.
class ConnectionHandler
+ def self.unowned_pool_finalizer(pid_map) # :nodoc:
+ lambda do |_|
+ discard_unowned_pools(pid_map)
+ end
+ end
+
+ def self.discard_unowned_pools(pid_map) # :nodoc:
+ pid_map.each do |pid, pools|
+ pools.values.compact.each(&:discard!) unless pid == Process.pid
+ end
+ end
+
def initialize
# These caches are keyed by spec.name (ConnectionSpecification#name).
@owner_to_pool = Concurrent::Map.new(initial_capacity: 2) do |h, k|
+ # Discard the parent's connection pools immediately; we have no need
+ # of them
+ ConnectionHandler.discard_unowned_pools(h)
+
h[k] = Concurrent::Map.new(initial_capacity: 2)
end
+
+ # Backup finalizer: if the forked child never needed a pool, the above
+ # early discard has not occurred
+ ObjectSpace.define_finalizer self, ConnectionHandler.unowned_pool_finalizer(@owner_to_pool)
end
def connection_pool_list
diff --git a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb
index 95e808648c..8993c517a6 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb
@@ -375,6 +375,19 @@ module ActiveRecord
reset_transaction
end
+ # Immediately forget this connection ever existed. Unlike disconnect!,
+ # this will not communicate with the server.
+ #
+ # After calling this method, the behavior of all other methods becomes
+ # undefined. This is called internally just before a forked process gets
+ # rid of a connection that belonged to its parent.
+ def discard!
+ # This should be overridden by concrete adapters.
+ #
+ # Prevent @connection's finalizer from touching the socket, or
+ # otherwise communicating with its server, when it is collected.
+ end
+
# Reset the state of this connection, directing the DBMS to clear
# transactions and other connection-related server-side state. Usually a
# database-dependent operation.
diff --git a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb
index ca651ef390..0e552dba95 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb
@@ -44,7 +44,7 @@ module ActiveRecord
json: { name: "json" },
}
- class StatementPool < ConnectionAdapters::StatementPool
+ class StatementPool < ConnectionAdapters::StatementPool # :nodoc:
private def dealloc(stmt)
stmt[:stmt].close
end
diff --git a/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb b/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb
index 8de582fee1..957e8acc90 100644
--- a/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb
@@ -3,9 +3,8 @@
require "active_record/connection_adapters/abstract_mysql_adapter"
require "active_record/connection_adapters/mysql/database_statements"
-gem "mysql2", ">= 0.3.18", "< 0.5"
+gem "mysql2", ">= 0.3.18", "< 0.5", "!= 0.4.3"
require "mysql2"
-raise "mysql2 0.4.3 is not supported. Please upgrade to 0.4.4+" if Mysql2::VERSION == "0.4.3"
module ActiveRecord
module ConnectionHandling # :nodoc:
@@ -105,6 +104,11 @@ module ActiveRecord
@connection.close
end
+ def discard! # :nodoc:
+ @connection.automatic_close = false
+ @connection = nil
+ end
+
private
def connect
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
index 5ce6765dd8..1739c288b6 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
@@ -273,6 +273,11 @@ module ActiveRecord
end
end
+ def discard! # :nodoc:
+ @connection.socket_io.reopen(IO::NULL)
+ @connection = nil
+ end
+
def native_database_types #:nodoc:
NATIVE_DATABASE_TYPES
end
diff --git a/activerecord/lib/active_record/migration/command_recorder.rb b/activerecord/lib/active_record/migration/command_recorder.rb
index ac7d506fd1..81ef4828f8 100644
--- a/activerecord/lib/active_record/migration/command_recorder.rb
+++ b/activerecord/lib/active_record/migration/command_recorder.rb
@@ -110,7 +110,7 @@ module ActiveRecord
private
- module StraightReversions
+ module StraightReversions # :nodoc:
private
{ transaction: :transaction,
execute_block: :execute_block,
diff --git a/activerecord/lib/active_record/relation.rb b/activerecord/lib/active_record/relation.rb
index 081ef5771f..d3b8091665 100644
--- a/activerecord/lib/active_record/relation.rb
+++ b/activerecord/lib/active_record/relation.rb
@@ -544,6 +544,7 @@ module ActiveRecord
end
@records.each(&:readonly!) if readonly_value
+ @offsets = {} unless @offsets.empty?
@loaded = true
@records
diff --git a/activerecord/lib/active_record/relation/finder_methods.rb b/activerecord/lib/active_record/relation/finder_methods.rb
index 706fd57704..77c1367556 100644
--- a/activerecord/lib/active_record/relation/finder_methods.rb
+++ b/activerecord/lib/active_record/relation/finder_methods.rb
@@ -88,7 +88,7 @@ module ActiveRecord
where(arg, *args).take!
rescue ::RangeError
raise RecordNotFound.new("Couldn't find #{@klass.name} with an out of range value",
- @klass.name)
+ @klass.name, @klass.primary_key)
end
# Gives a record (or N records if a parameter is supplied) without any implied
@@ -339,7 +339,7 @@ module ActiveRecord
if ids.nil?
error = "Couldn't find #{name}".dup
error << " with#{conditions}" if conditions
- raise RecordNotFound.new(error, name)
+ raise RecordNotFound.new(error, name, key)
elsif Array(ids).size == 1
error = "Couldn't find #{name} with '#{key}'=#{ids}#{conditions}"
raise RecordNotFound.new(error, name, key, ids)
@@ -347,7 +347,7 @@ module ActiveRecord
error = "Couldn't find all #{name.pluralize} with '#{key}': ".dup
error << "(#{ids.join(", ")})#{conditions} (found #{result_size} results, but was looking for #{expected_size})."
error << " Couldn't find #{name.pluralize(not_found_ids.size)} with #{key.to_s.pluralize(not_found_ids.size)} #{not_found_ids.join(', ')}." if not_found_ids
- raise RecordNotFound.new(error, name, primary_key, ids)
+ raise RecordNotFound.new(error, name, key, ids)
end
end
@@ -433,9 +433,12 @@ module ActiveRecord
ids = ids.flatten.compact.uniq
+ model_name = @klass.name
+
case ids.size
when 0
- raise RecordNotFound, "Couldn't find #{@klass.name} without an ID"
+ error_message = "Couldn't find #{model_name} without an ID"
+ raise RecordNotFound.new(error_message, model_name, primary_key)
when 1
result = find_one(ids.first)
expects_array ? [ result ] : result
@@ -443,7 +446,8 @@ module ActiveRecord
find_some(ids)
end
rescue ::RangeError
- raise RecordNotFound, "Couldn't find #{@klass.name} with an out of range ID"
+ error_message = "Couldn't find #{model_name} with an out of range ID"
+ raise RecordNotFound.new(error_message, model_name, primary_key, ids)
end
def find_one(id)
diff --git a/activerecord/lib/active_record/scoping.rb b/activerecord/lib/active_record/scoping.rb
index da585a9562..01ac56570a 100644
--- a/activerecord/lib/active_record/scoping.rb
+++ b/activerecord/lib/active_record/scoping.rb
@@ -11,23 +11,23 @@ module ActiveRecord
include Named
end
- module ClassMethods
- def current_scope(skip_inherited_scope = false) # :nodoc:
+ module ClassMethods # :nodoc:
+ def current_scope(skip_inherited_scope = false)
ScopeRegistry.value_for(:current_scope, self, skip_inherited_scope)
end
- def current_scope=(scope) #:nodoc:
+ def current_scope=(scope)
ScopeRegistry.set_value_for(:current_scope, self, scope)
end
# Collects attributes from scopes that should be applied when creating
# an AR instance for the particular class this is called on.
- def scope_attributes # :nodoc:
+ def scope_attributes
all.scope_for_create
end
# Are there attributes associated with this scope?
- def scope_attributes? # :nodoc:
+ def scope_attributes?
current_scope
end
end
diff --git a/activerecord/test/cases/associations/inverse_associations_test.rb b/activerecord/test/cases/associations/inverse_associations_test.rb
index e13cf93dcf..f8f6b10e2b 100644
--- a/activerecord/test/cases/associations/inverse_associations_test.rb
+++ b/activerecord/test/cases/associations/inverse_associations_test.rb
@@ -484,7 +484,10 @@ class InverseHasManyTests < ActiveRecord::TestCase
def test_raise_record_not_found_error_when_no_ids_are_passed
man = Man.create!
- assert_raise(ActiveRecord::RecordNotFound) { man.interests.find() }
+ exception = assert_raise(ActiveRecord::RecordNotFound) { man.interests.load.find() }
+
+ assert_equal exception.model, "Interest"
+ assert_equal exception.primary_key, "id"
end
def test_trying_to_use_inverses_that_dont_exist_should_raise_an_error
diff --git a/activerecord/test/cases/connection_adapters/connection_handler_test.rb b/activerecord/test/cases/connection_adapters/connection_handler_test.rb
index 74d0ed348e..cae74a2b9b 100644
--- a/activerecord/test/cases/connection_adapters/connection_handler_test.rb
+++ b/activerecord/test/cases/connection_adapters/connection_handler_test.rb
@@ -1,10 +1,15 @@
# frozen_string_literal: true
require "cases/helper"
+require "models/person"
module ActiveRecord
module ConnectionAdapters
class ConnectionHandlerTest < ActiveRecord::TestCase
+ self.use_transactional_tests = false
+
+ fixtures :people
+
def setup
@handler = ConnectionHandler.new
@spec_name = "primary"
@@ -139,6 +144,33 @@ module ActiveRecord
rd.close
end
+ def test_forked_child_doesnt_mangle_parent_connection
+ object_id = ActiveRecord::Base.connection.object_id
+ assert ActiveRecord::Base.connection.active?
+
+ rd, wr = IO.pipe
+ rd.binmode
+ wr.binmode
+
+ pid = fork {
+ rd.close
+ if ActiveRecord::Base.connection.active?
+ wr.write Marshal.dump ActiveRecord::Base.connection.object_id
+ end
+ wr.close
+
+ exit # allow finalizers to run
+ }
+
+ wr.close
+
+ Process.waitpid pid
+ assert_not_equal object_id, Marshal.load(rd.read)
+ rd.close
+
+ assert_equal 3, ActiveRecord::Base.connection.select_value("SELECT COUNT(*) FROM people")
+ end
+
def test_retrieve_connection_pool_copies_schema_cache_from_ancestor_pool
@pool.schema_cache = @pool.connection.schema_cache
@pool.schema_cache.add("posts")
diff --git a/activerecord/test/cases/finder_test.rb b/activerecord/test/cases/finder_test.rb
index 1268949ba9..93957ff50f 100644
--- a/activerecord/test/cases/finder_test.rb
+++ b/activerecord/test/cases/finder_test.rb
@@ -120,6 +120,21 @@ class FinderTest < ActiveRecord::TestCase
assert_equal "The Fourth Topic of the day", records[2].title
end
+ def test_find_with_ids_with_no_id_passed
+ exception = assert_raises(ActiveRecord::RecordNotFound) { Topic.find }
+ assert_equal exception.model, "Topic"
+ assert_equal exception.primary_key, "id"
+ end
+
+ def test_find_with_ids_with_id_out_of_range
+ exception = assert_raises(ActiveRecord::RecordNotFound) do
+ Topic.find("9999999999999999999999999999999")
+ end
+
+ assert_equal exception.model, "Topic"
+ assert_equal exception.primary_key, "id"
+ end
+
def test_find_passing_active_record_object_is_not_permitted
assert_raises(ArgumentError) do
Topic.find(Topic.last)
@@ -676,6 +691,22 @@ class FinderTest < ActiveRecord::TestCase
assert_kind_of Array, Topic.last(5)
end
+ def test_first_should_respect_loaded_records
+ authors = Author.order(:name)
+
+ assert_equal authors(:bob), authors.first
+
+ aaron = authors.create!(name: "Aaron")
+
+ authors.load
+
+ assert_no_queries do
+ assert_equal aaron, authors.first
+ assert_equal authors(:bob), authors.second
+ assert_not_equal authors.first, authors.second
+ end
+ end
+
def test_unexisting_record_exception_handling
assert_raise(ActiveRecord::RecordNotFound) {
Topic.find(1).parent
diff --git a/activesupport/CHANGELOG.md b/activesupport/CHANGELOG.md
index 3257c63fd2..b6eb64c1c9 100644
--- a/activesupport/CHANGELOG.md
+++ b/activesupport/CHANGELOG.md
@@ -1,3 +1,11 @@
+* Changed default behaviour of `ActiveSupport::SecurityUtils.secure_compare`,
+ to make it not leak length information even for variable length string.
+
+ Renamed old `ActiveSupport::SecurityUtils.secure_compare` to `fixed_length_secure_compare`,
+ and started raising `ArgumentError` in case of length mismatch of passed strings.
+
+ *Vipul A M*
+
* Make `ActiveSupport::TimeZone.all` return only time zones that are in
`ActiveSupport::TimeZone::MAPPING`.
diff --git a/activesupport/lib/active_support/security_utils.rb b/activesupport/lib/active_support/security_utils.rb
index b6b31ef140..20b6b9cd3f 100644
--- a/activesupport/lib/active_support/security_utils.rb
+++ b/activesupport/lib/active_support/security_utils.rb
@@ -4,14 +4,12 @@ require "digest/sha2"
module ActiveSupport
module SecurityUtils
- # Constant time string comparison.
+ # Constant time string comparison, for fixed length strings.
#
# The values compared should be of fixed length, such as strings
- # that have already been processed by HMAC. This should not be used
- # on variable length plaintext strings because it could leak length info
- # via timing attacks.
- def secure_compare(a, b)
- return false unless a.bytesize == b.bytesize
+ # that have already been processed by HMAC. Raises in case of length mismatch.
+ def fixed_length_secure_compare(a, b)
+ raise ArgumentError, "string length mismatch." unless a.bytesize == b.bytesize
l = a.unpack "C#{a.bytesize}"
@@ -19,11 +17,15 @@ module ActiveSupport
b.each_byte { |byte| res |= byte ^ l.shift }
res == 0
end
- module_function :secure_compare
+ module_function :fixed_length_secure_compare
- def variable_size_secure_compare(a, b) # :nodoc:
- secure_compare(::Digest::SHA256.hexdigest(a), ::Digest::SHA256.hexdigest(b))
+ # Constant time string comparison, for variable length strings.
+ #
+ # The values are first processed by SHA256, so that we don't leak length info
+ # via timing attacks.
+ def secure_compare(a, b)
+ fixed_length_secure_compare(::Digest::SHA256.hexdigest(a), ::Digest::SHA256.hexdigest(b)) && a == b
end
- module_function :variable_size_secure_compare
+ module_function :secure_compare
end
end
diff --git a/activesupport/test/security_utils_test.rb b/activesupport/test/security_utils_test.rb
index efd2bcfa0f..0a607594a2 100644
--- a/activesupport/test/security_utils_test.rb
+++ b/activesupport/test/security_utils_test.rb
@@ -9,8 +9,14 @@ class SecurityUtilsTest < ActiveSupport::TestCase
assert_not ActiveSupport::SecurityUtils.secure_compare("a", "b")
end
- def test_variable_size_secure_compare_should_perform_string_comparison
- assert ActiveSupport::SecurityUtils.variable_size_secure_compare("a", "a")
- assert_not ActiveSupport::SecurityUtils.variable_size_secure_compare("a", "b")
+ def test_fixed_length_secure_compare_should_perform_string_comparison
+ assert ActiveSupport::SecurityUtils.fixed_length_secure_compare("a", "a")
+ assert !ActiveSupport::SecurityUtils.fixed_length_secure_compare("a", "b")
+ end
+
+ def test_fixed_length_secure_compare_raise_on_length_mismatch
+ assert_raises(ArgumentError, "string length mismatch.") do
+ ActiveSupport::SecurityUtils.fixed_length_secure_compare("a", "ab")
+ end
end
end
diff --git a/guides/source/api_app.md b/guides/source/api_app.md
index 43a7de88b0..b360f270d7 100644
--- a/guides/source/api_app.md
+++ b/guides/source/api_app.md
@@ -414,8 +414,10 @@ Some common modules you might want to add:
- `AbstractController::Translation`: Support for the `l` and `t` localization
and translation methods.
-- `ActionController::HttpAuthentication::Basic` (or `Digest` or `Token`): Support
- for basic, digest or token HTTP authentication.
+- Support for basic, digest or token HTTP authentication:
+ * `ActionController::HttpAuthentication::Basic::ControllerMethods`,
+ * `ActionController::HttpAuthentication::Digest::ControllerMethods`,
+ * `ActionController::HttpAuthentication::Token::ControllerMethods`
- `ActionView::Layouts`: Support for layouts when rendering.
- `ActionController::MimeResponds`: Support for `respond_to`.
- `ActionController::Cookies`: Support for `cookies`, which includes
diff --git a/guides/source/configuring.md b/guides/source/configuring.md
index 6e129a5680..4bfcc1e21a 100644
--- a/guides/source/configuring.md
+++ b/guides/source/configuring.md
@@ -578,6 +578,8 @@ Defaults to `'signed cookie'`.
* `config.action_view.form_with_generates_remote_forms` determines whether `form_with` generates remote forms or not. This defaults to `true`.
+* `config.action_view.form_with_generates_ids` determines whether `form_with` generates ids on inputs. This defaults to `true`.
+
### Configuring Action Mailer
There are a number of settings available on `config.action_mailer`:
diff --git a/guides/source/engines.md b/guides/source/engines.md
index b226eac347..33694cf76a 100644
--- a/guides/source/engines.md
+++ b/guides/source/engines.md
@@ -921,7 +921,7 @@ engine:
mattr_accessor :author_class
```
-This method works like its brothers, `attr_accessor` and `cattr_accessor`, but
+This method works like its siblings, `attr_accessor` and `cattr_accessor`, but
provides a setter and getter method on the module with the specified name. To
use it, it must be referenced using `Blorgh.author_class`.
@@ -982,7 +982,7 @@ Blorgh.author_class = "User"
WARNING: It's very important here to use the `String` version of the class,
rather than the class itself. If you were to use the class, Rails would attempt
to load that class and then reference the related table. This could lead to
-problems if the table wasn't already existing. Therefore, a `String` should be
+problems if the table didn't already exist. Therefore, a `String` should be
used and then converted to a class using `constantize` in the engine later on.
Go ahead and try to create a new article. You will see that it works exactly in the
@@ -1514,7 +1514,7 @@ To hook into the initialization process of one of the following classes use the
## Configuration hooks
-These are the available configuration hooks. They do not hook into any particular framework, instead they run in context of the entire application.
+These are the available configuration hooks. They do not hook into any particular framework, but instead they run in context of the entire application.
| Hook | Use Case |
| ---------------------- | ------------------------------------------------------------------------------------- |
diff --git a/guides/source/layout.html.erb b/guides/source/layout.html.erb
index 334595e4d2..3981199e95 100644
--- a/guides/source/layout.html.erb
+++ b/guides/source/layout.html.erb
@@ -99,9 +99,9 @@
To get started, you can read our <%= link_to 'documentation contributions', 'http://edgeguides.rubyonrails.org/contributing_to_ruby_on_rails.html#contributing-to-the-rails-documentation' %> section.
</p>
<p>
- You may also find incomplete content, or stuff that is not up to date.
+ You may also find incomplete content or stuff that is not up to date.
Please do add any missing documentation for master. Make sure to check
- <%= link_to 'Edge Guides','http://edgeguides.rubyonrails.org' %> first to verify
+ <%= link_to 'Edge Guides', 'http://edgeguides.rubyonrails.org' %> first to verify
if the issues are already fixed or not on the master branch.
Check the <%= link_to 'Ruby on Rails Guides Guidelines', 'ruby_on_rails_guides_guidelines.html' %>
for style and conventions.
@@ -111,7 +111,7 @@
<%= link_to 'open an issue', 'https://github.com/rails/rails/issues' %>.
</p>
<p>And last but not least, any kind of discussion regarding Ruby on Rails
- documentation is very welcome in the <%= link_to 'rubyonrails-docs mailing list', 'https://groups.google.com/forum/#!forum/rubyonrails-docs' %>.
+ documentation is very welcome on the <%= link_to 'rubyonrails-docs mailing list', 'https://groups.google.com/forum/#!forum/rubyonrails-docs' %>.
</p>
</div>
</div>
diff --git a/guides/source/security.md b/guides/source/security.md
index fa90cadcd2..eeb005b661 100644
--- a/guides/source/security.md
+++ b/guides/source/security.md
@@ -52,7 +52,7 @@ User.find(session[:user_id])
NOTE: _The session ID is a 32-character random hex string._
-The session ID is generated using `SecureRandom.hex` which generates a random hex string using platform specific methods (such as OpenSSL, /dev/urandom or Win32) for generating cryptographically secure random numbers. Currently it is not feasible to brute-force Rails' session IDs.
+The session ID is generated using `SecureRandom.hex` which generates a random hex string using platform specific methods (such as OpenSSL, /dev/urandom or Win32 CryptoAPI) for generating cryptographically secure random numbers. Currently it is not feasible to brute-force Rails' session IDs.
### Session Hijacking
diff --git a/railties/lib/rails/application.rb b/railties/lib/rails/application.rb
index b1429df18b..075d17b0f4 100644
--- a/railties/lib/rails/application.rb
+++ b/railties/lib/rails/application.rb
@@ -174,8 +174,9 @@ module Rails
# team. Details at https://github.com/rails/rails/pull/6952#issuecomment-7661220
@caching_key_generator ||=
if secret_key_base
- ActiveSupport::CachingKeyGenerator.new \
+ ActiveSupport::CachingKeyGenerator.new(
ActiveSupport::KeyGenerator.new(secret_key_base, iterations: 1000)
+ )
else
ActiveSupport::LegacyKeyGenerator.new(secrets.secret_token)
end
@@ -400,8 +401,9 @@ module Rails
secrets.secret_token ||= config.secret_token
if secrets.secret_token.present?
- ActiveSupport::Deprecation.warn \
+ ActiveSupport::Deprecation.warn(
"`secrets.secret_token` is deprecated in favor of `secret_key_base` and will be removed in Rails 6.0."
+ )
end
secrets
@@ -424,8 +426,9 @@ module Rails
if Rails.env.test? || Rails.env.development?
Digest::MD5.hexdigest self.class.name
else
- validate_secret_key_base \
+ validate_secret_key_base(
ENV["SECRET_KEY_BASE"] || credentials.secret_key_base || secrets.secret_key_base
+ )
end
end
@@ -464,10 +467,11 @@ module Rails
#
# Rails.application.encrypted("config/special_tokens.yml.enc", key_path: "config/special_tokens.key")
def encrypted(path, key_path: "config/master.key", env_key: "RAILS_MASTER_KEY")
- ActiveSupport::EncryptedConfiguration.new \
+ ActiveSupport::EncryptedConfiguration.new(
config_path: Rails.root.join(path),
key_path: Rails.root.join(key_path),
env_key: env_key
+ )
end
def to_app #:nodoc:
diff --git a/railties/lib/rails/application/configuration.rb b/railties/lib/rails/application/configuration.rb
index 290ec13878..e221889da0 100644
--- a/railties/lib/rails/application/configuration.rb
+++ b/railties/lib/rails/application/configuration.rb
@@ -72,6 +72,9 @@ module Rails
self.ssl_options = { hsts: { subdomains: true } }
+ if respond_to?(:action_view)
+ action_view.form_with_generates_ids = false
+ end
when "5.1"
load_defaults "5.0"
@@ -82,7 +85,6 @@ module Rails
if respond_to?(:action_view)
action_view.form_with_generates_remote_forms = true
end
-
when "5.2"
load_defaults "5.1"
@@ -106,6 +108,9 @@ module Rails
action_controller.default_protect_from_forgery = true
end
+ if respond_to?(:action_view)
+ action_view.form_with_generates_ids = true
+ end
else
raise "Unknown version #{target_version.to_s.inspect}"
end
diff --git a/railties/lib/rails/generators/rails/credentials/credentials_generator.rb b/railties/lib/rails/generators/rails/credentials/credentials_generator.rb
index ab15da5423..067479c672 100644
--- a/railties/lib/rails/generators/rails/credentials/credentials_generator.rb
+++ b/railties/lib/rails/generators/rails/credentials/credentials_generator.rb
@@ -31,10 +31,11 @@ module Rails
private
def credentials
- ActiveSupport::EncryptedConfiguration.new \
+ ActiveSupport::EncryptedConfiguration.new(
config_path: "config/credentials.yml.enc",
key_path: "config/master.key",
env_key: "RAILS_MASTER_KEY"
+ )
end
def credentials_template
diff --git a/railties/test/application/configuration_test.rb b/railties/test/application/configuration_test.rb
index bb8cc0876c..edb6190ed0 100644
--- a/railties/test/application/configuration_test.rb
+++ b/railties/test/application/configuration_test.rb
@@ -757,6 +757,68 @@ module ApplicationTests
assert_match(/label/, last_response.body)
end
+ test "form_with can be configured with form_with_generates_ids" do
+ app_file "config/initializers/form_builder.rb", <<-RUBY
+ Rails.configuration.action_view.form_with_generates_ids = false
+ RUBY
+
+ app_file "app/models/post.rb", <<-RUBY
+ class Post
+ include ActiveModel::Model
+ attr_accessor :name
+ end
+ RUBY
+
+ app_file "app/controllers/posts_controller.rb", <<-RUBY
+ class PostsController < ApplicationController
+ def index
+ render inline: "<%= begin; form_with(model: Post.new) {|f| f.text_field(:name)}; rescue => e; e.to_s; end %>"
+ end
+ end
+ RUBY
+
+ add_to_config <<-RUBY
+ routes.prepend do
+ resources :posts
+ end
+ RUBY
+
+ app "development"
+
+ get "/posts"
+
+ assert_no_match(/id=('|")post_name('|")/, last_response.body)
+ end
+
+ test "form_with outputs ids by default" do
+ app_file "app/models/post.rb", <<-RUBY
+ class Post
+ include ActiveModel::Model
+ attr_accessor :name
+ end
+ RUBY
+
+ app_file "app/controllers/posts_controller.rb", <<-RUBY
+ class PostsController < ApplicationController
+ def index
+ render inline: "<%= begin; form_with(model: Post.new) {|f| f.text_field(:name)}; rescue => e; e.to_s; end %>"
+ end
+ end
+ RUBY
+
+ add_to_config <<-RUBY
+ routes.prepend do
+ resources :posts
+ end
+ RUBY
+
+ app "development"
+
+ get "/posts"
+
+ assert_match(/id=('|")post_name('|")/, last_response.body)
+ end
+
test "form_with can be configured with form_with_generates_remote_forms" do
app_file "config/initializers/form_builder.rb", <<-RUBY
Rails.configuration.action_view.form_with_generates_remote_forms = false