福田です
ActiveStorage便利ですよね
railsのmodelにファイルを簡単に紐づけることができるんですが、form postされたファイルだけじゃなくてdirect uploadで発行された謎トークンとかもattachできて混乱しちゃったので、結局何がattachできるのかコード読んで調べてみました
↓はhas_oneなattachのコードです
# Associates a given attachment with the current record, saving it to the database. # # person.avatar.attach(params[:avatar]) # ActionDispatch::Http::UploadedFile object # person.avatar.attach(params[:signed_blob_id]) # Signed reference to blob from direct upload # person.avatar.attach(io: File.open("/path/to/face.jpg"), filename: "face.jpg", content_type: "image/jpg") # person.avatar.attach(avatar_blob) # ActiveStorage::Blob object def attach(attachable) blob_was = blob if attached? blob = create_blob_from(attachable) unless blob == blob_was transaction do detach write_attachment build_attachment(blob: blob) end blob_was.purge_later if blob_was && dependent == :purge_later end end
どうやらattachは四種類の引数を受け取るようです
ActionDispatch::Http::UploadedFile
- form postされたfile
signed_blob_id
- ファイルそのものではなくてdirect uploadでアップロードされたファイルを表すID?
io
- IOクラスのインスタンス
ActiveStorage::Blob
active_storage_blobs
かな?- すでにattachされてるファイルを別のmodelに紐づけたりできそう
IOクラスのインスタンスを直接attachできるのは初めて知ったので試してみましょう
User model作って
class User < ApplicationRecord has_one_attached :avatar end
適当に置いといたpngをattachしてみる
irb(main):012:0> f = File.open(Rails.root.join('storage', 'sample_avatar.png').to_s) => #<File:/app/storage/sample_avatar.png> irb(main):013:0> User.first.avatar.attach(io: f, filename: 'sample_avatar.png', content_type: 'image/png')
urlを取得してみる
irb(main):023:0* include Rails.application.routes.url_helpers => Object irb(main):024:0> default_url_options[:host] = "localhost:3000" => "localhost:3000" irb(main):025:0> url_for User.first.avatar User Load (0.3ms) SELECT `users`.* FROM `users` ORDER BY `users`.`id` ASC LIMIT 1 ActiveStorage::Attachment Load (1.9ms) 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` = 'avatar' LIMIT 1 ActiveStorage::Blob Load (0.4ms) SELECT `active_storage_blobs`.* FROM `active_storage_blobs` WHERE `active_storage_blobs`.`id` = 1 LIMIT 1 => "http://localhost:3000/rails/active_storage/blobs/eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaHBCZz09IiwiZXhwIjpudWxsLCJwdXIiOiJibG9iX2lkIn19--c0c210c1622d0f9c9d208352011ee63a9aa8d5f1/sample_avatar.png"
ちゃんとattachできてる
IOのインスタンスってことはopen-uriとか使ってweb上の画像とかも直接attachできるので、SNS連携で登録された時のデフォルトアバターとか設定するのに使えそうですね