一番最初のパターンで、
File.open(Rails.root.join("app/assets/images/houseblend.jpeg"))
~~とやってもうまくいかないでしょうか。
~~
完全に読み違えていました。
Drinkのimageが必須になっているのでこれが任意にできるのなら簡単なんですけれど。
手元で試せないのでうまくいくか未確認ですが、ActiveStorage::Blob.create_and_upload! を使ってみるとどうなるでしょうか。
最初のパターンでこう書きます。
iamge: ActiveStorage::Blob.create_and_upload!(io: File.open(Rails.root.join("app/assets/images/houseblend.jpeg"))
Rails.root.joinはなくても動く気はしますけれど。
--
こうすればうまくいくかな?と考えるに至ったプロセスを説明します。
よくある使い方はRails Guideなんかに書いてあるやつですね。
https://railsguides.jp/active_storage_overview.html#file-io-objects%E3%82%92%E3%82%A2%E3%82%BF%E3%83%83%E3%83%81%E3%81%99%E3%82%8B
例えばすでに保存済みの User モデルのインスタンス、@user に対して @user.image.attach みたいな使い方を行えます。
実際に試した2個目のやり方はこれをやろうとしたんだと思いますが、Drink モデルの image は必須になっており、後から画像だけ追加というやり方は今回は使えません。
で、 ArgumentError: Could not find or build blob: expected attachable,
というエラーメッセージです。
日本語に訳すと「ファイルが見つからないか、またはblobの作成に失敗しました」みたいな感じです。
なので、blobデータを必要としているように見えます。
ActiveStorageは active_storage_blobs
と active_storage_attachments
の二つのテーブルで機能を実現しています。
これはつまり ActiveStorage::Blob
と ActiveStorage::Attachment
の二つのモデルで構成されていて、今回はその ActiveStorage::Blob
を必要としているエラーだと解釈しました。
上の attach メソッドも、中身を見てみると blob を生成しているんですよね。
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
create_blob_from
がその blob を生成している部分。
この中身をさらに追ってみると
def create_blob_from(attachable)
case attachable
when ActiveStorage::Blob
attachable
when ActionDispatch::Http::UploadedFile, Rack::Test::UploadedFile
ActiveStorage::Blob.create_after_upload! \
io: attachable.open,
filename: attachable.original_filename,
content_type: attachable.content_type
when Hash
ActiveStorage::Blob.create_after_upload!(attachable)
when String
ActiveStorage::Blob.find_signed(attachable)
else
nil
end
end
こんな感じ。
このメソッドは残念ながら private メソッドなのでそのまま呼べないんですが、多分 public メソッドで blob を作成するものがあるだろうなと探したのが https://edgeapi.rubyonrails.org/classes/ActiveStorage/Blob.html#method-c-create_and_upload-21 って訳です。
上のコード内でも出てきてますね。
Creates a new blob instance and then uploads the contents of the given io to the service. The blob instance is going to be saved before the upload begins to prevent the upload clobbering another due to key collisions. When providing a content type, pass identify: false to bypass automatic content type inference.
って説明を読む限りもそういう目的で使う感じですしね。
実際にこれを使っている実例を探してみたものの見つけられなかったので、残念ながらサンプル的なものは提供できなかったのですが。 attach
メソッド内部でも使われていることと同じことをやる以上、非常に公式な使い方なのでまあ大丈夫だろうなと思いました。
私はそれほど ActiveStorage 使っていないので少々調べるのに時間がかかりましたが、慣れている人ならもっとスムーズに調べられるかもしれません。
コツとしては
- エラーメッセージを読む(言語やフレームワークがうまくいかない理由を教えてくれているので、一番のヒント)
- 使おうとしている機能やライブラリ(ここでは ActiveStorage)の動作の概要を理解する
- RailsGuideなどで紹介されている一般的な利用法で呼び出すメソッドが、Railsやgem内部でどう動いているかを調べる(この場合は
attach
メソッド)
というところかなと思います。
でも、これを解決できるのは個人的な感覚では中級者以上で、ちょっと難しいかな、という気はします。
実際にはそこまで調べずに解決できないかなーと、seed 側でこの手の問題を解決した情報がないかとか探してみたんですが、まあたいていはあとから attach する RailsGuide のパターンでやっている例ばかりでした。
そのものズバリの例をどこかで見つけられると上の三つのステップなんていらないんですが、まあそういつも楽できるとは限りません。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2021/02/01 16:15
2021/02/01 16:38
2021/02/01 17:09
2021/02/01 17:57
2021/02/01 18:28
2021/02/01 18:33