aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--actionpack/CHANGELOG.md6
-rw-r--r--actionpack/lib/action_controller/metal/redirecting.rb2
-rw-r--r--activejob/test/support/integration/adapters/sidekiq.rb1
-rw-r--r--activerecord/lib/active_record/relation/query_methods.rb4
-rw-r--r--activerecord/test/cases/base_test.rb10
-rw-r--r--activerecord/test/cases/locking_test.rb4
-rw-r--r--activestorage/app/controllers/active_storage/blobs_controller.rb10
-rw-r--r--activestorage/app/controllers/active_storage/previews_controller.rb10
-rw-r--r--activestorage/app/controllers/active_storage/variants_controller.rb10
-rw-r--r--activestorage/app/controllers/concerns/active_storage/set_blob.rb16
-rw-r--r--activestorage/app/models/active_storage/blob.rb6
-rw-r--r--activestorage/app/models/active_storage/variant.rb37
-rw-r--r--activestorage/test/controllers/blobs_controller_test.rb5
-rw-r--r--activestorage/test/controllers/previews_controller_test.rb9
-rw-r--r--activestorage/test/controllers/variants_controller_test.rb9
-rw-r--r--activestorage/test/fixtures/files/icon.psdbin0 -> 37441 bytes
-rw-r--r--activestorage/test/models/variant_test.rb28
-rw-r--r--activesupport/CHANGELOG.md6
-rw-r--r--activesupport/lib/active_support/digest.rb10
-rw-r--r--activesupport/lib/active_support/railtie.rb4
-rw-r--r--activesupport/test/digest_test.rb2
-rw-r--r--guides/source/active_storage_overview.md22
-rw-r--r--guides/source/association_basics.md8
-rw-r--r--guides/source/contributing_to_ruby_on_rails.md4
-rw-r--r--railties/test/railties/engine_test.rb15
25 files changed, 164 insertions, 74 deletions
diff --git a/actionpack/CHANGELOG.md b/actionpack/CHANGELOG.md
index 384546d7b4..c75f0e83ac 100644
--- a/actionpack/CHANGELOG.md
+++ b/actionpack/CHANGELOG.md
@@ -111,9 +111,9 @@
*Rafael Mendonça França*
* Add `:allow_other_host` option to `redirect_back` method.
- When `allow_other_host` is set to `false`, the `redirect_back`
- will not allow a redirecting from a different host.
- `allow_other_host` is `true` by default.
+
+ When `allow_other_host` is set to `false`, the `redirect_back` will not allow redirecting from a
+ different host. `allow_other_host` is `true` by default.
*Tim Masliuchenko*
diff --git a/actionpack/lib/action_controller/metal/redirecting.rb b/actionpack/lib/action_controller/metal/redirecting.rb
index 87a2e29a3f..4c2b5120eb 100644
--- a/actionpack/lib/action_controller/metal/redirecting.rb
+++ b/actionpack/lib/action_controller/metal/redirecting.rb
@@ -83,7 +83,7 @@ module ActionController
#
# ==== Options
# * <tt>:fallback_location</tt> - The default fallback location that will be used on missing +Referer+ header.
- # * <tt>:allow_other_host</tt> - Allows or disallow redirection to the host that is different to the current host
+ # * <tt>:allow_other_host</tt> - Allow or disallow redirection to the host that is different to the current host, defaults to true.
#
# All other options that can be passed to <tt>redirect_to</tt> are accepted as
# options and the behavior is identical.
diff --git a/activejob/test/support/integration/adapters/sidekiq.rb b/activejob/test/support/integration/adapters/sidekiq.rb
index 4b01a81ec5..c79de12eaf 100644
--- a/activejob/test/support/integration/adapters/sidekiq.rb
+++ b/activejob/test/support/integration/adapters/sidekiq.rb
@@ -51,6 +51,7 @@ module SidekiqJobsManager
self_write.puts("TERM")
end
+ require "sidekiq/cli"
require "sidekiq/launcher"
sidekiq = Sidekiq::Launcher.new(queues: ["integration_tests"],
environment: "test",
diff --git a/activerecord/lib/active_record/relation/query_methods.rb b/activerecord/lib/active_record/relation/query_methods.rb
index 6b3ff3d610..2056f9bb73 100644
--- a/activerecord/lib/active_record/relation/query_methods.rb
+++ b/activerecord/lib/active_record/relation/query_methods.rb
@@ -1040,8 +1040,8 @@ module ActiveRecord
def build_select(arel)
if select_values.any?
arel.project(*arel_columns(select_values.uniq))
- elsif @klass.ignored_columns.any?
- arel.project(*arel_columns(@klass.column_names.map(&:to_sym)))
+ elsif klass.ignored_columns.any?
+ arel.project(*klass.column_names.map { |field| arel_attribute(field) })
else
arel.project(table[Arel.star])
end
diff --git a/activerecord/test/cases/base_test.rb b/activerecord/test/cases/base_test.rb
index 7fc4a396e4..b076b452e7 100644
--- a/activerecord/test/cases/base_test.rb
+++ b/activerecord/test/cases/base_test.rb
@@ -1498,10 +1498,14 @@ class BasicsTest < ActiveRecord::TestCase
test "column names are quoted when using #from clause and model has ignored columns" do
refute_empty Developer.ignored_columns
- query = Developer.from("`developers`").to_sql
- quoted_id = Developer.connection.quote_table_name("id")
+ query = Developer.from("developers").to_sql
+ quoted_id = "#{Developer.quoted_table_name}.#{Developer.quoted_primary_key}"
- assert_match(/SELECT #{quoted_id}.* FROM `developers`/, query)
+ assert_match(/SELECT #{quoted_id}.* FROM developers/, query)
+ end
+
+ test "using table name qualified column names unless having SELECT list explicitly" do
+ assert_equal developers(:david), Developer.from("developers").joins(:shared_computers).take
end
test "protected environments by default is an array with production" do
diff --git a/activerecord/test/cases/locking_test.rb b/activerecord/test/cases/locking_test.rb
index 437a5a38a3..3701be4b11 100644
--- a/activerecord/test/cases/locking_test.rb
+++ b/activerecord/test/cases/locking_test.rb
@@ -406,7 +406,7 @@ class OptimisticLockingTest < ActiveRecord::TestCase
assert_equal 0, car.lock_version
previously_car_updated_at = car.updated_at
- travel(1.second) do
+ travel(2.second) do
Wheel.create!(wheelable: car)
end
@@ -422,7 +422,7 @@ class OptimisticLockingTest < ActiveRecord::TestCase
assert_equal 2, car.lock_version
previously_car_updated_at = car.updated_at
- travel(1.second) do
+ travel(2.second) do
car.wheels.first.destroy!
end
diff --git a/activestorage/app/controllers/active_storage/blobs_controller.rb b/activestorage/app/controllers/active_storage/blobs_controller.rb
index a17e3852f9..fa44131048 100644
--- a/activestorage/app/controllers/active_storage/blobs_controller.rb
+++ b/activestorage/app/controllers/active_storage/blobs_controller.rb
@@ -5,12 +5,10 @@
# security-through-obscurity factor of the signed blob references, you'll need to implement your own
# authenticated redirection controller.
class ActiveStorage::BlobsController < ActionController::Base
+ include ActiveStorage::SetBlob
+
def show
- if blob = ActiveStorage::Blob.find_signed(params[:signed_id])
- expires_in ActiveStorage::Blob.service.url_expires_in
- redirect_to blob.service_url(disposition: params[:disposition])
- else
- head :not_found
- end
+ expires_in ActiveStorage::Blob.service.url_expires_in
+ redirect_to @blob.service_url(disposition: params[:disposition])
end
end
diff --git a/activestorage/app/controllers/active_storage/previews_controller.rb b/activestorage/app/controllers/active_storage/previews_controller.rb
index 9e8cf27b6e..aa7ef58ca4 100644
--- a/activestorage/app/controllers/active_storage/previews_controller.rb
+++ b/activestorage/app/controllers/active_storage/previews_controller.rb
@@ -1,12 +1,10 @@
# frozen_string_literal: true
class ActiveStorage::PreviewsController < ActionController::Base
+ include ActiveStorage::SetBlob
+
def show
- if blob = ActiveStorage::Blob.find_signed(params[:signed_blob_id])
- expires_in ActiveStorage::Blob.service.url_expires_in
- redirect_to ActiveStorage::Preview.new(blob, params[:variation_key]).processed.service_url(disposition: params[:disposition])
- else
- head :not_found
- end
+ expires_in ActiveStorage::Blob.service.url_expires_in
+ redirect_to ActiveStorage::Preview.new(@blob, params[:variation_key]).processed.service_url(disposition: params[:disposition])
end
end
diff --git a/activestorage/app/controllers/active_storage/variants_controller.rb b/activestorage/app/controllers/active_storage/variants_controller.rb
index dc5e78ecc0..e8f8dd592d 100644
--- a/activestorage/app/controllers/active_storage/variants_controller.rb
+++ b/activestorage/app/controllers/active_storage/variants_controller.rb
@@ -5,12 +5,10 @@
# security-through-obscurity factor of the signed blob and variation reference, you'll need to implement your own
# authenticated redirection controller.
class ActiveStorage::VariantsController < ActionController::Base
+ include ActiveStorage::SetBlob
+
def show
- if blob = ActiveStorage::Blob.find_signed(params[:signed_blob_id])
- expires_in ActiveStorage::Blob.service.url_expires_in
- redirect_to ActiveStorage::Variant.new(blob, params[:variation_key]).processed.service_url(disposition: params[:disposition])
- else
- head :not_found
- end
+ expires_in ActiveStorage::Blob.service.url_expires_in
+ redirect_to ActiveStorage::Variant.new(@blob, params[:variation_key]).processed.service_url(disposition: params[:disposition])
end
end
diff --git a/activestorage/app/controllers/concerns/active_storage/set_blob.rb b/activestorage/app/controllers/concerns/active_storage/set_blob.rb
new file mode 100644
index 0000000000..b0f3d97a66
--- /dev/null
+++ b/activestorage/app/controllers/concerns/active_storage/set_blob.rb
@@ -0,0 +1,16 @@
+# frozen_string_literal: true
+
+module ActiveStorage::SetBlob
+ extend ActiveSupport::Concern
+
+ included do
+ before_action :set_blob
+ end
+
+ private
+ def set_blob
+ @blob = ActiveStorage::Blob.find_signed(params[:signed_blob_id] || params[:signed_id])
+ rescue ActiveSupport::MessageVerifier::InvalidSignature
+ head :not_found
+ end
+end
diff --git a/activestorage/app/models/active_storage/blob.rb b/activestorage/app/models/active_storage/blob.rb
index fdf17ac67e..3b48ee72af 100644
--- a/activestorage/app/models/active_storage/blob.rb
+++ b/activestorage/app/models/active_storage/blob.rb
@@ -172,11 +172,11 @@ class ActiveStorage::Blob < ActiveRecord::Base
end
- # Returns an ActiveStorage::Preview instance for a previewable blob or an ActiveStorage::Variant instance for an image blob.
+ # Returns an ActiveStorage::Preview for a previewable blob or an ActiveStorage::Variant for a variable image blob.
#
# blob.representation(resize: "100x100").processed.service_url
#
- # Raises ActiveStorage::Blob::UnrepresentableError if the receiving blob is neither an image nor previewable. Call
+ # Raises ActiveStorage::Blob::UnrepresentableError if the receiving blob is neither variable nor previewable. Call
# ActiveStorage::Blob#representable? to determine whether a blob is representable.
#
# See ActiveStorage::Blob#preview and ActiveStorage::Blob#variant for more information.
@@ -191,7 +191,7 @@ class ActiveStorage::Blob < ActiveRecord::Base
end
end
- # Returns true if the blob is variable or is previewable.
+ # Returns true if the blob is variable or previewable.
def representable?
variable? || previewable?
end
diff --git a/activestorage/app/models/active_storage/variant.rb b/activestorage/app/models/active_storage/variant.rb
index fa5aa69bd3..8909fd628a 100644
--- a/activestorage/app/models/active_storage/variant.rb
+++ b/activestorage/app/models/active_storage/variant.rb
@@ -35,6 +35,8 @@
#
# avatar.variant(resize: "100x100", monochrome: true, flip: "-90")
class ActiveStorage::Variant
+ WEB_IMAGE_CONTENT_TYPES = %w( image/png image/jpeg image/jpg image/gif )
+
attr_reader :blob, :variation
delegate :service, to: :blob
@@ -62,7 +64,7 @@ class ActiveStorage::Variant
# for a variant that points to the ActiveStorage::VariantsController, which in turn will use this +service_call+ method
# for its redirection.
def service_url(expires_in: service.url_expires_in, disposition: :inline)
- service.url key, expires_in: expires_in, disposition: disposition, filename: blob.filename, content_type: blob.content_type
+ service.url key, expires_in: expires_in, disposition: disposition, filename: filename, content_type: content_type
end
# Returns the receiving variant. Allows ActiveStorage::Variant and ActiveStorage::Preview instances to be used interchangeably.
@@ -76,11 +78,40 @@ class ActiveStorage::Variant
end
def process
- service.upload key, transform(service.download(blob.key))
+ service.upload key, transform(blob.download)
+ end
+
+
+ def filename
+ if WEB_IMAGE_CONTENT_TYPES.include?(blob.content_type)
+ blob.filename
+ else
+ ActiveStorage::Filename.new("#{blob.filename.base}.png")
+ end
end
+ def content_type
+ blob.content_type.presence_in(WEB_IMAGE_CONTENT_TYPES) || "image/png"
+ end
+
+
def transform(io)
+ read_image_from(io) do |image|
+ mogrify image
+ format image
+ end
+ end
+
+ def read_image_from(io, &block)
require "mini_magick"
- File.open MiniMagick::Image.read(io).tap { |image| variation.transform(image) }.path
+ File.open MiniMagick::Image.read(io).tap(&block).path
+ end
+
+ def mogrify(image)
+ variation.transform(image)
+ end
+
+ def format(image)
+ image.format("PNG") unless WEB_IMAGE_CONTENT_TYPES.include?(blob.content_type)
end
end
diff --git a/activestorage/test/controllers/blobs_controller_test.rb b/activestorage/test/controllers/blobs_controller_test.rb
index 97177e64c2..9c811df895 100644
--- a/activestorage/test/controllers/blobs_controller_test.rb
+++ b/activestorage/test/controllers/blobs_controller_test.rb
@@ -8,6 +8,11 @@ class ActiveStorage::BlobsControllerTest < ActionDispatch::IntegrationTest
@blob = create_file_blob filename: "racecar.jpg"
end
+ test "showing blob with invalid signed ID" do
+ get rails_service_blob_url("invalid", "racecar.jpg")
+ assert_response :not_found
+ end
+
test "showing blob utilizes browser caching" do
get rails_blob_url(@blob)
diff --git a/activestorage/test/controllers/previews_controller_test.rb b/activestorage/test/controllers/previews_controller_test.rb
index c3151a710e..704a466160 100644
--- a/activestorage/test/controllers/previews_controller_test.rb
+++ b/activestorage/test/controllers/previews_controller_test.rb
@@ -21,4 +21,13 @@ class ActiveStorage::PreviewsControllerTest < ActionDispatch::IntegrationTest
assert_equal 77, image.width
assert_equal 100, image.height
end
+
+ test "showing preview with invalid signed blob ID" do
+ get rails_blob_preview_url(
+ filename: @blob.filename,
+ signed_blob_id: "invalid",
+ variation_key: ActiveStorage::Variation.encode(resize: "100x100"))
+
+ assert_response :not_found
+ end
end
diff --git a/activestorage/test/controllers/variants_controller_test.rb b/activestorage/test/controllers/variants_controller_test.rb
index 6c70d73786..a0642f9bed 100644
--- a/activestorage/test/controllers/variants_controller_test.rb
+++ b/activestorage/test/controllers/variants_controller_test.rb
@@ -20,4 +20,13 @@ class ActiveStorage::VariantsControllerTest < ActionDispatch::IntegrationTest
assert_equal 100, image.width
assert_equal 67, image.height
end
+
+ test "showing variant with invalid signed blob ID" do
+ get rails_blob_variation_url(
+ filename: @blob.filename,
+ signed_blob_id: "invalid",
+ variation_key: ActiveStorage::Variation.encode(resize: "100x100"))
+
+ assert_response :not_found
+ end
end
diff --git a/activestorage/test/fixtures/files/icon.psd b/activestorage/test/fixtures/files/icon.psd
new file mode 100644
index 0000000000..631fceeaab
--- /dev/null
+++ b/activestorage/test/fixtures/files/icon.psd
Binary files differ
diff --git a/activestorage/test/models/variant_test.rb b/activestorage/test/models/variant_test.rb
index 83ebce4446..8eced41ee0 100644
--- a/activestorage/test/models/variant_test.rb
+++ b/activestorage/test/models/variant_test.rb
@@ -4,12 +4,9 @@ require "test_helper"
require "database/setup"
class ActiveStorage::VariantTest < ActiveSupport::TestCase
- setup do
- @blob = create_file_blob filename: "racecar.jpg"
- end
-
- test "resized variation" do
- variant = @blob.variant(resize: "100x100").processed
+ test "resized variation of JPEG blob" do
+ blob = create_file_blob(filename: "racecar.jpg")
+ variant = blob.variant(resize: "100x100").processed
assert_match(/racecar\.jpg/, variant.service_url)
image = read_image(variant)
@@ -17,8 +14,9 @@ class ActiveStorage::VariantTest < ActiveSupport::TestCase
assert_equal 67, image.height
end
- test "resized and monochrome variation" do
- variant = @blob.variant(resize: "100x100", monochrome: true).processed
+ test "resized and monochrome variation of JPEG blob" do
+ blob = create_file_blob(filename: "racecar.jpg")
+ variant = blob.variant(resize: "100x100", monochrome: true).processed
assert_match(/racecar\.jpg/, variant.service_url)
image = read_image(variant)
@@ -27,6 +25,17 @@ class ActiveStorage::VariantTest < ActiveSupport::TestCase
assert_match(/Gray/, image.colorspace)
end
+ test "resized variation of PSD blob" do
+ blob = create_file_blob(filename: "icon.psd", content_type: "image/vnd.adobe.photoshop")
+ variant = blob.variant(resize: "20x20").processed
+ assert_match(/icon\.png/, variant.service_url)
+
+ image = read_image(variant)
+ assert_equal "PNG", image.type
+ assert_equal 20, image.width
+ assert_equal 20, image.height
+ end
+
test "variation of invariable blob" do
assert_raises ActiveStorage::Blob::InvariableError do
create_file_blob(filename: "report.pdf", content_type: "application/pdf").variant(resize: "100x100")
@@ -34,7 +43,8 @@ class ActiveStorage::VariantTest < ActiveSupport::TestCase
end
test "service_url doesn't grow in length despite long variant options" do
- variant = @blob.variant(font: "a" * 10_000).processed
+ blob = create_file_blob(filename: "racecar.jpg")
+ variant = blob.variant(font: "a" * 10_000).processed
assert_operator variant.service_url.length, :<, 500
end
end
diff --git a/activesupport/CHANGELOG.md b/activesupport/CHANGELOG.md
index abbadd404f..fccaeb5d32 100644
--- a/activesupport/CHANGELOG.md
+++ b/activesupport/CHANGELOG.md
@@ -1,7 +1,7 @@
-* Introduced `ActiveSupport::Digest` that allows to specify hash function implementation
- and defaults to `Digest::MD5`.
+* Allow the hash function used to generate non-sensitive digests, such as the
+ ETag header, to be specified with `config.active_support.hash_digest_class`.
- Replaced calls to `::Digest::MD5.hexdigest` with calls to `ActiveSupport::Digest.hexdigest`.
+ The object provided must respond to `#hexdigest`, e.g. `Digest::SHA1`.
*Dmitri Dolguikh*
diff --git a/activesupport/lib/active_support/digest.rb b/activesupport/lib/active_support/digest.rb
index d77eeb072b..fba10fbdcf 100644
--- a/activesupport/lib/active_support/digest.rb
+++ b/activesupport/lib/active_support/digest.rb
@@ -13,16 +13,8 @@ module ActiveSupport
end
def hexdigest(arg)
- new.hexdigest(arg)
+ hash_digest_class.hexdigest(arg)[0...32]
end
end
-
- def initialize(digest_class: nil)
- @digest_class = digest_class || self.class.hash_digest_class
- end
-
- def hexdigest(arg)
- @digest_class.hexdigest(arg).truncate(32)
- end
end
end
diff --git a/activesupport/lib/active_support/railtie.rb b/activesupport/lib/active_support/railtie.rb
index 3488721df9..91872e29c8 100644
--- a/activesupport/lib/active_support/railtie.rb
+++ b/activesupport/lib/active_support/railtie.rb
@@ -68,9 +68,9 @@ module ActiveSupport
end
initializer "active_support.set_hash_digest_class" do |app|
- if app.config.active_support.respond_to?(:use_hash_digest_class) && app.config.active_support.use_hash_digest_class
+ if app.config.active_support.respond_to?(:hash_digest_class) && app.config.active_support.hash_digest_class
ActiveSupport::Digest.hash_digest_class =
- app.config.active_support.use_hash_digest_class
+ app.config.active_support.hash_digest_class
end
end
end
diff --git a/activesupport/test/digest_test.rb b/activesupport/test/digest_test.rb
index 5dec75b9fe..83ff2a8d83 100644
--- a/activesupport/test/digest_test.rb
+++ b/activesupport/test/digest_test.rb
@@ -16,7 +16,7 @@ class DigestTest < ActiveSupport::TestCase
digest = ActiveSupport::Digest.hexdigest("hello friend")
assert_equal 32, digest.length
- assert_equal ::Digest::SHA1.hexdigest("hello friend").truncate(32), digest
+ assert_equal ::Digest::SHA1.hexdigest("hello friend")[0...32], digest
ensure
ActiveSupport::Digest.hash_digest_class = original_hash_digest_class
end
diff --git a/guides/source/active_storage_overview.md b/guides/source/active_storage_overview.md
index dbce074388..38323c089f 100644
--- a/guides/source/active_storage_overview.md
+++ b/guides/source/active_storage_overview.md
@@ -46,7 +46,7 @@ the migration is generated automatically.
Declare Active Storage services in `config/storage.yml`. For each service your
application uses, provide a name and the requisite configuration. The example
-below declares three services named `local`, `test`, and `s3`:
+below declares three services named `local`, `test`, and `amazon`:
```yaml
local:
@@ -57,7 +57,7 @@ test:
service: Disk
root: <%= Rails.root.join("tmp/storage") %>
-s3:
+amazon:
service: S3
access_key_id: ""
secret_access_key: ""
@@ -75,12 +75,12 @@ development environment, you would add the following to
config.active_storage.service = :local
```
-To use the s3 service in production, you add the following to
+To use the Amazon S3 service in production, you add the following to
`config/environments/production.rb`:
```ruby
-# Store files in S3.
-config.active_storage.service = :s3
+# Store files on Amazon S3.
+config.active_storage.service = :amazon
```
Continue reading for more information on the built-in service adapters (e.g.
@@ -101,7 +101,7 @@ local:
Declare an S3 service in `config/storage.yml`:
``` yaml
-s3:
+amazon:
service: S3
access_key_id: ""
secret_access_key: ""
@@ -204,7 +204,7 @@ Attach Files to a Model
The `has_one_attached` macro sets up a one-to-one mapping between records and
files. Each record can have one file attached to it.
-For example, suppose your application has a User model. If you want each user to
+For example, suppose your application has a `User` model. If you want each user to
have an avatar, define the `User` model like this:
``` ruby
@@ -218,7 +218,7 @@ You can create a user with an avatar:
``` ruby
class SignupController < ApplicationController
def create
- user = Users.create!(user_params)
+ user = User.create!(user_params)
session[:user_id] = user.id
redirect_to root_path
end
@@ -248,7 +248,7 @@ The `has_many_attached` macro sets up a one-to-many relationship between records
and files. Each record can have many files attached to it.
For example, suppose your application has a `Message` model. If you want each
-message to have many images, define the Message model like this:
+message to have many images, define the `Message` model like this:
```ruby
class Message < ApplicationRecord
@@ -332,7 +332,7 @@ To enable variants, add `mini_magick` to your `Gemfile`:
gem 'mini_magick'
```
-When the browser hits the variant URL, ActiveStorage will lazy transform the
+When the browser hits the variant URL, Active Storage will lazy transform the
original blob into the format you specified and redirect to its new service
location.
@@ -508,7 +508,7 @@ System tests clean up test data by rolling back a transaction. Because destroy
is never called on an object, the attached files are never cleaned up. If you
want to clear the files, you can do it in an `after_teardown` callback. Doing it
here ensures that all connections created during the test are complete and
-you won't receive an error from ActiveStorage saying it can't find a file.
+you won't receive an error from Active Storage saying it can't find a file.
``` ruby
class ApplicationSystemTestCase < ActionDispatch::SystemTestCase
diff --git a/guides/source/association_basics.md b/guides/source/association_basics.md
index 9616647f15..b5e236b790 100644
--- a/guides/source/association_basics.md
+++ b/guides/source/association_basics.md
@@ -1561,7 +1561,8 @@ The `collection.size` method returns the number of objects in the collection.
##### `collection.find(...)`
-The `collection.find` method finds objects within the collection. It uses the same syntax and options as `ActiveRecord::Base.find`.
+The `collection.find` method finds objects within the collection. It uses the same syntax and options as
+[`ActiveRecord::Base.find`](http://api.rubyonrails.org/classes/ActiveRecord/FinderMethods.html#method-i-find).
```ruby
@available_book = @author.books.find(1)
@@ -2091,7 +2092,8 @@ The `collection.size` method returns the number of objects in the collection.
##### `collection.find(...)`
-The `collection.find` method finds objects within the collection. It uses the same syntax and options as `ActiveRecord::Base.find`. It also adds the additional condition that the object must be in the collection.
+The `collection.find` method finds objects within the collection. It uses the same syntax and options as
+[`ActiveRecord::Base.find`](http://api.rubyonrails.org/classes/ActiveRecord/FinderMethods.html#method-i-find).
```ruby
@assembly = @part.assemblies.find(1)
@@ -2099,7 +2101,7 @@ The `collection.find` method finds objects within the collection. It uses the sa
##### `collection.where(...)`
-The `collection.where` method finds objects within the collection based on the conditions supplied but the objects are loaded lazily meaning that the database is queried only when the object(s) are accessed. It also adds the additional condition that the object must be in the collection.
+The `collection.where` method finds objects within the collection based on the conditions supplied but the objects are loaded lazily meaning that the database is queried only when the object(s) are accessed.
```ruby
@new_assemblies = @part.assemblies.where("created_at > ?", 2.days.ago)
diff --git a/guides/source/contributing_to_ruby_on_rails.md b/guides/source/contributing_to_ruby_on_rails.md
index 7424818757..967c992c05 100644
--- a/guides/source/contributing_to_ruby_on_rails.md
+++ b/guides/source/contributing_to_ruby_on_rails.md
@@ -84,7 +84,9 @@ discussions new features require.
Helping to Resolve Existing Issues
----------------------------------
-As a next step beyond reporting issues, you can help the core team resolve existing issues. If you check the [issues list](https://github.com/rails/rails/issues) in GitHub Issues, you'll find lots of issues already requiring attention. What can you do for these? Quite a bit, actually:
+As a next step beyond reporting issues, you can help the core team resolve existing ones by providing feedback about them. If you are new to Rails core development, that might be a great way to walk your first steps, you'll get familiar with the code base and the processes.
+
+If you check the [issues list](https://github.com/rails/rails/issues) in GitHub Issues, you'll find lots of issues already requiring attention. What can you do for these? Quite a bit, actually:
### Verifying Bug Reports
diff --git a/railties/test/railties/engine_test.rb b/railties/test/railties/engine_test.rb
index 4a861bff55..339a56c34f 100644
--- a/railties/test/railties/engine_test.rb
+++ b/railties/test/railties/engine_test.rb
@@ -1479,6 +1479,21 @@ YAML
assert_equal "/fruits/2/bukkits/posts", last_response.body
end
+ test "active_storage:install task works within engine" do
+ @plugin.write "Rakefile", <<-RUBY
+ APP_RAKEFILE = '#{app_path}/Rakefile'
+ load 'rails/tasks/engine.rake'
+ RUBY
+
+ Dir.chdir(@plugin.path) do
+ output = `bundle exec rake app:active_storage:install`
+ assert $?.success?, output
+
+ active_storage_migration = migrations.detect { |migration| migration.name == "CreateActiveStorageTables" }
+ assert active_storage_migration
+ end
+ end
+
private
def app
Rails.application