ActiveStorageを rails c で試す

こんにちは!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