個人開発のWebアプリ「まちかどルート」v6.0rc6への実装メモです。
Amazon S3に画像をダイレクトアップロード
Railsガイドをもとに実装しました。
セーフサーチを実装
前回の記事のとおりです。
【Rails】Active Storage環境下でGoogle Cloud Visionのセーフサーチを実装
S3アップロード画像のパブリックURLを取得
こちらの記事を参考にしました。
Rails ActiveStorage で PUBLIC な URL を表示する
セーフサーチを非同期処理化
※controllerのコードは省略します
model
has_one_attached :image
after_commit :annotate_self, on: [:create, :update]
def annotate_self
if image.attached?
ImageAnnotateJob.set(wait: 10.second).perform_later(self)
end
end
postの新規投稿もしくは編集のときに画像image
が添付されていたらImageAnnotateJob
というActive Jobのキューを走らせます。10秒後に走らすようセットした理由は、Amazon S3へのアップロード完了までのタイムラグが発生するかなと思ったからです。
job
class ImageAnnotateJob < ApplicationJob
queue_as :second
def perform(target)
tempfile = target.image.attachment.service.send(:object_for, target.image.key).public_url
require "google/cloud/vision"
image_annotator = Google::Cloud::Vision::ImageAnnotator.new
response = image_annotator.safe_search_detection image: tempfile
# 注1
response.responses.each do |res|
safe_search = res.safe_search_annotation.to_h
if safe_search.values.include?(:VERY_LIKELY) || safe_search.values.include?(:LIKELY)
target.destroy
return
end
end
end
end
いったんtempfile
にS3アップロード画像のパブリックURLを格納。それをGoogle Cloud Visionのセーフサーチにかけます。このコードはすべてActive Jobによってバックグラウンド(非同期)処理されます。もし不適切な画像と判断されれば投稿そのものを削除する流れです。
注1: 2022/05/19
初出の書き方だとAPIの仕様が変わったため正常動作しなくなったのでif
~end
の部分をこのように書き換えたら動くようになりました。to_h
メソッドを使っているのがポイントです。
Sidekiq
:concurrency: 5
:queues:
- [default, 7]
- [second, 5]
じぶんはActive JobのライブラリとしてSidekiqを使用しています。上記image_annotate_job.rb
のqueue_as :second
によってキューが処理される優先順位を設定しました。
あとがき
駆け足ですが以上です。Google Cloud Visionのセーフサーチは高精度ですがレスポンスに1~2秒ほど要するため、そのぶん前回の記事のような同期処理だと投稿完了までにユーザーを待たせてしまううえ、サーバーサイドに負荷がかかります。今回の記事はそれらの課題を解決するものとなります。
また、苦労したのがS3アップロード画像のパブリックURLを取得する部分でした。url_for
やrails_blob_url
といったActive Storageのメソッドを使うと時限的なものorリダイレクトされるURLしか取得できずセーフサーチにかけても「そんな画像はありませんよ」と言われてしまいます。
というわけで試行錯誤を経たおかげでよりレスポンス性とセキュリティ性を兼ね備えた画像投稿機能を実装できました。
補足: Rails 6.0ではこちらもご覧ください
https://qiita.com/west2538/items/f932978e79220b880693
gemのv1.0.0に対応した記事を書きました
https://qiita.com/west2538/items/89bdbc4a935d12a65202