Allow Cloudinary Active Storage service to reuse preloaded blobs via options (avoid extra DB queries)

オープン
#582 コメント 1 件 リアクション 0 件 担当者 0 名 GitHub で見る

まだ誰も着手していません。

評価

難易度
3/5
見積もり時間
1〜2日
初心者へのやさしさ
45/100
issue の種類
機能追加
明瞭さ
明確に書かれている
活発さ
停滞
技術スタック
rails, ruby
領域
backend

調査の方向性

まず CloudinaryService#url と private なヘルパー #find_blob_or_use_key の場所を特定し、次に #delete と #exist? がそのヘルパーをどのように呼び出しているかを確認します。URL オプションを通じて提供された任意の blob を再利用し、既存のキー処理とフォールバック動作を維持してください。削除処理は変更せず、blob が提供された場合に URL パスが追加の blob 検索を回避することを検証してください。

索引モデルが issue の本文から書いたものです。

説明

Feature request for Cloudinary Ruby SDK

Please enhance the Cloudinary Active Storage service so that it can reuse a preloaded ActiveStorage::Blob instead of always querying the database.

I’m specifically proposing:

  • Threading an optional :blob through the options hash into the internal helper #find_blob_or_use_key.
  • Updating #find_blob_or_use_key to accept an optional blob: parameter and use it when present.
  • Focusing primarily on #url while leaving #delete and #exist? unchanged for now.

This keeps public APIs backwards compatible and only adds an opt-in optimization path.


Explain your use case

In my Rails app, ActiveStorage::Blob records are often already loaded in memory via includes / preload/with_attached_*.

When I call blob.url, Rails ends up delegating to the configured service’s #url method and passes along an options hash. I’d like to be able to include the already-loaded blob in that options hash so the Cloudinary service doesn’t need to look it up again by key.

For my specific workload, this primarily matters for generating URLs (#url), where blobs are very frequently preloaded. For deletions, blobs are less likely to be preloaded, so I’m less concerned about optimizing #delete right now.


Describe the problem you’re trying to solve

Currently:

  • CloudinaryService#find_blob_or_use_key is a private helper used internally by:

    • #url
    • #delete
    • #exist?
  • These methods pass a key to find_blob_or_use_key, which then always does a DB lookup (unless the argument is already an ActiveStorage::BlobKey).

  • When calling blob.url, Rails goes through service.url(key, options), and the options hash is forwarded — but there is no support in the Cloudinary service for using something like options[:blob] to skip the DB query.

As a result:

  • Even if I already have the ActiveStorage::Blob instance, the Cloudinary service will still call ActiveStorage::Blob.find_by(key: key).
  • This can create unnecessary queries and N+1 patterns in attachment-heavy views or background jobs.
  • There’s no way to opt in to a “I already have the blob, please reuse it” behavior.

#delete is more problematic to change because Blob#delete only passes the key to the service and doesn’t pass an options hash at all. In my case, blobs are less likely to be preloaded at deletion time, so I’m okay with leaving #delete as-is initially.


Do you have a proposed solution?

Yes.

1. Pass blob through the options hash for #url

Because blob.url already forwards an options hash to the service, the most compatible way is to use that:

  • Allow callers of service.url (including blob.url) to pass blob via options[:blob].
  • Inside CloudinaryService#url, extract blob from options and pass it to find_blob_or_use_key.

Conceptual example:

def url(key, filename: nil, content_type: '', **options)
  blob = options[:blob]
  key = find_blob_or_use_key(key, blob:)

  # existing logic using key...
end
2. Update find_blob_or_use_key to accept an optional blob: argument

Then, update the private helper so that it reuses a provided blob if present, and falls back to the current behavior otherwise. For example:

def find_blob_or_use_key(key, blob: nil)
  if key.is_a?(ActiveStorage::BlobKey)
    key
  else
    begin
      blob ||= ActiveStorage::Blob.find_by(key: key)
      blob ? ActiveStorage::BlobKey.new(blob.attributes.as_json) : key
    rescue ActiveRecord::StatementInvalid => e
      # Return the original key if an error occurs
      key
    end
  end
end
Why this is backwards compatible
  • Existing callers that do not pass a :blob option behave exactly as before:

    • find_blob_or_use_key still does ActiveStorage::Blob.find_by(key: key) and returns the same result type.
    • It still returns the key unchanged if it’s already an ActiveStorage::BlobKey.
    • It still rescues ActiveRecord::StatementInvalid and returns the original key.
  • The optimization is opt-in:

    • Only when an upstream caller sets options[:blob] (for example, blob.url(blob: blob) or via a wrapper) will the Cloudinary service reuse the preloaded blob and skip the DB query.

This enables applications that already manage preloaded blobs to avoid extra database queries when generating URLs (and, optionally, when checking existence), without breaking or changing the behavior for any existing users of the SDK.

主要言語
Ruby
スター
420
フォーク
282
PR マージ指標
30日以内にマージされた PR はありません

環境構築

はじめの一歩

  1. issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
  2. 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
  3. リポジトリをフォークし、ブランチを切って変更します。
  4. issue 番号を参照したプルリクエストを送ります。

cloudinary/cloudinary_gem のほかの issue

cloudinary/cloudinary_gem の issue をすべて見る

似ている issue

Ruby の issue をもっと見る

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。