Commit Graph

1056 Commits

Author SHA1 Message Date
Nate Matykiewicz
78ad54569b
Make http_cache_forever use immutable: true 2024-07-06 01:59:39 -05:00
Rafael Mendonça França
3a2ec9bb3a
Merge pull request #51740 from heka1024/parallel-upload-in-mirror-service
Improve performance in `ActiveStorage::Service::MirrorService`
2024-06-21 17:28:47 -04:00
Joé Dupuis
f7ecde8331
Expire caching when a download fail while proxying in ActiveStorage
Fix #51284

Both Proxy controllers in Active Storage set the caching headers early
before streaming.

In some instances (see #51284), it is possible for the file
download (from the service to server) to fail before we send the first
byte to the client (response not yet committed).

In those instances, this change would invalidate the cache and return
a better response status before closing the stream.
2024-06-17 09:49:11 -07:00
Justin Ko
80a6291d7f Add test 2024-05-28 21:13:20 -06:00
Justin Ko
155d0afa31 Allow ActiveStorage::Attachment creation with no record attachments
FIxes #51882
2024-05-28 01:21:22 -06:00
Carlos Antonio da Silva
8150212b78
Merge pull request #51907 from higher-pixels/no-doc-preview-image-needed
Mark `preview_image_needed_before_processing_variants?` as private API
2024-05-24 13:18:27 -03:00
Tom Rossi
5192f31001 Mark preview_image_needed_before_processing_variants? as private API
It looks like `preview_image_needed_before_processing_variants?` was added recently,
but it's stated as being public API.

However, it looks like it's more of an implementation detail that's not meant for Active Storage users.

So this marks it as nodoc, so we're not on the hook for maintaining it.
2024-05-24 15:09:15 +00:00
Rafael Mendonça França
8ea62041ae
Merge pull request #51866 from tnir/tn-update-eslint-from-4.3.0-to-8.40.0
chore(deps-dev): update eslint from 4.19.1 to 8.40.0
2024-05-23 12:23:12 -04:00
Rafael Mendonça França
7ee34d9efb
Enable Rails minitest plugin in our rake tasks 2024-05-23 16:16:37 +00:00
Takuya Noguchi
b6e49a7b1f chore(deps-dev): update eslint from 4.3.0 to 8.40.0
Also update eslint-plugin-import from 2.27.5 to 2.29.0.

Signed-off-by: Takuya Noguchi <takninnovationresearch@gmail.com>
2024-05-23 14:23:15 +09:00
Rafael Mendonça França
bf59d363fb
Clean CHANGELOG for 8.0 2024-05-13 16:55:52 +00:00
Rafael Mendonça França
37fd0e7fe4
Development of Rails 8.0 starts now
🎉
2024-05-13 16:45:20 +00:00
heka1024
3f2258a835 Improve performance by parallelizing ActiveStorage::Service::MirrorService#delete and ActiveStorage::Service::MirrorService#delete_prefixed 2024-05-12 17:07:23 +09:00
Rafael Mendonça França
0cf8444d61
Remove deprecated config.active_storage.silence_invalid_content_types_warning 2024-05-01 18:44:30 +00:00
Rafael Mendonça França
b06252e2a7
Remove deprecated config.active_storage.replace_on_assign_to_many 2024-05-01 18:44:29 +00:00
fatkodima
702638291c
Fix tests without assertions in the framework 2024-04-30 23:29:30 +00:00
David Genord II
8d13216978
Be a lot more memory efficient analyzing images
Vips::Image#avg requires loading and evaluating the entire image. libvips can be a lot more efficient at retrieving the metadata we need.
2024-04-03 16:33:56 -04:00
Rosa Gutierrez
6ecb53cf92 Don't enqueue jobs to process a preview image if no variant requires it
This follows up on https://github.com/rails/rails/pull/51030, that introduces a
behaviour change for previewable attachments that don't specify any variants at all
or no variants that require pre-processing via `TransformJob`.
Before, when no variant required pre-processing, Attachment#transform_variants_later
didn't do anything. Now, a `ActiveStorage::PreviewImageJob` is enqueued with
the attachment's blob and a empty array.
2024-03-20 07:37:32 +01:00
Elvin Efendiev
64178f998e Support custom blob key in ActiveStorage::Blob#compose similar to other Blob APIs 2024-03-11 17:27:19 -04:00
Jeremy Daer
5cedb8745c Illustrator files are previewable with Poppler as well
Extends #51235's MuPDF support to Poppler.

Add test coverage for Blob previews and representation.
2024-03-01 13:04:27 -08:00
Jeremy Daer
bf8e0f5f61 Illustrator .ai files are previewable as PDFs
This happened to work with Marcel 1.0.2 and earlier since magic byte
sniffing sees that Illustrator files are PDFs internally, causing these
files to be treated as `application/pdf` despite having a declared
content type of `application/illustrator` and an `.ai` file extension.

Marcel 1.0.3 corrected this to the more specific `application/illustrator`
subtype of `application/pdf`, but the MuPDF previewer only accepts the
parent `application/pdf` type.

Changing it to accept PDF and any child types allows the previewer to
explicitly work with Illustrator files again, which was only a happy
accident previously.
2024-03-01 10:55:48 -08:00
Jeremy Daer
4f0f3448cd Marcel 1.0.4
Update tests to clarify content type detection heuristic after exposing
a regression in Marcel 1.0.3 that wasn't caught by its test suite:

1. magic bytes
2. declared content type, unless it's binary
3. filename extension
4. binary: application/octet-stream
2024-03-01 09:29:24 -08:00
Jean Boussier
7263da542b Deprecate ConnectionPool#connection
Replaced by `#lease_connection` to better reflect what it does.

`ActiveRecord::Base#connection` is deprecated in the same way
but without a removal timeline nor a deprecation warning.

Inside the Active Record test suite, we do remove `Base.connection`
to ensure it's not used internally.

Some callsites have been converted to use `with_connection`,
some other have been more simply migrated to `lease_connection`
and will serve as a list of callsites to convert for
https://github.com/rails/rails/pull/50793
2024-03-01 14:32:55 +01:00
Jean Boussier
a918394974 Refactor InternalMetadata, MigrationContext to belong to the pool
Extracted from: https://github.com/rails/rails/pull/50793

Similar to the recent refactoring of schema caches, rather than to directly
hold a connection, they now hold a pool and checkout a connection when needed.
2024-02-22 12:46:41 +01:00
Rafael Mendonça França
1400447ff6
Fix quote 2024-02-16 17:08:53 +00:00
Yasuo Honda
034398fdfe Address ActiveStorage::VariantTest#test_resized_variation_of_WEBP_blob failure at Rails Nightly CI
Managed to reproduce Rails Nightly CI failure
at https://buildkite.com/rails/rails-nightly/builds/149#018d9052-1b2d-48fa-9d74-a39df3f3f1d6/1251-1291

This commit allows both 33 and 34 as its height because this issue is isolated
that thedifference comes from libvips and/or ruby-vips behavior differences, not Active Storage.

* Steps to reprodude
Run this test on Ubuntu 22.04. It should not reproduce on Ubuntu 23.10.

```
git clone https://github.com/rails/rails
cd rails
rm Gemfile.lock
cd activestorage
bin/test test/models/variant_test.rb -n test_resized_variation_of_WEBP_blob
```

* Expected behavior
It should pass.

* Actual behavior
It fails because the height of the thumbnail is 34.

```
$ bin/test test/models/variant_test.rb -n test_resized_variation_of_WEBP_blob
F

Failure:
ActiveStorage::VariantTest#test_resized_variation_of_WEBP_blob [test/models/variant_test.rb:125]:
Expected: 33
  Actual: 34

bin/test test/models/variant_test.rb:117
```

Refer to https://github.com/libvips/ruby-vips/issues/383
2024-02-13 21:04:08 +09:00
Lewis Buckley
f3e3f82e7d
Add WebP as a new framework default image type
Follows https://github.com/rails/rails/pull/38918 and
https://github.com/rails/rails/pull/38988

At the time, webp browser support was limited. Now 96% of browsers
support webp: https://caniuse.com/?search=webp
2024-02-09 23:44:51 +00:00
Rafael Mendonça França
fbb230eb95
Merge pull request #51030 from searls/queue-approach-to-preview-image-race-condition
Fixes race condition for multiple preprocessed video variants
2024-02-09 18:15:53 -05:00
Rafael Mendonça França
0f9638ebb1
Update activestorage/app/models/active_storage/blob/representable.rb 2024-02-09 17:46:39 -05:00
Takahashi-Seiji
2f5e052521
docs:expand documentation on has_one_attached method.
Accepted PR's suggestions and added the information to has_many_attached method.

Co-authored-by: Salo Charabati <salochara@gmail.com>
2024-02-09 16:07:34 -05:00
Justin Searls
131fd59ff6 Fixes race condition when multiple preprocessed variants are defined for a Previewable file is attached
This fixes race condition in Active Storage when multiple preprocessed variants are defined for a `Previewable` file is attached.

When a variant is specified for a "previewable" file type (e.g. video  or PDF) attachment, a `preview_image` attachment is first created and attached on the original blob and then any user-specified variants are derived from _that_ preview image. When those variants are named and have `preprocessed: true`, the jobs to create those variants are queued simultaneously.

Example from my case:

```ruby
  has_one_attached :file, dependent: :purge_later do |attachable|
    attachable.variant :preview, resize_to_fill: [400, 400], preprocessed: true
    attachable.variant :still, format: "jpg", saver: {quality: 85}, preprocessed: true
  end
```

When a `Previewable` attachment is created (a video, in my case), `TransformJob.perform_later` is called for each named variant with `preprocessed: true`. Unless your queue adapter is synchronous (e.g. :inline or :test), this results in a race condition in which every such variant's worker will check `processed?`, see that no `preview_image` attachment exists yet on the `ActiveStorage::Blob`, and:

1. Redundantly download the file from storage
2. Create duplicative ActiveStorage::Attachment and `ActiveStorage::Blob` records for the `preview_image` attachment (all but one of which will be orphaned from the original blob's `has_one_attached :preview_image`)
3. Create variant blobs (and associated `ActiveStorage::VariantRecord`) that are similarly orphaned (by virtue of being a variant of an orphaned `preview_image` blob)

As a result, if the video is ever purged, `PurgeJob` will only find the current `has_one_attached :preview_image` and whatever variant demanded it into existence, then leave the rest as orphaned records in the database and in storage.

Pretty simple: wrap the first step of the job in `blob.with_lock {}`. By pessimistically locking on the blob, we can prevent processing the preview image multiple times by multiple `TransformJob` jobs running concurrently.

Alternate approaches would all be more work:

* Queuing a `PreviewImage` job instead of N `TransformJob` and have it, only after `preview_image` is attached, enqueue those `TransformJob` jobs
* Batching up all the named variant transformations into a single meta-job

Writing a test for this inside Rails would be difficult because it would require running the resulting TransformJob jobs concurrently. I [started a test](https://github.com/searls/rails/blob/fix-video-duplicate-preview-variants/activestorage/test/models/variant_with_record_test.rb#L348-L367) but failed to reproduce, in part because the test queue adapter will perform enqueued jobs inline instead of concurrently. In order to write a test that replicated the issue appropriately, we might first need a new option for `perform_enqueued_jobs(async: true) { … }`

If you're interested, [this gist](https://gist.github.com/searls/5b8298abe88b3206f670ea3c6d574aab) includes a driver script and output before and after the patch showing it working.

I only found this because I'm a total cheapskate and was literally counting records in my S3 bucket to ensure `PurgeJob` worked. Then I wasted the next two days trying to figure out why before landing on this. I strongly suspect that ActiveStorage users who host video and take advantage of `preprocessed: true` named variants will have a lot of orphaned stuff floating around their buckets.

To see if you have any such "zombie" preview_images (and presumably, associated variants) floating around your application that would survive calls to `purge` on the owning attachment, you could write a query like this:

```
ActiveStorage::Attachment
  .joins("INNER JOIN active_storage_attachments as other_attachments ON
          active_storage_attachments.record_id = other_attachments.record_id AND
          active_storage_attachments.id != other_attachments.id")
  .where(
    :name => "preview_image",
    :record_type => "ActiveStorage::Blob",
    "other_attachments.name" => "preview_image",
    "other_attachments.record_type" => "ActiveStorage::Blob"
  )
  .distinct
```

Clearing out one's production database and backend storage to get this all right-sized should be a fun exercise for the reader.

Co-authored-by: Aaron Patterson <aaron.patterson@gmail.com>
2024-02-09 13:22:35 -05:00
Jonathan del Strother
54d3934d43
Fix JSON-encoding ActiveStorage::Filename
ActiveStorage::Filename was missing quotes when encoded,
generating invalid json like this -

```
JSON.generate(foo: ActiveStorage::Filename.new("bar.pdf") # => '{"foo":bar.pdf}'
```

Delete to_json and rely on the implementation from ActiveSupport::ToJsonWithActiveSupportEncoder
2024-02-06 12:37:58 +00:00
zzak
4873347538
Fix Active Storage test configurations for CI
This change is an up-port of #50787 which applied a similar fix to 7-1-stable.

Since these tests weren't running before, we didn't notice when the DirectUploads controller tests were broken. My theory is that it has something to do with changing `response.parsed_body` to return a HWIA (in #49003).

This change is different from the 7-1-stable PR in that it removes the need to stringify or symbolize any keys, since we are comparing the metadata with string keys. This is a follow up to #43705.

Co-authored-by: Sean Doyle <seanpdoyle@users.noreply.github.com>
Co-authored-by: Jean byroot Boussier <jean.boussier+github@shopify.com>
2024-02-06 11:11:23 +09:00
Anup Narkhede
3d7b52176d Fix VideoAnalyzerTest#test_analyzing_a_rotated_HDR_video failure with ffmpeg < 5.0
The VideoAnalyzer uses ffprobe (part of ffmpeg) to determine the
rotation of a video. The VideoAnalyzer#angle returns tags["rotate"] if
it is available, else it attempts to get "rotation" from the Display
Matrix side_data.

However, ffprobe exhibits different behavior with different versions:
ffprobe version 4.4.2-0ubuntu on Ubuntu 22.04 returns a "rotate" : "90"
tag.

In contrast, ffprobe version 6.0-6ubuntu1 on Ubuntu 23.10 does not
return the "rotate" tag; instead, it determines the angle from the
display matrix side_data, which returns "rotation": -90.

To account for this difference, we now check for both values in the test.
2024-01-31 22:58:52 +00:00
Anup Narkhede
776626ff98
Fix rotation detection for HDR videos (#50854)
Fixes https://github.com/rails/rails/issues/50853

The video analyzer was relying on the positional reference of the Display
Matrix side_data to fetch the rotation value. However, the side_data is
not guaranteed to be in the same position. For instance, HDR videos shot
on iOS have "DOVI configuration record" side_data in the first position,
followed by the "Display Matrix" side data containing the rotation value.

This fix removes the positional reference and explicitely searches for
the "Display Matrix" side_data to retrieve the rotation angle.
2024-01-23 11:28:11 -08:00
Petrik de Heus
fe81d667a7
Merge pull request #50789 from p8/docs/relative-includes
Use relative includes of README's in documentation [ci-skip]
2024-01-21 18:30:07 +01:00
Edouard CHIN
82d4ad5da3 Fix ActiveStorage::Blob inverse association:
- This is a fix needed to unblock
  https://github.com/rails/rails/pull/50284,
  because Active Storage relies on a Active Record bug.

  The problem is best understood with a small snippet:

  ```
    blob = ActiveStorage::Blob.new

    ActiveStorage::Attachment.new(blob: blob)
    ActiveStorage::Attachment.new(blob: blob)

    # Currently:
    p blob.attachments #=> #<ActiveRecord::Associations::CollectionProxy []>

    # Once the Active Record bug is fixed:
    p blob.attachments #=> #<ActiveRecord::Associations::CollectionProxy [#<ActiveStorage::Attachment id: nil, name: nil, record_type: nil, record_id: nil, blob_id: nil, created_at: nil>, #<ActiveStorage::Attachment id: nil, name: nil, record_type: nil, record_id: nil, blob_id: nil, created_at: nil>]>

    # Trying to save the blob would result in trying to create 2 attachments which
    # fails because of unique constrainsts.
  ```

  ### Code path

  The real code path that does what the snippet above does is located here:

  9c3ffab47c/activestorage/lib/active_storage/attached/many.rb (L52)

  It's basically doing this:

  ```
    user.images.attach "photo1.png"
    # Initialize a Blob record and an Attachment

    user.images.attach "photo2.png"
    # Get the Blob from above, create another Attachment
    # Initialize a new Blob record and an new Attachment

    # rinse and repeat every time `attach` is called
  ```

  Basically each time we call `attach`, we grab the previous blobs that were attached
  (and that already have an Attachment record), and

  ### Solution

  - Explicitly set the `inverse_of`, so that it behaves as if #50284 is shipped
  - Don't build a new attachment for blob already having one.

  ### Tests

  I didn't add tests, the test suite is already well covered, adding the `inverse_of`
  without any changes breaks the test suite already. You can try by running
  for instance the `activestorage/test/models/attached/many_test.rb`.
2024-01-19 04:18:15 +01:00
Petrik
8565f45100 Use relative includes of README's in documentation [ci-skip]
The Rails documentation uses the `:include:` directive to inline the
README of the framework into the main documentation page. As the
README's aren't in the root directory from where SDoc is run we need to
add the framework path to the include:

    # :include: activesupport/README.md

This results in a warning when installing the gems as generating the rdoc for the gem is run from the gem/framework root:

    Couldn't find file to include 'activesupport/README.rdoc' from lib/active_support.rb

The `:include:` RDoc directive supports includes relative to the current
file as well:

    # :include: ../README.md

This makes sure it works for the Rails API docs and the separate gems.

Co-authored-by: Jonathan Hefner <jonathan@hefner.pro>
2024-01-18 10:39:15 +01:00
Aaron Patterson
7e9b5889cc
update changelog 2024-01-16 09:36:44 -08:00
Aaron Patterson
f2f50c904e
Fix N+1 on scope with non-image previews 2024-01-16 09:36:43 -08:00
Aaron Patterson
5f7bbf2925
Update activestorage/test/models/variant_with_record_test.rb
Co-authored-by: Petrik de Heus <petrik@deheus.net>
2024-01-15 13:10:32 -08:00
Aaron Patterson
496d761553
Eagerly load preview images
For non-image attachments (like videos), generated representations are
created as a preview_image_attachment instead of as normal variants, and
as a result aren't included in the `with_attached_` scopes. This adds
those preview image attachments to the `includes` of these scopes to
avoid an N+1 when iterating over a collection of attachments and
fetching the key of their representation (variants).

Co-Authored-By: Justin Searls <searls@gmail.com>
2024-01-15 11:41:30 -08:00
Aaron Patterson
3307a73c06
Failing test for #50560
Co-Authored-By: Justin Searls <searls@gmail.com>
2024-01-15 11:41:30 -08:00
Hans Schnedlitz
482330d156
Do not generate pidfile in production environments (#50644)
* Remove pidfile in production

* Update changelog

* Update activestorage/test/dummy/config/puma.rb

Co-authored-by: Rafael Mendonça França <rafael@franca.dev>

* Update template and other dummy files

---------

Co-authored-by: Rafael Mendonça França <rafael@franca.dev>
2024-01-08 14:47:25 -05:00
Jonathan Hefner
3bbf21c343 Use verb form of "fallback"
"Fallback" is a noun, whereas "fall back" is a verb.
2024-01-07 17:27:23 -06:00
Jonathan Hefner
d1411b2018 Split up code blocks for multi-file examples [ci-skip]
RDoc treats consecutive indented lines as a single code block.  For code
examples that span multiple files / languages, this confuses the syntax
highlighter and makes the examples harder to read.  Unfortunately, RDoc
doesn't provide syntax to prevent this, and it ignores multiple
consecutive blank lines.  However, by inserting an empty tag such as
`<code></code>`, we can force RDoc to recognize separate code blocks.
2024-01-07 17:27:23 -06:00
Jean Boussier
27140247c2 Cleanup defined? usage
Now that we dropped support for Ruby 2.7, we no longer
need to check if variables are defined before accessing them
to avoid the undefined variable warning.
2024-01-05 15:05:35 +01:00
Zacharias Knudsen
c67e9dfe19
Ensure installed migrations comply with rubocop-rails-omakase
Adds space inside array literal brackets in ActiveStorage/ActionText migrations.

The new `rubocop-rails-omakase` enables `Layout/SpaceInsideArrayLiteralBrackets`,
which failed on the migrations created when installing ActiveStorage and ActionText.
2024-01-04 08:53:23 +01:00
Jean Boussier
6ba2fdb2fe Bump the required Ruby version to 3.1.0
Until now, Rails only droped compatibility with older
rubies on new majors, but I propose to change this policy
because it causes us to either keep compatibility with long
EOLed rubies or to bump the Rails major more often, and to
drop multiple Ruby versions at once when we bump the major.

In my opinion it's a bad alignments of incentives. And we'd
be much better to just drop support in new minors whenever they
go EOL (so 3 years).

Also Ruby being an upstream dependency, it's not even
a semver violation AFAICT.

Since Rails 7.2 isn't planned before a few months, we
can already drop Ruby 3.0 as it will be EOL in March.
2023-12-31 08:54:03 +01:00
Jonathan Hefner
5b62994778
Merge pull request #50418 from the-spectator/buffered_checksum
Use buffered read while generating Blob checksum to improve memory
2023-12-26 12:38:17 -06:00