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--actionpack/lib/action_dispatch/middleware/cookies.rb2
-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.rb5
-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/scoping.rb10
-rw-r--r--activerecord/test/cases/connection_adapters/connection_handler_test.rb32
-rw-r--r--activerecord/test/cases/finder_test.rb16
-rw-r--r--activestorage/lib/active_storage/service/gcs_service.rb17
-rw-r--r--activestorage/test/service/gcs_service_test.rb9
-rw-r--r--activesupport/CHANGELOG.md8
-rw-r--r--activesupport/lib/active_support/security_utils.rb22
-rw-r--r--activesupport/test/security_utils_test.rb11
-rw-r--r--guides/assets/images/belongs_to.pngbin22147 -> 35041 bytes
-rw-r--r--guides/assets/images/habtm.pngbin47284 -> 61435 bytes
-rw-r--r--guides/assets/images/has_many.pngbin24300 -> 36233 bytes
-rw-r--r--guides/assets/images/has_many_through.pngbin78099 -> 98834 bytes
-rw-r--r--guides/assets/images/has_one.pngbin27547 -> 38222 bytes
-rw-r--r--guides/assets/images/has_one_through.pngbin70130 -> 92535 bytes
-rw-r--r--guides/assets/images/polymorphic.pngbin65417 -> 84739 bytes
-rw-r--r--guides/source/layout.html.erb6
-rw-r--r--guides/source/layouts_and_rendering.md2
-rw-r--r--guides/source/security.md2
-rw-r--r--guides/source/working_with_javascript_in_rails.md60
-rw-r--r--railties/lib/rails/command/helpers/editor.rb2
30 files changed, 197 insertions, 80 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/actionpack/lib/action_dispatch/middleware/cookies.rb b/actionpack/lib/action_dispatch/middleware/cookies.rb
index 86a070c6ad..ea4156c972 100644
--- a/actionpack/lib/action_dispatch/middleware/cookies.rb
+++ b/actionpack/lib/action_dispatch/middleware/cookies.rb
@@ -161,7 +161,7 @@ module ActionDispatch
#
# * <tt>:tld_length</tt> - When using <tt>:domain => :all</tt>, this option can be used to explicitly
# set the TLD length when using a short (<= 3 character) domain that is being interpreted as part of a TLD.
- # For example, to share cookies between user1.lvh.me and user2.lvh.me, set <tt>:tld_length</tt> to 1.
+ # For example, to share cookies between user1.lvh.me and user2.lvh.me, set <tt>:tld_length</tt> to 2.
# * <tt>:expires</tt> - The time at which this cookie expires, as a \Time or ActiveSupport::Duration object.
# * <tt>:secure</tt> - Whether this cookie is only transmitted to HTTPS servers.
# Default is +false+.
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 6c06f67239..c5013dc1ee 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb
@@ -447,6 +447,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.
#
@@ -863,11 +878,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 7e6db860dd..5411a6a262 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb
@@ -367,6 +367,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..1d614dc8bf 100644
--- a/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb
@@ -105,6 +105,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/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/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..b5c9bdf3a7 100644
--- a/activerecord/test/cases/finder_test.rb
+++ b/activerecord/test/cases/finder_test.rb
@@ -676,6 +676,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/activestorage/lib/active_storage/service/gcs_service.rb b/activestorage/lib/active_storage/service/gcs_service.rb
index b4ffeeeb8a..be6ddf32a0 100644
--- a/activestorage/lib/active_storage/service/gcs_service.rb
+++ b/activestorage/lib/active_storage/service/gcs_service.rb
@@ -7,11 +7,8 @@ module ActiveStorage
# Wraps the Google Cloud Storage as an Active Storage service. See ActiveStorage::Service for the generic API
# documentation that applies to all services.
class Service::GCSService < Service
- attr_reader :client, :bucket
-
- def initialize(project:, keyfile:, bucket:, **options)
- @client = Google::Cloud::Storage.new(project: project, keyfile: keyfile, **options)
- @bucket = @client.bucket(bucket)
+ def initialize(**config)
+ @config = config
end
def upload(key, io, checksum: nil)
@@ -85,8 +82,18 @@ module ActiveStorage
end
private
+ attr_reader :config
+
def file_for(key)
bucket.file(key, skip_lookup: true)
end
+
+ def bucket
+ @bucket ||= client.bucket(config.fetch(:bucket))
+ end
+
+ def client
+ @client ||= Google::Cloud::Storage.new(config.except(:bucket))
+ end
end
end
diff --git a/activestorage/test/service/gcs_service_test.rb b/activestorage/test/service/gcs_service_test.rb
index 5566c664a9..1860149da9 100644
--- a/activestorage/test/service/gcs_service_test.rb
+++ b/activestorage/test/service/gcs_service_test.rb
@@ -32,13 +32,8 @@ if SERVICE_CONFIGURATIONS[:gcs]
end
test "signed URL generation" do
- freeze_time do
- url = SERVICE.bucket.signed_url(FIXTURE_KEY, expires: 120) +
- "&response-content-disposition=inline%3B+filename%3D%22test.txt%22%3B+filename%2A%3DUTF-8%27%27test.txt" +
- "&response-content-type=text%2Fplain"
-
- assert_equal url, @service.url(FIXTURE_KEY, expires_in: 2.minutes, disposition: :inline, filename: ActiveStorage::Filename.new("test.txt"), content_type: "text/plain")
- end
+ assert_match(/storage\.googleapis\.com\/.*response-content-disposition=inline.*test\.txt.*response-content-type=text%2Fplain/,
+ @service.url(FIXTURE_KEY, expires_in: 2.minutes, disposition: :inline, filename: ActiveStorage::Filename.new("test.txt"), content_type: "text/plain"))
end
end
else
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..6945f653e6 100644
--- a/activesupport/test/security_utils_test.rb
+++ b/activesupport/test/security_utils_test.rb
@@ -13,4 +13,15 @@ class SecurityUtilsTest < ActiveSupport::TestCase
assert ActiveSupport::SecurityUtils.variable_size_secure_compare("a", "a")
assert_not ActiveSupport::SecurityUtils.variable_size_secure_compare("a", "b")
end
+
+ 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/assets/images/belongs_to.png b/guides/assets/images/belongs_to.png
index 1a9926e578..2b8c1d52ea 100644
--- a/guides/assets/images/belongs_to.png
+++ b/guides/assets/images/belongs_to.png
Binary files differ
diff --git a/guides/assets/images/habtm.png b/guides/assets/images/habtm.png
index 41013b743d..7e508cc1a6 100644
--- a/guides/assets/images/habtm.png
+++ b/guides/assets/images/habtm.png
Binary files differ
diff --git a/guides/assets/images/has_many.png b/guides/assets/images/has_many.png
index 0d67bea38b..36ccf9f0f6 100644
--- a/guides/assets/images/has_many.png
+++ b/guides/assets/images/has_many.png
Binary files differ
diff --git a/guides/assets/images/has_many_through.png b/guides/assets/images/has_many_through.png
index b4da60e1fb..9e9caabd73 100644
--- a/guides/assets/images/has_many_through.png
+++ b/guides/assets/images/has_many_through.png
Binary files differ
diff --git a/guides/assets/images/has_one.png b/guides/assets/images/has_one.png
index c70763856a..c29c6b9c59 100644
--- a/guides/assets/images/has_one.png
+++ b/guides/assets/images/has_one.png
Binary files differ
diff --git a/guides/assets/images/has_one_through.png b/guides/assets/images/has_one_through.png
index 888a02b775..fdf13286c4 100644
--- a/guides/assets/images/has_one_through.png
+++ b/guides/assets/images/has_one_through.png
Binary files differ
diff --git a/guides/assets/images/polymorphic.png b/guides/assets/images/polymorphic.png
index e0a7f6d64a..d630db9e01 100644
--- a/guides/assets/images/polymorphic.png
+++ b/guides/assets/images/polymorphic.png
Binary files differ
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/layouts_and_rendering.md b/guides/source/layouts_and_rendering.md
index f4597b0e60..4d79b2db89 100644
--- a/guides/source/layouts_and_rendering.md
+++ b/guides/source/layouts_and_rendering.md
@@ -285,7 +285,7 @@ the response. Using `:plain` or `:html` might be more appropriate most of the
time.
NOTE: Unless overridden, your response returned from this render option will be
-`text/html`, as that is the default content type of Action Dispatch response.
+`text/plain`, as that is the default content type of Action Dispatch response.
#### Options for `render`
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/guides/source/working_with_javascript_in_rails.md b/guides/source/working_with_javascript_in_rails.md
index b2716c7faa..86746a5ae0 100644
--- a/guides/source/working_with_javascript_in_rails.md
+++ b/guides/source/working_with_javascript_in_rails.md
@@ -188,15 +188,20 @@ bind to the `ajax:success` event. On failure, use `ajax:error`. Check it out:
```coffeescript
$(document).ready ->
- $("#new_article").on("ajax:success", (e, data, status, xhr) ->
+ $("#new_article").on("ajax:success", (event) ->
+ [data, status, xhr] = event.detail
$("#new_article").append xhr.responseText
- ).on "ajax:error", (e, xhr, status, error) ->
+ ).on "ajax:error", (event) ->
$("#new_article").append "<p>ERROR</p>"
```
Obviously, you'll want to be a bit more sophisticated than that, but it's a
start.
+NOTE: As of Rails 5.1 and the new `rails-ujs`, the parameters `data, status, xhr`
+have been bundled into `event.detail`. For information about the previously used
+`jquery-ujs` in Rails 5 and earlier, read the [`jquery-ujs` wiki](https://github.com/rails/jquery-ujs/wiki/ajax).
+
#### link_to
[`link_to`](http://api.rubyonrails.org/classes/ActionView/Helpers/UrlHelper.html#method-i-link_to)
@@ -225,7 +230,7 @@ and write some CoffeeScript like this:
```coffeescript
$ ->
- $("a[data-remote]").on "ajax:success", (e, data, status, xhr) ->
+ $("a[data-remote]").on "ajax:success", (event) ->
alert "The article was deleted."
```
@@ -343,39 +348,6 @@ This generates a form with:
<input data-disable-with="Saving..." type="submit">
```
-Dealing with Ajax events
-------------------------
-
-Here are the different events that are fired when you deal with elements
-that have a `data-remote` attribute:
-
-NOTE: All handlers bound to these events are always passed the event object as the
-first argument. The table below describes the extra parameters passed after the
-event argument. For example, if the extra parameters are listed as `xhr, settings`,
-then to access them, you would define your handler with `function(event, xhr, settings)`.
-
-| Event name | Extra parameters | Fired |
-|---------------------|------------------|-------------------------------------------------------------|
-| `ajax:before` | | Before the whole ajax business, aborts if stopped. |
-| `ajax:beforeSend` | xhr, options | Before the request is sent, aborts if stopped. |
-| `ajax:send` | xhr | When the request is sent. |
-| `ajax:success` | xhr, status, err | After completion, if the response was a success. |
-| `ajax:error` | xhr, status, err | After completion, if the response was an error. |
-| `ajax:complete` | xhr, status | After the request has been completed, no matter the outcome.|
-| `ajax:aborted:file` | elements | If there are non-blank file inputs, aborts if stopped. |
-
-### Stoppable events
-
-If you stop `ajax:before` or `ajax:beforeSend` by returning false from the
-handler method, the Ajax request will never take place. The `ajax:before` event
-is also useful for manipulating form data before serialization. The
-`ajax:beforeSend` event is also useful for adding custom request headers.
-
-If you stop the `ajax:aborted:file` event, the default behavior of allowing the
-browser to submit the form via normal means (i.e. non-Ajax submission) will be
-canceled and the form will not be submitted at all. This is useful for
-implementing your own Ajax file upload workaround.
-
### Rails-ujs event handlers
Rails 5.1 introduced rails-ujs and dropped jQuery as a dependency.
@@ -405,6 +377,22 @@ document.body.addEventListener('ajax:success', function(event) {
})
```
+NOTE: As of Rails 5.1 and the new `rails-ujs`, the parameters `data, status, xhr`
+have been bundled into `event.detail`. For information about the previously used
+`jquery-ujs` in Rails 5 and earlier, read the [`jquery-ujs` wiki](https://github.com/rails/jquery-ujs/wiki/ajax).
+
+### Stoppable events
+
+If you stop `ajax:before` or `ajax:beforeSend` by returning false from the
+handler method, the Ajax request will never take place. The `ajax:before` event
+can manipulate form data before serialization and the
+`ajax:beforeSend` event is useful for adding custom request headers.
+
+If you stop the `ajax:aborted:file` event, the default behavior of allowing the
+browser to submit the form via normal means (i.e. non-Ajax submission) will be
+canceled and the form will not be submitted at all. This is useful for
+implementing your own Ajax file upload workaround.
+
Server-Side Concerns
--------------------
diff --git a/railties/lib/rails/command/helpers/editor.rb b/railties/lib/rails/command/helpers/editor.rb
index 5e9ecc05e7..6191d97672 100644
--- a/railties/lib/rails/command/helpers/editor.rb
+++ b/railties/lib/rails/command/helpers/editor.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require "active_support/encrypted_file"
module Rails