LoginSignup
9
9

More than 5 years have passed since last update.

Rails4でFaceBookなどから取得した画像をAWS S3にリサイズして保存する処理をConcernに切り出す

Last updated at Posted at 2016-01-17

動機

omniauthでログイン処理を実装した際、ユーザの画像もデフォルトで保存しておきたい。
実装するのはよいが、モデルに実装してしまうと複数のモデルで使うときに、同じコードを書かないといけないので、S3への画像アクセッサとしてConcernに切り出しました。
また、rmagickを使ってリサイズできるようにもしました。

前提

rmagcikはネイティブライブラリのImageMagcikに依存するのであらかじめインストールしておく必要があります。

MacにImageMagickをインストールする方法

コード

GemFile

#ruby version
ruby '2.1.5'

#rails version 
gem 'rails', '4.2.1'

gem 'rmagick'
gem 'aws-sdk', '~> 1'
gem 'aws-s3', require: 'aws/s3'
config/s3.yml
bucket: 保存したいバケット名を書いてください
access_key_id: アクセスキーを書いてください
secret_access_key: シークレットアクセスキーを書いてください

S3Access.rb
module S3Access
  extend ActiveSupport::Concern

  included do
    require 'open-uri'
    require 'rmagick'
  end

  # クラスメソッド定義
  module ClassMethods
  end

  # インスタンスメソッド

  # 拡張子取得
  def image_types
    # code
    {'JPEG' => 'jpg', 'GIF' => 'gif', 'PNG' => 'png'}
  end

  #バケットのurlを返すメソッド
  #このurlをモデル側で永続化しておき、ビューにはこのurlを表示して画像を参照する
  def backet_url
    # code
    s3config = YAML.load_file(Rails.root.join('config', 's3.yml'))
    "http://s3-us-west-2.amazonaws.com/#{s3config['bucket']}"
  end

  #バケット名を返すメソッド
  def backet
    s3config = YAML.load_file(Rails.root.join('config', 's3.yml'))
    s3 = AWS::S3.new(access_key_id: s3config['access_key_id'], secret_access_key: s3config['secret_access_key'])
    s3.buckets[s3config['bucket']]
  end


  # url経由で読み込んだ画像をs3に保存する.
  # omniauth経由でのユーザ画像登録時はこれを呼び出す
  # uri : "https://graph.facebook.com/527606440739083/picture?width=200&height=200"
  # key s3に保存するファイルのパス
  # height, width リサイズする幅、高さを指定
  def save_from_uri(uri, key, width, height)
    open(uri) do |data|
      save_from_binary(data.read, key, width, height)
    end
  end

  #アプリないで画像再設定する場合はこちらを呼ぶ
  def update_from_binary(binary, key, width, height)
    b = backet
    object = b.objects["#{key}.jpg"]
    object.delete if object.exists?
    save_from_binary(binary, key, width, height)
  end

 private:
 #保存処理共通メソッド
  def save_from_binary(binary, key, width, height)
    # code
    img = Magick::Image.from_blob(binary).first.resize_to_fill(width, height)
    img.format = 'JPEG'

    b = backet
    object = b.objects["#{key}.#{image_types[img.format]}"]
    unless object.exists?
      object.write(
        img.to_blob, # 一つ目の引数でバイナリを渡してしまえば良い
        acl: :private, # 非公開にする場合、ここで:privateを指定しておく
        content_type: "image/#{img.format.downcase}",
      )
    end
  end
end

9
9
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
9