hamayuzinの日記

エンジニアとかデータサイエンティストとかやってます。あの時 あれやってたな的な備忘録にできれば。

【aws/api gateway/lambda/s3】 api gateway ⇔ lambda ⇔ s3 で、動的に画像のresize railsから叩いてみる編

目次

  1. 全体像編
  2. lambdaでのresize編
  3. api gateway 編
  4. railsから叩いてみる編 いまここ
  5. S3で404redirect 番外編

前略

作ったresize apirailsから使う場合の設定 carrierwaveを使う前提でやる

画像保存カラム名は、image

railsの設定

今回は、content_image_controller を作成し resizeした画像を扱うだけの コントローラーを使う

view

任意のviewで

= image_tag(content_image_path(id: @hogehoge.id, resize_query: 500), alt: '画像サイズが大きすぎます。もう少し小さいサイズのアップロードをお願いします。')

controller

class ContentImagesController < ApplicationController

  def show
    hogehoge = HogeHoge.find(image_params[:id])
    # ここでimage取ってきて
    image = ImageResizer.new(hogehoge.id, image_params[:resize_query]).get_image
    # ここでimageを返す
    send_data(image, disposition: "inline", type: file_type(hogehoge) )
  end

  private

  def image_params
    params.permit(:id, :resize_query)
  end

  def file_type(hogehoge)
    "image/#{hogehoge.image.path.split('.')[-1]}"
  end

end

画像取得部分

service層を作成し そこにおいた

  1. S3に画像があるかチェック
  2. なかったらAPI叩いてresizeした画像を取得
  3. どちらであっても、画像のデータを返す

今回は、エラーの場合は、エラーの画像を返すようにした

class ImageResizer

  def initialize(id, resize_query)
    @id = id
    @resize_query = resize_query
    @hogehoge = HogeHoge.find(id)
  end

  def get_image
    begin
      bucket = Aws::S3::Resource.new(
        access_key_id: Rails.application.secrets.aws[:access_key_id],
        secret_access_key: Rails.application.secrets.aws[:secret_access_key],
        region: 'ap-northeast-1'
      ).bucket(Settings.image.bucket)
    rescue
      # 仮にシステムエラーでS3に接続できない場合は、public/system-error.pngを返す
      open("#{Rails.root}/public/system-error.png").read
    end
    # 決まったパターンのURLなので、ここで作成
    key = resized_file_name
  # 存在チェックし、あれば返答
    return bucket.object(key).get.body.read if bucket.object(key).exists?
 # なければ、ここで、resizeした画像を要求
    resized_image_body
  end

  private

  def resized_file_name
    "#{Settings.image_content.folder}/#{@id}/#{@resize_query}/#{@hogehoge.image.path.split('/')[-1]}"
  end

  def resized_image_body
    host_uri = URI.parse(Settings.image_resize_api.url)
    http = Net::HTTP.new(host_uri.host, host_uri.port)
    http.use_ssl = true
    uri = URI.parse("#{Settings.image_resize_api.url}/#{Settings.image_content.bucket}/#{Settings.image_content.folder}/#{@id}/#{@resize_query}/#{@hogehoge.image.path.split('/')[-1]}")
    req = Net::HTTP::Get.new(uri)
    req['Content-Type'] = "image/#{@hogehoge.image.path.split('.')[-1]}"
    req['Accept'] = "image/#{@hogehoge.image.path.split('.')[-1]}"
    res = http.request(req)
    case res
    when Net::HTTPSuccess
      res.body
    else
      # システムエラーのときは、public/too-big.pngを返す
      open("#{Rails.root}/public/too-big.png").read
    end
  end
end

これで、viewファイルのresize_query変えるだけで、resizeが自動で走ってくれる