さっきこんな記事を書きました。
今度は、更新で画像を追加しようとしたところ、上書きされてしまいました。
追加されると思っていたのでびっくりな挙動でしたが、その辺りはこのissueにあります。
Rails5までは、追加がデフォルトの動作でしたが、Rails6からは上書きがデフォルトの動作になります。
Rails5の動作と同じにしたい場合は、config/application.rb
などで、以下の設定が必要です。
config.active_storage.replace_on_assign_to_many = false
しかし、これは設定せずに、せっかくRails6で上書きがデフォルトの動作なので、それで対応したいと思います。
対応方法
実は先ほどのissueのコメントの中に対応方法がありました。
https://github.com/rails/rails/issues/35817#issuecomment-484158884
前回の記事のビューに追加で書くとすれば、こう。
.mb-3 = f.label :images = f.file_field :images, direct_upload: true, multiple: true, accept: 'image/*' - @post.images.each do |image| = f.hidden_field :images, multiple: true, value: image.signed_id
signed_id
を付けることで、追加アップロードにできるようになりました。
新たな不具合
しかし、新たな不具合が起きました。 ファイルを追加しつつ、既存の画像を削除しようとしたら、エラーになりました。
これと同じようなエラーなのですが、@post.images
を追加してから削除して…という途中で、hidden_fieldに入れたsigned_idでは追加しようとするのに、削除フラグがONになっているからおかしくなるのでしょう。
これに関しては、スマートな回避方法を思いつきませんでした。
苦肉の策
Rails6からは上書き保存なところを利用して、削除対象のimageのsigned_idを取得して、それを上書き対象から除外しました。コントローラーのstrong_parametersでの対応となります。
class PostsController < ApplicationController # 略 private def post_params permit_params = params.require(:post).permit( :title, :content, images: [], images_attachments_attributes: [ :id, :_destroy ], ) images_attachments_attributes = permit_params.delete(:images_attachments_attributes) if images_attachments_attributes destroy_signed_ids = images_attachments_attributes.to_h.map do |_, attribute| @post.images.find_by(id: attribute[:id])&.signed_id if attribute.delete(:_destroy) end.compact permit_params[:images] -= destroy_signed_ids end permit_params end end
これで、ファイルを追加しつつ、ファイルを削除可能になりました👍
まとめ
ActiveStorageは難しい…。