Skip to content

Update - #5

Open
asurin wants to merge 1136 commits into
tkwwarchive:0.11-stablefrom
carrierwaveuploader:master
Open

Update#5
asurin wants to merge 1136 commits into
tkwwarchive:0.11-stablefrom
carrierwaveuploader:master

Conversation

@asurin

@asurin asurin commented Nov 14, 2016

Copy link
Copy Markdown

No description provided.

BrianHawley and others added 30 commits September 29, 2022 09:30
chore: minor refactor from select first to detect
Raise DownloadError when no content is returned
…ptions

fix: ruby 2.7 kwarg warning in uploader process
Given that it is not advised to put other stuff in the same directory
as CarrierWave's cache, this fix makes clean_cache! not break then.

Based on the similar fix for the Fog storage clean_cache!.
Local storage clean_cache! fix for off-topic files
Enable to override configurations by 'false' on a per-uploader basis
Also the call to write_#{column}_identifier doesn't need to be in CarrierWave::ActiveRecord, since what it does is not specific to ActiveRecord.
Fixes #2540
Since the appropriate wait time depends on the each of the remote server,
it is better to be able to configure the wait time on the application side.
Support to configure download retry wait time
mshibuya and others added 30 commits January 12, 2025 17:36
…}=`, `##{column}_cache=`, and `#remote_#{column}_url=`

Fixes #2778, Fixes #2779
By providing a 'changelog_uri' in the metadata of the gemspec a
'Changelog' link will be shown on https://rubygems.org/gems/carrierwave
which makes it quick and easy for someone to check on the changes
introduced with a new version.

Details of this functionality can be found on https://guides.rubygems.org/specification-reference/#metadata
Adds a commented example of `content_type_allowlist` (/image\//) to the
generated uploader.  It mirrors the existing `extension_allowlist`
comment and helps users mitigate content-type spoofing attacks.
Bumps [actions/checkout](https://github.com/actions/checkout) from 4 to 5.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](actions/checkout@v4...v5)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: '5'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
* Fix "Lint/Void: Variable storage used in void context."

The current logic does nothing. So just add a comment to fix the linter.

* Avoid to test against JRuby 10.1.x

It seems that activerecord-jdbc-adapter doesn't work with the latest
version.
Bumps [actions/checkout](https://github.com/actions/checkout) from 5 to 6.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](actions/checkout@v5...v6)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps [actions/checkout](https://github.com/actions/checkout) from 6 to 7.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](actions/checkout@v6...v7)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: '7'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
…ctions/actions/checkout-7

Bump actions/checkout from 6 to 7
* upgrade marcel gem currently locked to '~> 1.0.0', lock to '~> 1.0'

* Bump actions/checkout from 6 to 7

Bumps [actions/checkout](https://github.com/actions/checkout) from 6 to 7.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](actions/checkout@v6...v7)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: '7'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>

* loosen marcel restriction

* fix issue from upgraded MiniMagick

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: RobL <contact@robl.me>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
…te!` (#2817)

Previously, when `manipulate!` was called with a block that returned nil
for every frame, the resulting empty frames array caused an
`ArgumentError` in frames.append(true)`. This is because
RMagick's `ImageList#append` does not accept a bare true value on an
empty list.

https://github.com/rmagick/rmagick/blob/9788a6d43b3aebb5a1ad72013f1fe0b3affa300f/ext/RMagick/rmilist.cpp#L143
https://github.com/rmagick/rmagick/blob/9788a6d43b3aebb5a1ad72013f1fe0b3affa300f/ext/RMagick/rmilist.cpp#L877

This made the error hard to diagnose since the root cause
(unsupported format or a block that always returns nil) was not surfaced.

It looks like this happens when an image file isn't supported by
ImageMagick.
(In our case, this happens with HEIC files with unsupported compatible brands)

So this changed to check frames and if it's empty, raises an appropriate error.
#process_uri decoded the path and re-encoded it, which loses the distinction
between %2F and '/', and between %2B and '+'. Every fix in this area has so far
had to pick which of the two to break: a literal + in a path became %2B and
404'd (#2505, #2590, #2800), %2F used as part of an object name was decoded
into a path separator (#2808), and percent-encoded sub-delims in a signed URL
were decoded, invalidating the signature (#858).

Escape only what cannot appear in each component instead, leaving existing %XX
untouched. The operation is then idempotent and leaves an already valid URL
unchanged, so those shapes no longer have to be traded off against each other.

Split the three operations that #encode_path was serving at once: encoding raw
data into a component, decoding a component back for display, and repairing a
string that is already a URI. Only the second may decode, so the filename taken
from a URL now uses URI semantics rather than CGI.unescape, which is for form
encoding and turns '+' into a space.

Also strip whitespace and newlines left over from pasting and supply a missing
scheme, as remote_#{column}_url= is meant to be fed from a text field.

Fixes #2800

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Bumps the JRuby build from 10.0.5.0 to the latest 10.1.1.0 release.
It stays on Rails 7.2, since activerecord-jdbc-adapter has no stable
release supporting Rails 8.x yet (only an 80.0.pre1 prerelease);
pointing it at 8.1 made bundler silently resolve down to the ancient
1.3.22, which calls alias_method_chain and blows up loading
ActiveRecord. The previous Rails 8.0 combination is kept in the
matrix, tested against Ruby 4.0.

Also drops the stale "~> 1.0" sqlite3 pin in the root Gemfile, added
back to fix Rails 7 builds when that Gemfile always resolved to
whatever Rails was latest at the time. Now that latest Rails is 8.x,
which requires sqlite3 >= 2.1, the stale pin broke activerecord_spec
instead. gemfiles/rails-7-2.gemfile and newer already leave sqlite3
unpinned; do the same here.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
)

* Simplify tests around use of `Open3` within `mini_magick`

Throughout their history they were ultimately calling either `popen3` or
`capture3`, and it has been noted that `capture3` internally calls
`popen3` within the standard library, so we only need to stub at the
lowest level to cover all versions.

* Relax dependency on image_processing to allow updates to `~> 2.0`

Add `ruby-vips` as a dependency for testing because `image_processing`
no longer hard-requires it.

---------

Co-authored-by: Amir Yalon <git@please.nospammail.net>
ActiveStorage on Rails main now requires marcel `~> 2.0`, which conflicts
with our `< 2` pin and breaks bundle install on the rails-main build.

Relax the constraint to `< 3`. On Ruby < 3.3 (and JRuby) Bundler keeps
resolving marcel 1.x, since marcel 2.0 requires Ruby >= 3.3.

marcel 2 also validates the declared MIME type against the RFC grammar
instead of splitting on the first `;`, `,` or space, so a header carrying
more than one type (e.g. "image/png; text/html") now falls back to
application/octet-stream. Extract the first media type ourselves before
handing it to Marcel to preserve the previous behavior.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Caching to a remote storage costs a PUT, a COPY and a DELETE per file,
repeated for every version. Only the PUT carries the bytes; the COPY and the
DELETE exist solely to move the object from the cache key to the store key,
and are pure overhead whenever the record is saved right away, which is the
common case. The server-side copy is not free either, having been reported as
the dominant cost on OpenStack (#2605).

The cache defaulted to local storage until 629afec made it follow #storage, to
avoid the confusion of having to configure the two separately (#2353),
knowingly accepting that overhead in return. Deferring the upload removes the
need to choose between the two: Storage::Fog now stages the file in the local
cache and uploads it only when it turns out to be needed beyond the current
request, which is when its cache name is read to be carried over by a form, or
its URL is generated to be fetched by a browser. The happy path becomes a
single PUT straight to the store, while redisplaying a form after a validation
error keeps working across servers exactly as before.

No configuration changes: storages which have nothing to defer are unaffected,
as Storage::Abstract#materialize_cache! returns the file it is given.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Uploader#blank? delegated to the file, whose #empty? costs a HEAD request on
a remote storage. ActiveSupport implements #present? as !#blank?, so anything
Rails-idiomatic reached the network: `user.avatar?`, `user.avatar.present?`,
`validates :avatar, presence: true`, serializers, view guards, once per record
on a page listing many of them (#2802, #2776, #2784).

CarrierWave::Storage::Fog::File#empty? was added in 3.1.0 to make presence
mean the same thing on both storages (#1926), since SanitizedFile#empty?
checks the filesystem. That aligned them on the expensive reading. Two
questions were being conflated: whether a file is assigned, which the
identifier already answers for free, and whether it is actually in the
storage, which nothing but the storage can answer. Split them: #blank? and
#present? answer the first, and the new #exists? answers the second.

A cached file is still verified, as a cache name can point at a cache which is
gone and the check is local either way. A version now reports itself present
whenever its parent is, which #1926 relied on to tell whether a conditional
version had been created; #exists? answers that explicitly.

Also fix two ways the remote storage was asked more than it had to be:
directory.files.head was memoized with ||=, so a file which is not there was
looked up again on every access (#2698, #2793), and #size called #zero? on a
content length the storage may not report (#2787).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Retrieving an uploader ran the :if/:unless condition of every version right
away, to decide which ones to retrieve. The conditions receive the file, and
they exist precisely to look at it, so a condition on the content type or the
dimensions costs a HEAD request on a remote storage, or an ImageMagick call,
once per record. It is paid by anything that merely touches the mounted
column, whether or not a version is ever used (#2461, #2132).

Nothing forces that work to happen at retrieval time. Retrieval itself is
free, and the conditions are answered against the same file whenever they are
asked. Record the retrieval instead and run it on the first access to
#versions, which every path to a version goes through (#2669). Reading only
the original file now touches the storage no more than it has to.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Only the identifier is persisted, and everything else about a stored file is
worked out again on retrieval, by re-running the uploader's definition and by
asking the storage. Some of it cannot be worked out correctly. Which versions
a conditional creates is settled when the file is stored, and the conditions
receive the file precisely so they can look at it, so re-deciding later gives
whatever the current answer is: a version that exists loses its URL, or one
that was never created gets a URL leading to a 404 (#2148, #1926). The rest of
it is merely expensive, costing a request per record on a remote storage.

Give the mount a column to record it in, and the facts are read back rather
than guessed:

    mount_uploader :image, ImageUploader, metadata_column: :image_metadata

The uploader collects them in #build_metadata when the file is about to be
stored, which is the moment they are true, and it is overridable so that
uploaders can record their own. Which versions were created, their filenames,
the size and the content type are recorded by default; #version_active?,
#size, #content_type and #store_path consult them instead of working them out.

Nothing changes for those who do not name a column, and records stored before
one was added have nothing recorded and keep behaving as they did, so no
backfill is needed.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
`process convert: format` sets force_extension on the class, from the
declaration alone, while whether the conversion runs is decided per file by the
condition. A JPEG which the condition spared was still stored under a .webp
name (#2723). Set the extension where the decision is made, in #process!, so it
follows what actually happened. The class-level one stays for an unconditional
conversion, where the declaration is the fact and can be relied on to work the
extension out again on retrieval.

A conditional one cannot, so it has to survive to the request the file is
retrieved in, where nothing re-runs the processing. Both ends of the trip carry
it now instead of deriving it: the cache name, so a redisplayed form finds the
cached file, and the recorded filename, so retrieval from the store finds the
stored one. This is why the case could not be fixed on its own, and why the
mount now refuses an uploader which converts conditionally unless it is given a
metadata_column to record the result in.

The mount is where that can be told, having both the uploader and the options,
and it fails at boot rather than on a save. What it cannot see is a version's
processors, which are only built once a version is used, so those warn once per
uploader when the conversion runs.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.