Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ユーザーアイコンの画像のURLが表示の度に変わるので、変わらないようにしたい。 #7225

Closed
machida opened this issue Jan 24, 2024 · 4 comments

Comments

@machida
Copy link
Member

machida commented Jan 24, 2024

キャッシュができないので。

/users/1234/iconみたいなURLで永続的にアイコンが表示できると良い。
ただ、効率的なキャッシュされるかなどをActiveStorageの機能と合わせてうまく使う必要があります。
(ActiveStorageはあまり知られてない機能がたくさん合ったりするので)

@komagata komagata changed the title アイコン画像のURLが表示の度に変わるので、変わらないようにしたい。 ユーザーアイコンの画像のURLが表示の度に変わるので、変わらないようにしたい。 Jan 24, 2024
@junohm410
Copy link
Contributor

junohm410 commented Feb 3, 2024

@komagata @machida
お疲れ様です。
本Issueにつきまして、調査したことと、その対応について考えましたことをシェアさせていただきます。

お手隙の際にご確認いただき、認識のおかしな点やこの対応の方向性で問題ないかなど、レスポンスを頂戴できるとありがたいです。
お忙しいところ恐れ入りますが、よろしくお願いいたします🙏

サマリ

  • 「ユーザーアイコンの画像のURLが表示の度に変わる」という問題は、ActiveStorageに保存されたファイルへのパブリックアクセスを許可している本番環境では起きていないと思われる
  • 開発環境では上記の設定が許可されていないので、本Issueの問題が起きる
  • 開発環境でもパブリックアクセス設定を行えば、画像のURLは常に同じになり、本番環境と同じ状態になると思われる

詳細

画像URLが取得されるまでの流れと、パブリックアクセス設定について

https://bootcamp.fjord.jp/reports/88644 の日報でも同内容をまとめております。

もともと、開発環境で私が「ユーザーアイコンの画像のURLが表示の度に変わる」という現象に遭遇したのは、下のIssueに取り組む際に、APIを通してユーザーが持つ通知の一覧をフェッチしたときでした。
#7163

通知一覧をフェッチしたときに含まれるアイコン画像のURLは、User#avatar_urlで取得されています。

# app/views/api/users/_user.json.jbuilder

# ...
json.(user, *columns)
json.avatar_url user.avatar_url
# ...

User#avatar_urlは、ActiveStorage::Blob#urlを使ってブロブのurlを取得します。

# Userモデル

  def avatar_url
    default_image_path = '/images/users/avatars/default.png'

    if avatar.attached?
       # ActiveStorage::Blob#urlでブロブ(画像ファイルそのもの)のurlを取得する
      avatar.variant(resize: AVATAR_SIZE).processed.url
    else
      image_url default_image_path
    end
  rescue ActiveStorage::FileNotFoundError, ActiveStorage::InvariableError
    image_url default_image_path
  end

ActiveStorage::Blob#urlの詳細を確認すると、

Returns the URL of the blob on the service. This returns a permanent URL for public files, and returns a short-lived URL for private files. Private files are signed, and not for public use. Instead, the URL should only be exposed as a redirect from a stable, possibly authenticated URL. Hiding the URL behind a redirect also allows you to change services without updating all URLs.

https://api.rubyonrails.org/v7.1/classes/ActiveStorage/Blob.html#method-i-url

とあり、「パブリックなファイルなら(使用しているストレージサービスの)永続URLを返し、プライベートファイルなら期限付きURLを返す。」となっています。
bootcampアプリのconfig/storage.ymlの設定を見てみると、productionで使われているGCSの方ではパブリックになっていますが、開発環境では設定がされていません。

# config/storage.yml

local:
  service: Disk
  root: <%= Rails.root.join("storage") %>

google:
  service: GCS
  project: "bootcamp-224405"
  credentials: <%= Base64.decode64(ENV["GOOGLE_CREDENTIALS"].to_s) %>
  bucket: <%= ENV["GCS_BUCKET"] %>
  public: true

本番のプロフィールページの自分のアイコン画像のURLを確認→ページを更新し再度確認→最初のときとURLが変わっていないことを確認しました。
常にhttps://storage.googleapis.com/bootcamp-fjord-jp/{おそらく私のアイコン画像を表す一意の文字列}というGCSのURLが一言一句同じ状態で返されます。
(プロフィールページの自分の画像のURLもUser#avator_urlで実装されていることは確認済み)

一方、開発環境では上記の設定がなされていないため、User#avatar_urlの実行のたびに有効期限(bootcampアプリでは7日間)付きの異なるURLが毎回返されている、というのが本Issueの根本原因かと思われます。

対応の方向について

本番環境では本Issueの問題は起きていませんが、開発環境ではSWRでフェッチしたデータのキャッシュが効かずに不要に再レンダリングを引き起こされるなど、本番と開発環境で微妙に挙動が変わってしまっています。

local:
  service: Disk
  root: <%= Rails.root.join("storage") %>
  public: true #追加する

開発環境でもパブリックアクセス設定を行えば、本番と同じ挙動をするようになります。

railsコンソールによる検証

検証内容

  • 一人のユーザーを取得(今回はアイコンがあるmachidaさん)
  • user.avatar.urlを二回行う
  • その二回の結果が等しいかどうか確認する

変更前 -> 二回の結果が異なる = アバターのURLが取得するたびに変わってしまっている

irb(main):001:0> ActiveStorage::Current.host = 'http://localhost:3000'
=> "http://localhost:3000"

irb(main):002:0> user = User.find(679998234)
#...

irb(main):004:0> tempUrl1 = user.avatar.url
  Disk Storage (1.7ms) Generated URL for file at key: t6pm0dzpr7nix8s4kownrojgf7nc (http://localhost:3000/rails/active_storage/disk/eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaDdDVG9JYTJWNVNTSWhkRFp3YlRCa2VuQnlOMjVwZURoek5HdHZkMjV5YjJwblpqZHVZd1k2QmtWVU9oQmthWE53YjNOcGRHbHZia2tpUVdsdWJHbHVaVHNnWm1sc1pXNWhiV1U5SW0xaFkyaHBaR0V1YW5Cbklqc2dabWxzWlc1aGJXVXFQVlZVUmkwNEp5ZHRZV05vYVdSaExtcHdad1k3QmxRNkVXTnZiblJsYm5SZmRIbHdaVWtpRDJsdFlXZGxMMnB3WldjR093WlVPaEZ6WlhKMmFXTmxYMjVoYldVNkNteHZZMkZzIiwiZXhwIjoiMjAyNC0wMi0wMlQxNTo0MjoyNS45MjlaIiwicHVyIjoiYmxvYl9rZXkifX0=--6a03cac68fb670d09bb7b82ab6840d5b22c11bc1/machida.jpg)
=> "http://localhost:3000/rails/active_storage/disk/eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaDdDVG9JYTJWNVNTSWhkRFp3YlRCa2VuQnlOMjVwZURoek5HdHZkMjV5YjJwblpqZHVZd1k2QmtWVU9oQmthWE53YjNOcGRHbHZia2tpUVdsdWJHbHVaVHNnWm1sc1pXNWhiV1U5SW...

irb(main):005:0> tempUrl2 = user.avatar.url
  Disk Storage (2.0ms) Generated URL for file at key: t6pm0dzpr7nix8s4kownrojgf7nc (http://localhost:3000/rails/active_storage/disk/eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaDdDVG9JYTJWNVNTSWhkRFp3YlRCa2VuQnlOMjVwZURoek5HdHZkMjV5YjJwblpqZHVZd1k2QmtWVU9oQmthWE53YjNOcGRHbHZia2tpUVdsdWJHbHVaVHNnWm1sc1pXNWhiV1U5SW0xaFkyaHBaR0V1YW5Cbklqc2dabWxzWlc1aGJXVXFQVlZVUmkwNEp5ZHRZV05vYVdSaExtcHdad1k3QmxRNkVXTnZiblJsYm5SZmRIbHdaVWtpRDJsdFlXZGxMMnB3WldjR093WlVPaEZ6WlhKMmFXTmxYMjVoYldVNkNteHZZMkZzIiwiZXhwIjoiMjAyNC0wMi0wMlQxNTo0Mjo0My4zNjRaIiwicHVyIjoiYmxvYl9rZXkifX0=--c2e8fe8145a7323beae3c0d22604d6b2fcaabcba/machida.jpg)
=> "http://localhost:3000/rails/active_storage/disk/eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaDdDVG9JYTJWNVNTSWhkRFp3YlRCa2VuQnlOMjVwZURoek5HdHZkMjV5YjJwblpqZHVZd1k2QmtWVU9oQmthWE53YjNOcGRHbHZia2tpUVdsdWJHbHVaVHNnWm1sc1pXNWhiV1U5SW...

irb(main):006:0> tempUrl1 == tempUrl2
=> false

パブリックアクセスに変更後 -> 二回の結果が同じ = アバターのURLが変わっていない

irb(main):001:0> ActiveStorage::Current.host = 'http://localhost:3000'
=> "http://localhost:3000"
                                                                                                                    
irb(main):002:0> user = User.find(679998234)
#...
                                                            
irb(main):003:0> tempUrl1 = user.avatar.url
  ActiveStorage::Attachment Load (2.4ms)  SELECT "active_storage_attachments".* FROM "active_storage_attachments" WHERE "active_storage_attachments"."record_id" = $1 AND "active_storage_attachments"."record_type" = $2 AND "active_storage_attachments"."name" = $3 LIMIT $4  [["record_id", 679998234], ["record_type", "User"], ["name", "avatar"], ["LIMIT", 1]]
  ActiveStorage::Blob Load (0.9ms)  SELECT "active_storage_blobs".* FROM "active_storage_blobs" WHERE "active_storage_blobs"."id" = $1 LIMIT $2  [["id", 10], ["LIMIT", 1]]
  Disk Storage (61.2ms) Generated URL for file at key: t6pm0dzpr7nix8s4kownrojgf7nc (http://localhost:3000/rails/active_storage/disk/eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaDdDVG9JYTJWNVNTSWhkRFp3YlRCa2VuQnlOMjVwZURoek5HdHZkMjV5YjJwblpqZHVZd1k2QmtWVU9oQmthWE53YjNOcGRHbHZia2tpUVdsdWJHbHVaVHNnWm1sc1pXNWhiV1U5SW0xaFkyaHBaR0V1YW5Cbklqc2dabWxzWlc1aGJXVXFQVlZVUmkwNEp5ZHRZV05vYVdSaExtcHdad1k3QmxRNkVXTnZiblJsYm5SZmRIbHdaVWtpRDJsdFlXZGxMMnB3WldjR093WlVPaEZ6WlhKMmFXTmxYMjVoYldVNkNteHZZMkZzIiwiZXhwIjpudWxsLCJwdXIiOiJibG9iX2tleSJ9fQ==--55a584bfdfda1204733659055747dbd5400d1166/machida.jpg)
=> "http://localhost:3000/rails/active_storage/disk/eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaDdDVG9JYTJWNVNTSWhkRFp3YlRCa2VuQnlOMjVwZURoek5HdHZkMjV5YjJwblpqZHVZd1k2QmtWVU9oQmthWE53YjNOcGRHbHZia2tpUVdsdWJHbHVaVHNnWm1sc1pXNWhiV1U5SW...

irb(main):004:0> tempUrl2 = user.avatar.url
  Disk Storage (0.6ms) Generated URL for file at key: t6pm0dzpr7nix8s4kownrojgf7nc (http://localhost:3000/rails/active_storage/disk/eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaDdDVG9JYTJWNVNTSWhkRFp3YlRCa2VuQnlOMjVwZURoek5HdHZkMjV5YjJwblpqZHVZd1k2QmtWVU9oQmthWE53YjNOcGRHbHZia2tpUVdsdWJHbHVaVHNnWm1sc1pXNWhiV1U5SW0xaFkyaHBaR0V1YW5Cbklqc2dabWxzWlc1aGJXVXFQVlZVUmkwNEp5ZHRZV05vYVdSaExtcHdad1k3QmxRNkVXTnZiblJsYm5SZmRIbHdaVWtpRDJsdFlXZGxMMnB3WldjR093WlVPaEZ6WlhKMmFXTmxYMjVoYldVNkNteHZZMkZzIiwiZXhwIjpudWxsLCJwdXIiOiJibG9iX2tleSJ9fQ==--55a584bfdfda1204733659055747dbd5400d1166/machida.jpg)
=> "http://localhost:3000/rails/active_storage/disk/eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaDdDVG9JYTJWNVNTSWhkRFp3YlRCa2VuQnlOMjVwZURoek5HdHZkMjV5YjJwblpqZHVZd1k2QmtWVU9oQmthWE53YjNOcGRHbHZia2tpUVdsdWJHbHVaVHNnWm1sc1pXNWhiV1U5SW...
                                                              
irb(main):005:0> tempUrl1 == tempUrl2
=> true

@komagata
Copy link
Member

komagata commented Feb 4, 2024

@junohm410

お手隙の際にご確認いただき、認識のおかしな点やこの対応の方向性で問題ないかなど、レスポンスを頂戴できるとありがたいです。

質問タイムで話した通り、上記の方向性で問題ないです〜

質問タイムの話から進んだ点としては
@junohm410 さんが予想した通り開発環境もpublic設定すればOKだった」
ってことですよね。

@junohm410
Copy link
Contributor

@komagata
ご返信、ありがとうございます🙏

質問タイムの話から進んだ点としては
「junohm410 さんが予想した通り開発環境もpublic設定すればOKだった」
ってことですよね。

はい、その通りです。
ここを切り分けてお伝えすべきでした。すみませんでした🙇‍♂️

それでは、上記の方向で対応します。
引き続きよろしくお願いいたします。

@junohm410
Copy link
Contributor

junohm410 commented Feb 16, 2024

本件、開発・テスト環境においてActiveStrogeのパブリックアクセスを許可する修正PRがマージされました。
ステージング環境上で、下記のことを確認し、動作確認が取れました。

  • テストユーザーでログインし、ユーザーアイコン画像を登録
  • ユーザープロフィールに移動し、アイコン画像を右クリック -> 「新しいタブで画像を開く」で表示されるタブのURLを確認
  • ユーザープロフィール画面を再読み込みし、上記の画像のURLの確認を繰り返す
  • 再読み込み後も、画像のURLに変更がないことを確認

本番環境には影響のない変更のため、本Issueはこちらでクローズとさせていただきます。

@komagata komagata moved this to 完成 in bootcamp Aug 21, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Archived in project
Development

No branches or pull requests

3 participants