aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.codeclimate.yml2
-rw-r--r--Gemfile1
-rw-r--r--Gemfile.lock11
-rw-r--r--actionpack/lib/action_controller/metal/testing.rb6
-rw-r--r--actionpack/lib/action_dispatch/testing/integration.rb24
-rw-r--r--activejob/lib/active_job/exceptions.rb2
-rw-r--r--activejob/test/cases/exceptions_test.rb2
-rw-r--r--activejob/test/jobs/retry_job.rb2
-rw-r--r--activerecord/CHANGELOG.md12
-rw-r--r--activerecord/lib/active_record/connection_adapters/mysql/schema_dumper.rb7
-rw-r--r--activerecord/lib/active_record/relation/calculations.rb2
-rw-r--r--activerecord/test/cases/adapters/mysql2/auto_increment_test.rb34
-rw-r--r--activerecord/test/cases/associations/has_one_associations_test.rb3
-rw-r--r--activerecord/test/cases/calculations_test.rb4
-rw-r--r--activestorage/app/models/active_storage/blob.rb30
-rw-r--r--activestorage/app/models/active_storage/variant.rb4
-rw-r--r--activestorage/app/models/active_storage/variation.rb15
-rw-r--r--activestorage/test/database/setup.rb2
-rwxr-xr-xactivestorage/test/dummy/bin/bundle2
-rw-r--r--activestorage/test/models/preview_test.rb2
-rw-r--r--activestorage/test/models/representation_test.rb41
-rw-r--r--activestorage/test/test_helper.rb6
-rw-r--r--guides/source/active_record_querying.md4
-rw-r--r--guides/source/active_support_instrumentation.md61
-rw-r--r--guides/source/working_with_javascript_in_rails.md2
-rw-r--r--railties/test/commands/server_test.rb12
-rw-r--r--railties/test/generators/argv_scrubber_test.rb3
27 files changed, 246 insertions, 50 deletions
diff --git a/.codeclimate.yml b/.codeclimate.yml
index 63d3562e9b..1f4a1bb201 100644
--- a/.codeclimate.yml
+++ b/.codeclimate.yml
@@ -1,7 +1,7 @@
engines:
rubocop:
enabled: true
- channel: rubocop-0-49
+ channel: rubocop-0-50
ratings:
paths:
diff --git a/Gemfile b/Gemfile
index 1826c232fb..f545dd5fa1 100644
--- a/Gemfile
+++ b/Gemfile
@@ -18,7 +18,6 @@ gem "mocha", require: false
gem "capybara", "~> 2.15"
gem "rack-cache", "~> 1.2"
-gem "jquery-rails"
gem "coffee-rails"
gem "sass-rails", github: "rails/sass-rails", branch: "5-0-stable"
gem "turbolinks", "~> 5"
diff --git a/Gemfile.lock b/Gemfile.lock
index 9c3a7e3c82..ac56bca4ce 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -290,10 +290,6 @@ GEM
httpclient (2.8.3)
i18n (0.8.6)
jmespath (1.3.1)
- jquery-rails (4.3.1)
- rails-dom-testing (>= 1, < 3)
- railties (>= 4.2.0)
- thor (>= 0.14, < 2.0)
json (2.1.0)
jwt (1.5.6)
kindlerb (1.2.0)
@@ -391,14 +387,14 @@ GEM
sinatra (>= 0.9.2)
vegas (~> 0.1.2)
retriable (3.1.1)
- rubocop (0.49.1)
+ rubocop (0.50.0)
parallel (~> 1.10)
parser (>= 2.3.3.1, < 3.0)
powerpack (~> 0.1)
- rainbow (>= 1.99.1, < 3.0)
+ rainbow (>= 2.2.2, < 3.0)
ruby-progressbar (~> 1.7)
unicode-display_width (~> 1.0, >= 1.0.1)
- ruby-progressbar (1.8.1)
+ ruby-progressbar (1.9.0)
ruby_dep (1.5.0)
rubyzip (1.2.1)
rufus-scheduler (3.4.2)
@@ -510,7 +506,6 @@ DEPENDENCIES
erubis (~> 2.7.0)
google-cloud-storage (~> 1.3)
hiredis
- jquery-rails
json (>= 2.0.0)
kindlerb (~> 1.2.0)
libxml-ruby
diff --git a/actionpack/lib/action_controller/metal/testing.rb b/actionpack/lib/action_controller/metal/testing.rb
index b07f1f3d8c..6e8a95040f 100644
--- a/actionpack/lib/action_controller/metal/testing.rb
+++ b/actionpack/lib/action_controller/metal/testing.rb
@@ -12,11 +12,5 @@ module ActionController
self.params = nil
end
end
-
- module ClassMethods
- def before_filters
- _process_action_callbacks.find_all { |x| x.kind == :before }.map(&:name)
- end
- end
end
end
diff --git a/actionpack/lib/action_dispatch/testing/integration.rb b/actionpack/lib/action_dispatch/testing/integration.rb
index ae1f368e8b..8caa71199e 100644
--- a/actionpack/lib/action_dispatch/testing/integration.rb
+++ b/actionpack/lib/action_dispatch/testing/integration.rb
@@ -12,38 +12,38 @@ require_relative "request_encoder"
module ActionDispatch
module Integration #:nodoc:
module RequestHelpers
- # Performs a GET request with the given parameters. See +#process+ for more
- # details.
+ # Performs a GET request with the given parameters. See ActionDispatch::Integration::Session#process
+ # for more details.
def get(path, **args)
process(:get, path, **args)
end
- # Performs a POST request with the given parameters. See +#process+ for more
- # details.
+ # Performs a POST request with the given parameters. See ActionDispatch::Integration::Session#process
+ # for more details.
def post(path, **args)
process(:post, path, **args)
end
- # Performs a PATCH request with the given parameters. See +#process+ for more
- # details.
+ # Performs a PATCH request with the given parameters. See ActionDispatch::Integration::Session#process
+ # for more details.
def patch(path, **args)
process(:patch, path, **args)
end
- # Performs a PUT request with the given parameters. See +#process+ for more
- # details.
+ # Performs a PUT request with the given parameters. See ActionDispatch::Integration::Session#process
+ # for more details.
def put(path, **args)
process(:put, path, **args)
end
- # Performs a DELETE request with the given parameters. See +#process+ for
- # more details.
+ # Performs a DELETE request with the given parameters. See ActionDispatch::Integration::Session#process
+ # for more details.
def delete(path, **args)
process(:delete, path, **args)
end
- # Performs a HEAD request with the given parameters. See +#process+ for more
- # details.
+ # Performs a HEAD request with the given parameters. See ActionDispatch::Integration::Session#process
+ # for more details.
def head(path, *args)
process(:head, path, *args)
end
diff --git a/activejob/lib/active_job/exceptions.rb b/activejob/lib/active_job/exceptions.rb
index dfc74deb1a..8b4a88ba6a 100644
--- a/activejob/lib/active_job/exceptions.rb
+++ b/activejob/lib/active_job/exceptions.rb
@@ -49,7 +49,7 @@ module ActiveJob
retry_job wait: determine_delay(wait), queue: queue, priority: priority
else
if block_given?
- yield self, exception
+ yield self, error
else
logger.error "Stopped retrying #{self.class} due to a #{exception}, which reoccurred on #{executions} attempts. The original exception was #{error.cause.inspect}."
raise error
diff --git a/activejob/test/cases/exceptions_test.rb b/activejob/test/cases/exceptions_test.rb
index 7a3c372143..22fed0a808 100644
--- a/activejob/test/cases/exceptions_test.rb
+++ b/activejob/test/cases/exceptions_test.rb
@@ -61,7 +61,7 @@ class ExceptionsTest < ActiveJob::TestCase
test "custom handling of job that exceeds retry attempts" do
perform_enqueued_jobs do
RetryJob.perform_later "CustomCatchError", 6
- assert_equal "Dealt with a job that failed to retry in a custom way after 6 attempts", JobBuffer.last_value
+ assert_equal "Dealt with a job that failed to retry in a custom way after 6 attempts. Message: CustomCatchError", JobBuffer.last_value
end
end
diff --git a/activejob/test/jobs/retry_job.rb b/activejob/test/jobs/retry_job.rb
index a12d09779b..9aa99d9a21 100644
--- a/activejob/test/jobs/retry_job.rb
+++ b/activejob/test/jobs/retry_job.rb
@@ -17,7 +17,7 @@ class RetryJob < ActiveJob::Base
retry_on ShortWaitTenAttemptsError, wait: 1.second, attempts: 10
retry_on ExponentialWaitTenAttemptsError, wait: :exponentially_longer, attempts: 10
retry_on CustomWaitTenAttemptsError, wait: ->(executions) { executions * 2 }, attempts: 10
- retry_on(CustomCatchError) { |job, exception| JobBuffer.add("Dealt with a job that failed to retry in a custom way after #{job.arguments.second} attempts") }
+ retry_on(CustomCatchError) { |job, exception| JobBuffer.add("Dealt with a job that failed to retry in a custom way after #{job.arguments.second} attempts. Message: #{exception.message}") }
discard_on DiscardableError
def perform(raising, attempts)
diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md
index 288f22a9d3..0492694dac 100644
--- a/activerecord/CHANGELOG.md
+++ b/activerecord/CHANGELOG.md
@@ -1,3 +1,15 @@
+* MySQL: Don't lose `auto_increment: true` in the `db/schema.rb`.
+
+ Fixes #30894.
+
+ *Ryuta Kamizono*
+
+* Fix `COUNT(DISTINCT ...)` for `GROUP BY` with `ORDER BY` and `LIMIT`.
+
+ Fixes #30886.
+
+ *Ryuta Kamizono*
+
* PostgreSQL `tsrange` now preserves subsecond precision.
PostgreSQL 9.1+ introduced range types, and Rails added support for using
diff --git a/activerecord/lib/active_record/connection_adapters/mysql/schema_dumper.rb b/activerecord/lib/active_record/connection_adapters/mysql/schema_dumper.rb
index 95eb77aea4..d23178e43c 100644
--- a/activerecord/lib/active_record/connection_adapters/mysql/schema_dumper.rb
+++ b/activerecord/lib/active_record/connection_adapters/mysql/schema_dumper.rb
@@ -8,6 +8,7 @@ module ActiveRecord
def prepare_column_options(column)
spec = super
spec[:unsigned] = "true" if column.unsigned?
+ spec[:auto_increment] = "true" if column.auto_increment?
if @connection.supports_virtual_columns? && column.virtual?
spec[:as] = extract_expression_for_virtual_column(column)
@@ -18,6 +19,12 @@ module ActiveRecord
spec
end
+ def column_spec_for_primary_key(column)
+ spec = super
+ spec.delete(:auto_increment) if column.type == :integer && column.auto_increment?
+ spec
+ end
+
def default_primary_key?(column)
super && column.auto_increment? && !column.unsigned?
end
diff --git a/activerecord/lib/active_record/relation/calculations.rb b/activerecord/lib/active_record/relation/calculations.rb
index 4ef0502893..116bddce85 100644
--- a/activerecord/lib/active_record/relation/calculations.rb
+++ b/activerecord/lib/active_record/relation/calculations.rb
@@ -216,7 +216,7 @@ module ActiveRecord
if operation == "count"
column_name ||= select_for_count
if column_name == :all
- if distinct && !(has_limit_or_offset? && order_values.any?)
+ if distinct && (group_values.any? || !(has_limit_or_offset? && order_values.any?))
column_name = primary_key
end
elsif column_name =~ /\s*DISTINCT[\s(]+/i
diff --git a/activerecord/test/cases/adapters/mysql2/auto_increment_test.rb b/activerecord/test/cases/adapters/mysql2/auto_increment_test.rb
new file mode 100644
index 0000000000..4c67633946
--- /dev/null
+++ b/activerecord/test/cases/adapters/mysql2/auto_increment_test.rb
@@ -0,0 +1,34 @@
+# frozen_string_literal: true
+
+require "cases/helper"
+require "support/schema_dumping_helper"
+
+class Mysql2AutoIncrementTest < ActiveRecord::Mysql2TestCase
+ include SchemaDumpingHelper
+
+ def setup
+ @connection = ActiveRecord::Base.connection
+ end
+
+ def teardown
+ @connection.drop_table :auto_increments, if_exists: true
+ end
+
+ def test_auto_increment_without_primary_key
+ @connection.create_table :auto_increments, id: false, force: true do |t|
+ t.integer :id, null: false, auto_increment: true
+ t.index :id
+ end
+ output = dump_table_schema("auto_increments")
+ assert_match(/t\.integer\s+"id",\s+null: false,\s+auto_increment: true$/, output)
+ end
+
+ def test_auto_increment_with_composite_primary_key
+ @connection.create_table :auto_increments, primary_key: [:id, :created_at], force: true do |t|
+ t.integer :id, null: false, auto_increment: true
+ t.datetime :created_at, null: false
+ end
+ output = dump_table_schema("auto_increments")
+ assert_match(/t\.integer\s+"id",\s+null: false,\s+auto_increment: true$/, output)
+ end
+end
diff --git a/activerecord/test/cases/associations/has_one_associations_test.rb b/activerecord/test/cases/associations/has_one_associations_test.rb
index 2a9ebd19ed..ec5d95080b 100644
--- a/activerecord/test/cases/associations/has_one_associations_test.rb
+++ b/activerecord/test/cases/associations/has_one_associations_test.rb
@@ -30,7 +30,8 @@ class HasOneAssociationsTest < ActiveRecord::TestCase
ActiveRecord::SQLCounter.clear_log
companies(:first_firm).account
ensure
- assert ActiveRecord::SQLCounter.log_all.all? { |sql| /order by/i !~ sql }, "ORDER BY was used in the query"
+ log_all = ActiveRecord::SQLCounter.log_all
+ assert log_all.all? { |sql| /order by/i !~ sql }, "ORDER BY was used in the query: #{log_all}"
end
def test_has_one_cache_nils
diff --git a/activerecord/test/cases/calculations_test.rb b/activerecord/test/cases/calculations_test.rb
index b47fd0af41..66bc14b5ab 100644
--- a/activerecord/test/cases/calculations_test.rb
+++ b/activerecord/test/cases/calculations_test.rb
@@ -260,6 +260,10 @@ class CalculationsTest < ActiveRecord::TestCase
assert_equal 3, Account.joins(:firm).distinct.order(:firm_id).limit(3).offset(2).count
end
+ def test_distinct_count_with_group_by_and_order_and_limit
+ assert_equal({ 6 => 2 }, Account.group(:firm_id).distinct.order("1 DESC").limit(1).count)
+ end
+
def test_should_group_by_summed_field_having_condition
c = Account.group(:firm_id).having("sum(credit_limit) > 50").sum(:credit_limit)
assert_nil c[1]
diff --git a/activestorage/app/models/active_storage/blob.rb b/activestorage/app/models/active_storage/blob.rb
index ff785d4f61..84b8f3827b 100644
--- a/activestorage/app/models/active_storage/blob.rb
+++ b/activestorage/app/models/active_storage/blob.rb
@@ -15,6 +15,7 @@
# If you need to create a derivative or otherwise change the blob, simply create a new blob and purge the old one.
class ActiveStorage::Blob < ActiveRecord::Base
class UnpreviewableError < StandardError; end
+ class UnrepresentableError < StandardError; end
self.table_name = "active_storage_blobs"
@@ -123,7 +124,7 @@ class ActiveStorage::Blob < ActiveRecord::Base
# This will create a URL for that specific blob with that specific variant, which the ActiveStorage::VariantsController
# can then produce on-demand.
def variant(transformations)
- ActiveStorage::Variant.new(self, ActiveStorage::Variation.new(transformations))
+ ActiveStorage::Variant.new(self, ActiveStorage::Variation.wrap(transformations))
end
@@ -143,7 +144,7 @@ class ActiveStorage::Blob < ActiveRecord::Base
# whether a blob is accepted by any previewer, call ActiveStorage::Blob#previewable?.
def preview(transformations)
if previewable?
- ActiveStorage::Preview.new(self, ActiveStorage::Variation.new(transformations))
+ ActiveStorage::Preview.new(self, ActiveStorage::Variation.wrap(transformations))
else
raise UnpreviewableError
end
@@ -155,6 +156,31 @@ class ActiveStorage::Blob < ActiveRecord::Base
end
+ # Returns an ActiveStorage::Preview instance for a previewable blob or an ActiveStorage::Variant instance for an image blob.
+ #
+ # blob.representation(resize: "100x100").processed.service_url
+ #
+ # Raises ActiveStorage::Blob::UnrepresentableError if the receiving blob is neither an image nor previewable. Call
+ # ActiveStorage::Blob#representable? to determine whether a blob is representable.
+ #
+ # See ActiveStorage::Blob#preview and ActiveStorage::Blob#variant for more information.
+ def representation(transformations)
+ case
+ when previewable?
+ preview transformations
+ when image?
+ variant transformations
+ else
+ raise UnrepresentableError
+ end
+ end
+
+ # Returns true if the blob is an image or is previewable.
+ def representable?
+ image? || previewable?
+ end
+
+
# Returns the URL of the blob on the service. This URL is intended to be short-lived for security and not used directly
# with users. Instead, the +service_url+ should only be exposed as a redirect from a stable, possibly authenticated URL.
# Hiding the +service_url+ behind a redirect also gives you the power to change services without updating all URLs. And
diff --git a/activestorage/app/models/active_storage/variant.rb b/activestorage/app/models/active_storage/variant.rb
index 90a3605331..fa5aa69bd3 100644
--- a/activestorage/app/models/active_storage/variant.rb
+++ b/activestorage/app/models/active_storage/variant.rb
@@ -65,6 +65,10 @@ class ActiveStorage::Variant
service.url key, expires_in: expires_in, disposition: disposition, filename: blob.filename, content_type: blob.content_type
end
+ # Returns the receiving variant. Allows ActiveStorage::Variant and ActiveStorage::Preview instances to be used interchangeably.
+ def image
+ self
+ end
private
def processed?
diff --git a/activestorage/app/models/active_storage/variation.rb b/activestorage/app/models/active_storage/variation.rb
index df2643442a..13bad87cac 100644
--- a/activestorage/app/models/active_storage/variation.rb
+++ b/activestorage/app/models/active_storage/variation.rb
@@ -13,16 +13,21 @@ class ActiveStorage::Variation
attr_reader :transformations
class << self
- def wrap(variation_or_key)
- case variation_or_key
+ # Returns a Variation instance based on the given variator. If the variator is a Variation, it is
+ # returned unmodified. If it is a String, it is passed to ActiveStorage::Variation.decode. Otherwise,
+ # it is assumed to be a transformations Hash and is passed directly to the constructor.
+ def wrap(variator)
+ case variator
when self
- variation_or_key
+ variator
+ when String
+ decode variator
else
- decode variation_or_key
+ new variator
end
end
- # Returns a variation instance with the transformations that were encoded by +encode+.
+ # Returns a Variation instance with the transformations that were encoded by +encode+.
def decode(key)
new ActiveStorage.verifier.verify(key, purpose: :variation)
end
diff --git a/activestorage/test/database/setup.rb b/activestorage/test/database/setup.rb
index 87564499e6..705650a25d 100644
--- a/activestorage/test/database/setup.rb
+++ b/activestorage/test/database/setup.rb
@@ -3,5 +3,5 @@
require_relative "create_users_migration"
ActiveRecord::Base.establish_connection(adapter: "sqlite3", database: ":memory:")
-ActiveRecord::Migrator.migrate File.expand_path("../../../db/migrate", __FILE__)
+ActiveRecord::Migrator.migrate File.expand_path("../../db/migrate", __dir__)
ActiveStorageCreateUsers.migrate(:up)
diff --git a/activestorage/test/dummy/bin/bundle b/activestorage/test/dummy/bin/bundle
index 277e128251..5015ba6f8b 100755
--- a/activestorage/test/dummy/bin/bundle
+++ b/activestorage/test/dummy/bin/bundle
@@ -1,5 +1,5 @@
#!/usr/bin/env ruby
# frozen_string_literal: true
-ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", __FILE__)
+ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__)
load Gem.bin_path("bundler", "bundle")
diff --git a/activestorage/test/models/preview_test.rb b/activestorage/test/models/preview_test.rb
index 317a2d5c58..bcd8442f4b 100644
--- a/activestorage/test/models/preview_test.rb
+++ b/activestorage/test/models/preview_test.rb
@@ -7,6 +7,7 @@ class ActiveStorage::PreviewTest < ActiveSupport::TestCase
test "previewing a PDF" do
blob = create_file_blob(filename: "report.pdf", content_type: "application/pdf")
preview = blob.preview(resize: "640x280").processed
+
assert preview.image.attached?
assert_equal "report.png", preview.image.filename.to_s
assert_equal "image/png", preview.image.content_type
@@ -19,6 +20,7 @@ class ActiveStorage::PreviewTest < ActiveSupport::TestCase
test "previewing an MP4 video" do
blob = create_file_blob(filename: "video.mp4", content_type: "video/mp4")
preview = blob.preview(resize: "640x280").processed
+
assert preview.image.attached?
assert_equal "video.png", preview.image.filename.to_s
assert_equal "image/png", preview.image.content_type
diff --git a/activestorage/test/models/representation_test.rb b/activestorage/test/models/representation_test.rb
new file mode 100644
index 0000000000..29fe61aee4
--- /dev/null
+++ b/activestorage/test/models/representation_test.rb
@@ -0,0 +1,41 @@
+# frozen_string_literal: true
+
+require "test_helper"
+require "database/setup"
+
+class ActiveStorage::RepresentationTest < ActiveSupport::TestCase
+ test "representing an image" do
+ blob = create_file_blob
+ representation = blob.representation(resize: "100x100").processed
+
+ image = read_image(representation.image)
+ assert_equal 100, image.width
+ assert_equal 67, image.height
+ end
+
+ test "representing a PDF" do
+ blob = create_file_blob(filename: "report.pdf", content_type: "application/pdf")
+ representation = blob.representation(resize: "640x280").processed
+
+ image = read_image(representation.image)
+ assert_equal 612, image.width
+ assert_equal 792, image.height
+ end
+
+ test "representing an MP4 video" do
+ blob = create_file_blob(filename: "video.mp4", content_type: "video/mp4")
+ representation = blob.representation(resize: "640x280").processed
+
+ image = read_image(representation.image)
+ assert_equal 640, image.width
+ assert_equal 480, image.height
+ end
+
+ test "representing an unrepresentable blob" do
+ blob = create_blob
+
+ assert_raises ActiveStorage::Blob::UnrepresentableError do
+ blob.representation resize: "100x100"
+ end
+ end
+end
diff --git a/activestorage/test/test_helper.rb b/activestorage/test/test_helper.rb
index dd37239060..60656feb80 100644
--- a/activestorage/test/test_helper.rb
+++ b/activestorage/test/test_helper.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require File.expand_path("../../test/dummy/config/environment.rb", __FILE__)
+require_relative "dummy/config/environment.rb"
require "bundler/setup"
require "active_support"
@@ -23,7 +23,7 @@ Minitest.backtrace_filter = Minitest::BacktraceFilter.new
require "yaml"
SERVICE_CONFIGURATIONS = begin
- erb = ERB.new(Pathname.new(File.expand_path("../service/configurations.yml", __FILE__)).read)
+ erb = ERB.new(Pathname.new(File.expand_path("service/configurations.yml", __dir__)).read)
configuration = YAML.load(erb.result) || {}
configuration.deep_symbolize_keys
rescue Errno::ENOENT
@@ -38,7 +38,7 @@ ActiveStorage::Service.logger = ActiveSupport::Logger.new(nil)
ActiveStorage.verifier = ActiveSupport::MessageVerifier.new("Testing")
class ActiveSupport::TestCase
- self.file_fixture_path = File.expand_path("../fixtures/files", __FILE__)
+ self.file_fixture_path = File.expand_path("fixtures/files", __dir__)
private
def create_blob(data: "Hello world!", filename: "hello.txt", content_type: "text/plain")
diff --git a/guides/source/active_record_querying.md b/guides/source/active_record_querying.md
index 3573c3c77b..3786343fc3 100644
--- a/guides/source/active_record_querying.md
+++ b/guides/source/active_record_querying.md
@@ -1712,10 +1712,10 @@ Client.find_by_sql("SELECT * FROM clients
### `select_all`
-`find_by_sql` has a close relative called `connection#select_all`. `select_all` will retrieve objects from the database using custom SQL just like `find_by_sql` but will not instantiate them. Instead, you will get an array of hashes where each hash indicates a record.
+`find_by_sql` has a close relative called `connection#select_all`. `select_all` will retrieve objects from the database using custom SQL just like `find_by_sql` but will not instantiate them. This method will return an instance of `ActiveRecord::Result` class and calling `to_hash` on this object would return you an array of hashes where each hash indicates a record.
```ruby
-Client.connection.select_all("SELECT first_name, created_at FROM clients WHERE id = '1'")
+Client.connection.select_all("SELECT first_name, created_at FROM clients WHERE id = '1'").to_hash
# => [
# {"first_name"=>"Rafael", "created_at"=>"2012-11-10 23:23:45.281189"},
# {"first_name"=>"Eileen", "created_at"=>"2013-12-09 11:22:35.221282"}
diff --git a/guides/source/active_support_instrumentation.md b/guides/source/active_support_instrumentation.md
index 3b31557f41..25f78fd940 100644
--- a/guides/source/active_support_instrumentation.md
+++ b/guides/source/active_support_instrumentation.md
@@ -197,6 +197,12 @@ INFO. Additional keys may be added by the caller.
}
```
+### unpermitted_parameters.action_controller
+
+| Key | Value |
+| ------- | ---------------- |
+| `:keys` | Unpermitted keys |
+
Action View
-----------
@@ -337,6 +343,22 @@ Action Mailer
}
```
+### process.action_mailer
+
+| Key | Value |
+| ------------- | ------------------------ |
+| `:mailer` | Name of the mailer class |
+| `:action` | The action |
+| `:args` | The arguments |
+
+```ruby
+{
+ mailer: "Notification",
+ action: "welcome_email",
+ args: []
+}
+```
+
Active Support
--------------
@@ -450,6 +472,45 @@ Active Job
| `:adapter` | QueueAdapter object processing the job |
| `:job` | Job object |
+Action Cable
+------------
+
+### perform_action.action_cable
+
+| Key | Value |
+| ---------------- | ------------------------- |
+| `:channel_class` | Name of the channel class |
+| `:action` | The action |
+| `:data` | A hash of data |
+
+### transmit.action_cable
+
+| Key | Value |
+| ---------------- | ------------------------- |
+| `:channel_class` | Name of the channel class |
+| `:data` | A hash of data |
+| `:via` | Via |
+
+### transmit_subscription_confirmation.action_cable
+
+| Key | Value |
+| ---------------- | ------------------------- |
+| `:channel_class` | Name of the channel class |
+
+### transmit_subscription_rejection.action_cable
+
+| Key | Value |
+| ---------------- | ------------------------- |
+| `:channel_class` | Name of the channel class |
+
+### broadcast.action_cable
+
+| Key | Value |
+| --------------- | -------------------- |
+| `:broadcasting` | A named broadcasting |
+| `:message` | A hash of message |
+| `:coder` | The coder |
+
Active Storage
--------------
diff --git a/guides/source/working_with_javascript_in_rails.md b/guides/source/working_with_javascript_in_rails.md
index 098366ec1b..b2716c7faa 100644
--- a/guides/source/working_with_javascript_in_rails.md
+++ b/guides/source/working_with_javascript_in_rails.md
@@ -174,7 +174,7 @@ passing the `:local` option `form_with`.
This will generate the following HTML:
```html
-<form action="/articles" method="post" data-remote="true">
+<form action="/articles" accept-charset="UTF-8" method="post" data-remote="true">
...
</form>
```
diff --git a/railties/test/commands/server_test.rb b/railties/test/commands/server_test.rb
index a6201e4f04..33715ea75f 100644
--- a/railties/test/commands/server_test.rb
+++ b/railties/test/commands/server_test.rb
@@ -22,6 +22,18 @@ class Rails::ServerTest < ActiveSupport::TestCase
assert_nil options[:server]
end
+ def test_daemon_with_option
+ args = ["-d"]
+ options = parse_arguments(args)
+ assert_equal true, options[:daemonize]
+ end
+
+ def test_daemon_without_option
+ args = []
+ options = parse_arguments(args)
+ assert_equal false, options[:daemonize]
+ end
+
def test_server_option_without_environment
args = ["thin"]
with_rack_env nil do
diff --git a/railties/test/generators/argv_scrubber_test.rb b/railties/test/generators/argv_scrubber_test.rb
index 3f4c985a33..9ef61dc978 100644
--- a/railties/test/generators/argv_scrubber_test.rb
+++ b/railties/test/generators/argv_scrubber_test.rb
@@ -82,9 +82,8 @@ module Rails
file.puts "--hello --world"
file.flush
- message = nil
scrubber = Class.new(ARGVScrubber) {
- define_method(:puts) { |msg| message = msg }
+ define_method(:puts) { |msg| }
}.new ["new", "--rc=#{file.path}"]
args = scrubber.prepare!
assert_equal ["--hello", "--world"], args