Resizing

Gem Version test codecov

Client and utilities for Resizing - an image hosting and transformation service.

Requirements

  • Ruby 3.1.0 or later (tested against 3.1, 3.2, 3.3, 3.4 and 4.0)
  • Rails 7.0 or later for the CarrierWave integration (tested against 7.0, 7.1, 7.2, 8.0 and 8.1)
  • Faraday 1.x or 2.x (tested against 1.10 and the latest 2.x)

The exact combinations exercised in CI are listed in .github/workflows/test.yml. Support for a Ruby or Rails series that has reached upstream end-of-life may be dropped in a minor release; such changes are announced in the release notes.

Installation

Add this line to your application's Gemfile:

gem 'resizing'

And then execute:

$ bundle install

Or install it yourself as:

$ gem install resizing

Configuration

Resizing.configure = {
  image_host: 'https://img.resizing.net',
  project_id: 'your-project-id',
  secret_token: 'your-secret-token'
}

video_host は動画 API の廃止にともない非推奨です。指定しても利用されず、Configuration#video_host や Configuration::DEFAULT_VIDEO_HOST を参照すると警告が出ます。将来のバージョンで削除します。

Usage

Basic Client Usage

# Initialize client
client = Resizing::Client.new

# Upload image to resizing
file = File.open('sample.jpg', 'r')
response = client.post(file)
# => {
#      "id"=>"a4ed2bf0-a4cf-44fa-9c82-b53e581cb469",
#      "project_id"=>"098a2a0d-0000-0000-0000-000000000000",
#      "content_type"=>"image/jpeg",
#      "latest_version_id"=>"LJY5bxBF7Ryxfr5kC1F.63W8bzp3pcUm",
#      "latest_etag"=>"\"190143614e6c342637584f46f18f8c58\"",
#      "created_at"=>"2020-05-15T15:33:10.711Z",
#      "updated_at"=>"2020-05-15T15:33:10.711Z",
#      "url"=>"/projects/098a2a0d-0000-0000-0000-000000000000/upload/images/a4ed2bf0-a4cf-44fa-9c82-b53e581cb469"
#    }

# Generate transformation URL
image_id = response['id']
transformation_url = Resizing.url_from_image_id(image_id, nil, ['w_200', 'h_300'])
# => "https://img.resizing.net/projects/.../upload/images/.../w_200,h_300"

CarrierWave Integration

class ImageUploader < CarrierWave::Uploader::Base
  include Resizing::CarrierWave

  version :list_smallest do
    process resize_to_fill: [200, 200]
  end
end

class User
  mount_uploader :image, ImageUploader
end

process declares the transformation applied when the browser fetches the image URL, so the processors are never run as local image processing on upload.

The uploader validations hooked on CarrierWave's :cache callbacks are checked before the image is uploaded to Resizing:

class ImageUploader < CarrierWave::Uploader::Base
  include Resizing::CarrierWave

  def extension_allowlist
    %w[jpg jpeg gif png]
  end

  def content_type_allowlist
    [%r{\Aimage/}]
  end

  def size_range
    0..(5 * 1024 * 1024)
  end
end

extension_denylist and content_type_denylist work the same way. A rejected file is not uploaded, and the model becomes invalid with an error on the mounted column, as in plain CarrierWave.

The extension checked by extension_allowlist / extension_denylist is derived from the content type of the file whenever it is known, not from the file name. A file downloaded from a Resizing URL (e.g. assigned through remote_<column>_url=) ends with the version string, so its file name has no meaningful extension; the Content-Type of the response is used instead. When the content type is unknown (application/octet-stream), the extension of the file name is used as in plain CarrierWave.

Versions are not uploaded separately: a version only changes the transformation in the generated URL, so a single upload backs every version.

Development

This repository ships a Dev Container so that everyone develops against the same Ruby / MySQL setup.

Requirements: Docker and either VS Code + the Dev Containers extension, or the devcontainer CLI.

  1. Open the repository in VS Code and run Dev Containers: Reopen in Container (or run devcontainer up --workspace-folder .).

  2. bundle install and the MySQL wait are executed automatically by .devcontainer/post-create.sh.

  3. Inside the container:

    $ bundle exec rake test    # run the tests
    $ bundle exec rubocop      # run the linter
    $ bin/console              # interactive prompt
    

The container provides:

  • Ruby managed by rbenv, so the version can be changed from inside the container (see below)
  • MySQL 5.7 with the resizing_gem_test database, matching CI
  • RAILS_VERSION to test against another Rails version, matching the RAILS_VERSION switch in the Gemfile and in CI. Unset, the Gemfile picks the newest supported Rails that runs on the current Ruby (8.1, or 7.2 on Ruby 3.1)

Gems are installed into a named volume (/usr/local/bundle). vendor/, .bundle/ and .ruby-lsp/ are kept on their own volumes so that Ruby artifacts generated on the host do not leak into the container through the bind mount: vendor/ holds gems whose native extensions are built against the host's libraries, .bundle/config points BUNDLE_PATH at it, and .ruby-lsp/ records which gems the Ruby LSP extension has installed. The host copies are left untouched.

Changing the Ruby version

Ruby 3.1.7 is installed when the image is built, and .ruby-version is honoured on container creation. To switch to another version from inside the container:

$ rbenv install 3.3.12
$ rbenv local 3.3.12    # writes .ruby-version (gitignored)
$ bundle install

rbenv install needs no sudo; the build dependencies are already in the image. To change the version the image ships with, set the RUBY_VERSION build arg in .devcontainer/compose.yaml and rebuild.

Without a Dev Container

After checking out the repo, run bin/setup to install dependencies. Then, run rake test to run the tests. You can also run bin/console for an interactive prompt that will allow you to experiment.

The tests need a MySQL server. docker-compose.yml in the repository root starts a suitable one (docker compose up -d mysql).

Each test process creates its own database (resizing_gem_test_<host>_<pid>) and drops it when the run finishes, so several test processes can share one MySQL server without breaking each other's tables. Databases left behind by killed processes are cleaned up on the next run.

The connection defaults to root:[email protected]:3306 and can be overridden with the MYSQL_HOST, MYSQL_PORT, MYSQL_USER and MYSQL_PASSWORD environment variables. Setting MYSQL_DATABASE uses that database as is and never drops it; in that case give each concurrent test process a different name, otherwise they will overwrite each other's tables.

To install this gem onto your local machine, run bundle exec rake install. To release a new version, update the version number in version.rb, and then run bundle exec rake release, which will create a git tag for the version, push git commits and tags, and push the .gem file to rubygems.org.

Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/jksy/resizing-gem.

License

The gem is available as open source under the terms of the MIT License.