こんにちは!kossyです!
さて、今回はrailsのActiveStorageをrails consoleで試す方法について、ブログに残してみたいと思います。
環境
Ruby 2.6.3
Rails 6.0.3
MacOS Mojave
前提として、ActiveStorageのinstallおよびmigrateを終え、適当なモデル(例ではUserモデルとします)を作成済みで、
has_one_attached :image をモデルに記述済みとします。
設定手順等は以下の記事をご参照ください。
attach・detach
has_one_attachedを記述すると、attach, detach, attached? 等のメソッドが使えるようになります。
attachは以下の方法で行うことができます。
$ bundle exec rails c $ file_path = Pathname.new("../sample.png") $ User.first.image.attach(io: File.open(file_path), filename: 'sample.png', content_type: 'image/png') User Load (11.8ms) SELECT `users`.* FROM `users` ORDER BY `users`.`id` ASC LIMIT 1 (1.0ms) BEGIN Tenant Load (1.0ms) SELECT `tenants`.* FROM `tenants` WHERE `tenants`.`id` = 1 LIMIT 1 ActiveStorage::Blob Load (0.7ms) SELECT `active_storage_blobs`.* FROM `active_storage_blobs` INNER JOIN `active_storage_attachments` ON `active_storage_blobs`.`id` = `active_storage_attachments`.`blob_id` WHERE `active_storage_attachments`.`record_id` = 1 AND `active_storage_attachments`.`record_type` = 'User' AND `active_storage_attachments`.`name` = 'image' LIMIT 1 ActiveStorage::Attachment Load (0.7ms) SELECT `active_storage_attachments`.* FROM `active_storage_attachments` WHERE `active_storage_attachments`.`record_id` = 1 AND `active_storage_attachments`.`record_type` = 'User' AND `active_storage_attachments`.`name` = 'image' LIMIT 1 ActiveStorage::Blob Create (41.5ms) INSERT INTO `active_storage_blobs` (`key`, `filename`, `content_type`, `metadata`, `byte_size`, `checksum`, `created_at`) VALUES ('81hurrmwnr639jbncqdrp29bawgs', 'otenki.png', 'image/png', '{\"identified\":true}', 11292, 'ZxJ+WIvspRPOnzLjZ4WNsQ==', '2020-08-16 14:58:50') ActiveStorage::Attachment Create (1.1ms) INSERT INTO `active_storage_attachments` (`name`, `record_type`, `record_id`, `blob_id`, `created_at`) VALUES ('image', 'User', 1, 3, '2020-08-16 14:58:50') User Update (0.7ms) UPDATE `users` SET `users`.`updated_at` = '2020-08-16 14:58:50.197520' WHERE `users`.`id` = 1 (26.0ms) COMMIT Disk Storage (2.5ms) Uploaded file to key: 81hurrmwnr639jbncqdrp29bawgs (checksum: ZxJ+WIvspRPOnzLjZ4WNsQ==) Enqueued ActiveStorage::AnalyzeJob (Job ID: a52b37af-0810-48bc-9474-b7c85bd8ddde) to Async(active_storage_analysis) with arguments: #<GlobalID:0x00007fe2ccbeab98 @uri=#<URI::GID gid://sfa-rails/ActiveStorage::Blob/3>> => true
detachは簡単で、imageに対して実行するだけです。
User.first.image.detach User Load (15.8ms) SELECT `users`.* FROM `users` ORDER BY `users`.`id` ASC LIMIT 1 ActiveStorage::Attachment Load (2.5ms) SELECT `active_storage_attachments`.* FROM `active_storage_attachments` WHERE `active_storage_attachments`.`record_id` = 1 AND `active_storage_attachments`.`record_type` = 'User' AND `active_storage_attachments`.`name` = 'image' LIMIT 1 ActiveStorage::Attachment Destroy (52.0ms) DELETE FROM `active_storage_attachments` WHERE `active_storage_attachments`.`id` = 3 => nil
ちなみに、detachと似たメソッドでpurgeメソッドもあります。
User.first.image.purge User Load (0.7ms) SELECT `users`.* FROM `users` ORDER BY `users`.`id` ASC LIMIT 1 ActiveStorage::Attachment Load (0.6ms) SELECT `active_storage_attachments`.* FROM `active_storage_attachments` WHERE `active_storage_attachments`.`record_id` = 1 AND `active_storage_attachments`.`record_type` = 'User' AND `active_storage_attachments`.`name` = 'image' LIMIT 1 ActiveStorage::Attachment Destroy (3.3ms) DELETE FROM `active_storage_attachments` WHERE `active_storage_attachments`.`id` = 4 ActiveStorage::Blob Load (0.9ms) SELECT `active_storage_blobs`.* FROM `active_storage_blobs` WHERE `active_storage_blobs`.`id` = 4 LIMIT 1 (0.5ms) BEGIN ActiveStorage::Attachment Exists? (0.6ms) SELECT 1 AS one FROM `active_storage_attachments` WHERE `active_storage_attachments`.`blob_id` = 4 LIMIT 1 ActiveStorage::Attachment Load (0.6ms) SELECT `active_storage_attachments`.* FROM `active_storage_attachments` WHERE `active_storage_attachments`.`record_id` = 4 AND `active_storage_attachments`.`record_type` = 'ActiveStorage::Blob' AND `active_storage_attachments`.`name` = 'preview_image' LIMIT 1 ActiveStorage::Blob Destroy (14.0ms) DELETE FROM `active_storage_blobs` WHERE `active_storage_blobs`.`id` = 4 (0.7ms) COMMIT Disk Storage (0.3ms) Deleted file from key: udidu0lp13b3h0u3pgmfvqzg0yuk Disk Storage (0.3ms) Deleted files by key prefix: variants/udidu0lp13b3h0u3pgmfvqzg0yuk/ => nil
detachメソッドと異なるのは、DiskのStorage(ファイルの実体)も一緒に削除する点です。
ハマりどころやユースケースについては以下の記事が詳しかったです。
エンコード
APIモードを使っていると、encodeした画像のバイナリデータをそのままフロントに渡すケースもあるかと思います。
以下にencodeの手順を記載します。
$ file_path = Pathname.new("../sample.png") $ User.first.image.attach(io: File.open(file_path), filename: 'sample.png', content_type: 'image/png') $ Base64.encode64(User.first.image.download) => "iVBORw0KGgoAAAANSUhEUgAAAFkAAADwCAYAAABrGMiJAAAYUWlDQ1BJQ0Mg\nUH..."
上記のように標準モジュールのBase64のencode64メソッドの引数に、attachしたimageをdownloadしたものを渡せばencodeできます。
勉強になりました。
参考にさせていただいたサイト
Rails Console から ActiveStorage にファイルをアタッチする方法 - Qiita
ActiveRecord トランザクションと ActiveStorage をちょっとだけ仲良くさせる方法 - SmartHR Tech Blog
Active Storage の概要 - Railsガイド
ActiveStorage::Attached::One
APIモードのRailsでActive StorageとS3を使ってバックエンド、Reactでフロントエンドを実装したい - tomoyaf blog
【Rails 5.2】 Active Storageの使い方 - Qiita