おはようございます!
2021年はもっとJSと仲良くなりたい @shutooike です!
今回試すのは ActiveStorage の Permanent URLs です。
セットアップ
前回の記事↑で作った Rails アプリを今回も使います!
まず ActiveStorage をインストールします
$ dip rails active_storage:install Creating test_rails_latest_backend_run ... done Copied migration 20210119162125_create_active_storage_tables.active_storage.rb from active_storage $ dip rails db:migrate Creating test_rails_latest_backend_run ... done == 20210119162125 CreateActiveStorageTables: migrating ======================== -- create_table(:active_storage_blobs, {}) -> 0.0406s -- create_table(:active_storage_attachments, {}) -> 0.0151s -- create_table(:active_storage_variant_records, {}) -> 0.0351s == 20210119162125 CreateActiveStorageTables: migrated (0.0931s) ===============
前回作った Post に画像を添付できるようにします。
app/models/post.rb
class Post < ApplicationRecord has_many :comments, dependent: :destroy_async has_one_attached :image # <- 追加 end
app/controllers/posts_controller.rb
class PostsController < ApplicationController . . private . . # Only allow a list of trusted parameters through. def post_params params.require(:post).permit(:title, :body, :image) # <- :image を追加 end end
app/views/posts/_form.html.erb
. . <div class="field"> <%= form.label :image %> <%= form.file_field :image %> </div> . .
app/views/posts/show.html.erb
. . <div> <p><b>Image:</b></p> <%= image_tag @post.image %> </div> . .
Create Post
を押下すると
これで Post に画像を添付できるようになりました!
永続的なURL
これまで
ActiveStorage 6.0 までは Blob#service_url
は有効期限付きの一時的なURLを返していました。
$ dip rails c Creating test_rails_latest_backend_run ... done Running via Spring preloader in process 14 Loading development environment (Rails 6.1.0) irb(main):001:0> ActiveStorage::Current.host = 'http://localhost:3000' => "http://localhost:3000" irb(main):002:0> Post.last.image.service_url (1.4ms) SELECT sqlite_version(*) Post Load (3.6ms) SELECT "posts".* FROM "posts" ORDER BY "posts"."id" DESC LIMIT ? [["LIMIT", 1]] ActiveStorage::Attachment Load (2.7ms) SELECT "active_storage_attachments".* FROM "active_storage_attachments" WHERE "active_storage_attachments"."record_id" = ? AND "active_storage_attachments"."record_type" = ? AND "active_storage_attachments"."name" = ? LIMIT ? [["record_id", 4], ["record_type", "Post"], ["name", "image"], ["LIMIT", 1]] ActiveStorage::Blob Load (3.1ms) SELECT "active_storage_blobs".* FROM "active_storage_blobs" WHERE "active_storage_blobs"."id" = ? LIMIT ? [["id", 2], ["LIMIT", 1]] DEPRECATION WARNING: service_url is deprecated and will be removed from Rails 6.2 (use url instead) (called from irb_binding at (irb):2) Disk Storage (10.6ms) Generated URL for file at key: hhq2ryr88ot5hkkepsy2xxg7jgxo (http://localhost:3000/rails/active_storage/disk/eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaDdDVG9JYTJWNVNTSWhhR2h4TW5KNWNqZzRiM1ExYUd0clpYQnplVEo0ZUdjM2FtZDRid1k2QmtWVU9oQmthWE53YjNOcGRHbHZia2tpUDJsdWJHbHVaVHNnWm1sc1pXNWhiV1U5SW1sdVoyRm5aUzV3Ym1jaU95Qm1hV3hsYm1GdFpTbzlWVlJHTFRnbkoybHVaMkZuWlM1d2JtY0dPd1pVT2hGamIyNTBaVzUwWDNSNWNHVkpJZzVwYldGblpTOXdibWNHT3daVU9oRnpaWEoyYVdObFgyNWhiV1U2RW14dlkyRnNYM0J5YVhaaGRHVT0iLCJleHAiOiIyMDIxLTAxLTI0VDE0OjMyOjE5LjczNFoiLCJwdXIiOiJibG9iX2tleSJ9fQ==--dfa4689e26923e9d0783baaad60aab40953870f4/ingage.png) => "http://localhost:3000/rails/active_storage/disk/eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaDdDVG9JYTJWNVNTSWhhR2h4TW5KNWNqZzRiM1ExYUd0clpYQnplVEo0ZUdjM2FtZDRid1k2QmtWVU9oQmthWE53YjNOcGRHbHZia2tpUDJsdWJHbHVaVHNnWm1sc1pXNWhiV1U5SW1sdVoyRm5aUzV3Ym1jaU95Qm1hV3hsYm1GdFpTbzlWVlJHTFRnbkoybHVaMkZuWlM1d2JtY0dPd1pVT2hGamIyNTBaVzUwWDNSNWNHVkpJZzVwYldGblpTOXdibWNHT3daVU9oRnpaWEoyYVdObFgyNWhiV1U2RW14dlkyRnNYM0J5YVhaaGRHVT0iLCJleHAiOiIyMDIxLTAxLTI0VDE0OjMyOjE5LjczNFoiLCJwdXIiOiJibG9iX2tleSJ9fQ==--dfa4689e26923e9d0783baaad60aab40953870f4/ingage.png"
なので Blob#service_url
が返した URL を開くと最初はこのように表示できますが、
5分すると・・・
有効期限が切れて表示できなくなります。
irb(main):005:0> url1 = Post.last.image.url Post Load (3.4ms) SELECT "posts".* FROM "posts" ORDER BY "posts"."id" DESC LIMIT ? [["LIMIT", 1]] ActiveStorage::Attachment Load (3.5ms) SELECT "active_storage_attachments".* FROM "active_storage_attachments" WHERE "active_storage_attachments"."record_id" = ? AND "active_storage_attachments"."record_type" = ? AND "active_storage_attachments"."name" = ? LIMIT ? [["record_id", 6], ["record_type", "Post"], ["name", "image"], ["LIMIT", 1]] ActiveStorage::Blob Load (7.8ms) SELECT "active_storage_blobs".* FROM "active_storage_blobs" WHERE "active_storage_blobs"."id" = ? LIMIT ? [["id", 4], ["LIMIT", 1]] Disk Storage (1.3ms) Generated URL for file at key: 8lrdasfec0ti6trsc2z2y1bsjibj (http://localhost:3000/rails/active_storage/disk/eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaDdDVG9JYTJWNVNTSWhPR3h5WkdGelptVmpNSFJwTm5SeWMyTXllako1TVdKemFtbGlhZ1k2QmtWVU9oQmthWE53YjNOcGRHbHZia2tpUDJsdWJHbHVaVHNnWm1sc1pXNWhiV1U5SW1sdVoyRm5aUzV3Ym1jaU95Qm1hV3hsYm1GdFpTbzlWVlJHTFRnbkoybHVaMkZuWlM1d2JtY0dPd1pVT2hGamIyNTBaVzUwWDNSNWNHVkpJZzVwYldGblpTOXdibWNHT3daVU9oRnpaWEoyYVdObFgyNWhiV1U2Q214dlkyRnMiLCJleHAiOiIyMDIxLTAxLTI0VDE1OjI1OjIxLjc4MloiLCJwdXIiOiJibG9iX2tleSJ9fQ==--2258a7523a81600867d2146764da7a9dce6ebfbd/ingage.png) => "http://localhost:3000/rails/active_storage/disk/eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaDdDVG9JYTJWNVNTSWhPR3h5WkdGelptVmpNSFJwTm5SeWMyTXllako1TVdKemFtbGlhZ1k2QmtWVU9oQmthWE53YjNOcGRHbHZia2tpUDJsdWJHbHVaVHNnWm1sc1pXNWhiV1U5SW1sdVoyRm5aUzV3Ym1jaU95Qm1hV3hsYm1GdFpTbzlWVlJ..." irb(main):006:0> sleep 5.minutes => 300 irb(main):007:0> url2 = Post.last.image.url Post Load (11.4ms) SELECT "posts".* FROM "posts" ORDER BY "posts"."id" DESC LIMIT ? [["LIMIT", 1]] ActiveStorage::Attachment Load (23.4ms) SELECT "active_storage_attachments".* FROM "active_storage_attachments" WHERE "active_storage_attachments"."record_id" = ? AND "active_storage_attachments"."record_type" = ? AND "active_storage_attachments"."name" = ? LIMIT ? [["record_id", 6], ["record_type", "Post"], ["name", "image"], ["LIMIT", 1]] ActiveStorage::Blob Load (7.6ms) SELECT "active_storage_blobs".* FROM "active_storage_blobs" WHERE "active_storage_blobs"."id" = ? LIMIT ? [["id", 4], ["LIMIT", 1]] Disk Storage (1.3ms) Generated URL for file at key: 8lrdasfec0ti6trsc2z2y1bsjibj (http://localhost:3000/rails/active_storage/disk/eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaDdDVG9JYTJWNVNTSWhPR3h5WkdGelptVmpNSFJwTm5SeWMyTXllako1TVdKemFtbGlhZ1k2QmtWVU9oQmthWE53YjNOcGRHbHZia2tpUDJsdWJHbHVaVHNnWm1sc1pXNWhiV1U5SW1sdVoyRm5aUzV3Ym1jaU95Qm1hV3hsYm1GdFpTbzlWVlJHTFRnbkoybHVaMkZuWlM1d2JtY0dPd1pVT2hGamIyNTBaVzUwWDNSNWNHVkpJZzVwYldGblpTOXdibWNHT3daVU9oRnpaWEoyYVdObFgyNWhiV1U2Q214dlkyRnMiLCJleHAiOiIyMDIxLTAxLTI0VDE1OjMxOjA2LjAzN1oiLCJwdXIiOiJibG9iX2tleSJ9fQ==--ae964cba7705144602bb150cd790f35c6be9d0f4/ingage.png) => "http://localhost:3000/rails/active_storage/disk/eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaDdDVG9JYTJWNVNTSWhPR3h5WkdGelptVmpNSFJwTm5SeWMyTXllako1TVdKemFtbGlhZ1k2QmtWVU9oQmthWE53YjNOcGRHbHZia2tpUDJsdWJHbHVaVHNnWm1sc1pXNWhiV1U5SW1sdVoyRm5aUzV3Ym1jaU95Qm1hV3hsYm1GdFpTbzlWVlJ..." irb(main):008:0> url1 == url2 => false
Rails Console での検証↑
6.1 から
6.1 からは config/storage.yml で public: true | false
が設定でき、true
の場合は永続的なURLが返されるようになりました!
まず public: true
を設定に追加します
config/storage.yml
. . local: service: Disk root: <%= Rails.root.join("storage") %> public: true . .
Rails Console で検証してみます。
$ dip rails c Creating test_rails_latest_backend_run ... done Running via Spring preloader in process 14 Loading development environment (Rails 6.1.0) irb(main):001:0> ActiveStorage::Current.host = 'http://localhost:3000' => "http://localhost:3000" irb(main):002:0> url1 = Post.last.image.url (2.4ms) SELECT sqlite_version(*) Post Load (5.7ms) SELECT "posts".* FROM "posts" ORDER BY "posts"."id" DESC LIMIT ? [["LIMIT", 1]] ActiveStorage::Attachment Load (3.7ms) SELECT "active_storage_attachments".* FROM "active_storage_attachments" WHERE "active_storage_attachments"."record_id" = ? AND "active_storage_attachments"."record_type" = ? AND "active_storage_attachments"."name" = ? LIMIT ? [["record_id", 6], ["record_type", "Post"], ["name", "image"], ["LIMIT", 1]] ActiveStorage::Blob Load (5.7ms) SELECT "active_storage_blobs".* FROM "active_storage_blobs" WHERE "active_storage_blobs"."id" = ? LIMIT ? [["id", 4], ["LIMIT", 1]] Disk Storage (7.7ms) Generated URL for file at key: 8lrdasfec0ti6trsc2z2y1bsjibj (http://localhost:3000/rails/active_storage/disk/eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaDdDVG9JYTJWNVNTSWhPR3h5WkdGelptVmpNSFJwTm5SeWMyTXllako1TVdKemFtbGlhZ1k2QmtWVU9oQmthWE53YjNOcGRHbHZia2tpUDJsdWJHbHVaVHNnWm1sc1pXNWhiV1U5SW1sdVoyRm5aUzV3Ym1jaU95Qm1hV3hsYm1GdFpTbzlWVlJHTFRnbkoybHVaMkZuWlM1d2JtY0dPd1pVT2hGamIyNTBaVzUwWDNSNWNHVkpJZzVwYldGblpTOXdibWNHT3daVU9oRnpaWEoyYVdObFgyNWhiV1U2Q214dlkyRnMiLCJleHAiOm51bGwsInB1ciI6ImJsb2Jfa2V5In19--e502a110ec7258265e886e90ae501d254087ca1b/ingage.png) => "http://localhost:3000/rails/active_storage/disk/eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaDdDVG9JYTJWNVNTSWhPR3h5WkdGelptVmpNSFJwTm5SeWMyTXllako1TVdKemFtbGlhZ1k2QmtWVU9oQmthWE53YjNOcGRHbHZia2tpUDJsdWJHbHVaVHNnWm1sc1pXNWhiV1U5SW1sdVoyRm5aUzV3Ym1jaU95Qm1hV3hsYm1GdFpTbzlWVlJ..." irb(main):003:0> sleep 5.minutes => 300 irb(main):004:0> url2 = Post.last.image.url Post Load (72.4ms) SELECT "posts".* FROM "posts" ORDER BY "posts"."id" DESC LIMIT ? [["LIMIT", 1]] ActiveStorage::Attachment Load (7.0ms) SELECT "active_storage_attachments".* FROM "active_storage_attachments" WHERE "active_storage_attachments"."record_id" = ? AND "active_storage_attachments"."record_type" = ? AND "active_storage_attachments"."name" = ? LIMIT ? [["record_id", 6], ["record_type", "Post"], ["name", "image"], ["LIMIT", 1]] ActiveStorage::Blob Load (3.5ms) SELECT "active_storage_blobs".* FROM "active_storage_blobs" WHERE "active_storage_blobs"."id" = ? LIMIT ? [["id", 4], ["LIMIT", 1]] Disk Storage (2.8ms) Generated URL for file at key: 8lrdasfec0ti6trsc2z2y1bsjibj (http://localhost:3000/rails/active_storage/disk/eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaDdDVG9JYTJWNVNTSWhPR3h5WkdGelptVmpNSFJwTm5SeWMyTXllako1TVdKemFtbGlhZ1k2QmtWVU9oQmthWE53YjNOcGRHbHZia2tpUDJsdWJHbHVaVHNnWm1sc1pXNWhiV1U5SW1sdVoyRm5aUzV3Ym1jaU95Qm1hV3hsYm1GdFpTbzlWVlJHTFRnbkoybHVaMkZuWlM1d2JtY0dPd1pVT2hGamIyNTBaVzUwWDNSNWNHVkpJZzVwYldGblpTOXdibWNHT3daVU9oRnpaWEoyYVdObFgyNWhiV1U2Q214dlkyRnMiLCJleHAiOm51bGwsInB1ciI6ImJsb2Jfa2V5In19--e502a110ec7258265e886e90ae501d254087ca1b/ingage.png) => "http://localhost:3000/rails/active_storage/disk/eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaDdDVG9JYTJWNVNTSWhPR3h5WkdGelptVmpNSFJwTm5SeWMyTXllako1TVdKemFtbGlhZ1k2QmtWVU9oQmthWE53YjNOcGRHbHZia2tpUDJsdWJHbHVaVHNnWm1sc1pXNWhiV1U5SW1sdVoyRm5aUzV3Ym1jaU95Qm1hV3hsYm1GdFpTbzlWVlJ..." irb(main):005:0> url1 == url2 => true
5分経ってもURLは変わっていないですね!🎉
ちなみに Rails 6.1 からは Blob#service_url
が非推奨になり、代わりに Blob#url
を使います。*1
次回は ActiveStorage が multiple storage services に対応したことを書く予定です!
ではまた!
おまけ
Blob#service_url
を Rails Console で試してみると URI::InvalidURIError (bad URI(is not URI?): nil)
というエラーが出ました。
$ dip rails c Creating test_rails_latest_backend_run ... done Running via Spring preloader in process 14 Loading development environment (Rails 6.1.0) irb(main):001:0> Post.last.image.blob.service_url (1.2ms) SELECT sqlite_version(*) Post Load (4.6ms) SELECT "posts".* FROM "posts" ORDER BY "posts"."id" DESC LIMIT ? [["LIMIT", 1]] ActiveStorage::Attachment Load (5.6ms) SELECT "active_storage_attachments".* FROM "active_storage_attachments" WHERE "active_storage_attachments"."record_id" = ? AND "active_storage_attachments"."record_type" = ? AND "active_storage_attachments"."name" = ? LIMIT ? [["record_id", 5], ["record_type", "Post"], ["name", "image"], ["LIMIT", 1]] ActiveStorage::Blob Load (5.3ms) SELECT "active_storage_blobs".* FROM "active_storage_blobs" WHERE "active_storage_blobs"."id" = ? LIMIT ? [["id", 3], ["LIMIT", 1]] DEPRECATION WARNING: service_url is deprecated and will be removed from Rails 6.2 (use url instead) (called from irb_binding at (irb):1) Disk Storage (9.8ms) Generated URL for file at key: d7j7u5gnrvzl73uhlse3ch62n7x1 () Traceback (most recent call last): 1: from (irb):1 URI::InvalidURIError (bad URI(is not URI?): nil)
どうやら ActiveStorage::Current.host
が nil
ぽいので値を入れてあげると無事 URL を返してくれるようになりました!
irb(main):002:0> ActiveStorage::Current.host = 'http://localhost:3000' => "http://localhost:3000" irb(main):003:0> Post.last.image.blob.service_url Post Load (8.5ms) SELECT "posts".* FROM "posts" ORDER BY "posts"."id" DESC LIMIT ? [["LIMIT", 1]] ActiveStorage::Attachment Load (4.4ms) SELECT "active_storage_attachments".* FROM "active_storage_attachments" WHERE "active_storage_attachments"."record_id" = ? AND "active_storage_attachments"."record_type" = ? AND "active_storage_attachments"."name" = ? LIMIT ? [["record_id", 5], ["record_type", "Post"], ["name", "image"], ["LIMIT", 1]] ActiveStorage::Blob Load (4.0ms) SELECT "active_storage_blobs".* FROM "active_storage_blobs" WHERE "active_storage_blobs"."id" = ? LIMIT ? [["id", 3], ["LIMIT", 1]] DEPRECATION WARNING: service_url is deprecated and will be removed from Rails 6.2 (use url instead) (called from irb_binding at (irb):3) Disk Storage (4.6ms) Generated URL for file at key: d7j7u5gnrvzl73uhlse3ch62n7x1 (http://localhost:3000/rails/active_storage/disk/eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaDdDVG9JYTJWNVNTSWhaRGRxTjNVMVoyNXlkbnBzTnpOMWFHeHpaVE5qYURZeWJqZDRNUVk2QmtWVU9oQmthWE53YjNOcGRHbHZia2tpUDJsdWJHbHVaVHNnWm1sc1pXNWhiV1U5SW1sdVoyRm5aUzV3Ym1jaU95Qm1hV3hsYm1GdFpTbzlWVlJHTFRnbkoybHVaMkZuWlM1d2JtY0dPd1pVT2hGamIyNTBaVzUwWDNSNWNHVkpJZzVwYldGblpTOXdibWNHT3daVU9oRnpaWEoyYVdObFgyNWhiV1U2Q214dlkyRnMiLCJleHAiOiIyMDIxLTAxLTI0VDE1OjA1OjUxLjU4NloiLCJwdXIiOiJibG9iX2tleSJ9fQ==--bd4bd9aa30ad12d6c2512cf633f94ad49ae22a80/ingage.png) => "http://localhost:3000/rails/active_storage/disk/eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaDdDVG9JYTJWNVNTSWhaRGRxTjNVMVoyNXlkbnBzTnpOMWFHeHpaVE5qYURZeWJqZDRNUVk2QmtWVU9oQmthWE53YjNOcGRHbHZia2tpUDJsdWJHbHVaVHNnWm1sc1pXNWhiV1U5SW1sdVoyRm5aUzV3Ym1jaU95Qm1hV3hsYm1GdFpTbzlWVlJHTFRnbkoybHVaMkZuWlM1d2JtY0dPd1pVT2hGamIyNTBaVzUwWDNSNWNHVkpJZzVwYldGblpTOXdibWNHT3daVU9oRnpaWEoyYVdObFgyNWhiV1U2Q214dlkyRnMiLCJleHAiOiIyMDIxLTAxLTI0VDE1OjA1OjUxLjU4NloiLCJwdXIiOiJibG9iX2tleSJ9fQ==--bd4bd9aa30ad12d6c2512cf633f94ad49ae22a80/ingage.png"
検証していないですが、Service に Disk を使っているときに開発環境で起こるみたいです。誰かの参考になれば 🙏 🙏
*1:記事内ではごっちゃになってます。すいません!