Rails
Heroku
AWS
RubyOnRails

rails+heroku+aws s3の構成で画像を保存する

やりたいこと

画像を投稿できるようにしたいがherokuだと一時的な保存になるということなのでawsのs3に保存する。

全体構成

調べてみると2つ実装方法があった。今回はcarrierwaveを選択。

paperclip

paperclip
https://github.com/thoughtbot/paperclip

carrierwave

carrierwave
https://github.com/carrierwaveuploader/carrierwave

全体の設計

  • carrierwaveを使い、fileuploaderの作成
  • fogでawsのs3に繋ぎ、s3に画像を保存
  • URLを画像に付与してそのURLを元に表示

awsアカウント作成

https://qiita.com/junara/items/1899f23c091bcee3b058#aws

この記事のアカウント作成部分を参考に。バケットの状態については下記

https://docs.aws.amazon.com/ja_jp/AmazonS3/latest/user-guide/bucket-permissions-check.html

  • Public – 世界中の誰でも、または認証された AWS ユーザーがパブリックアクセス可能。
  • Not public* – バケットはパブリックアクセス可能ではありません。ただし、バケットのオブジェクトは、オブジェクト ACL によりパブリックアクセス可能の場合があります。
  • Access denied – バケットからロックアウトされています。
  • Error – サービス関連のエラーが発生しました。
  • Undetermined – Amazon S3 はバケットがパブリックアクセス可能かどうかを判断できません。

fogとcarrierwaveのinstall

gem 'carrierwave'
gem 'fog'

画像保存用のモデル作成

新規のモデルに追加する場合

$ rails g model image
class CreatePhotos < ActiveRecord::Migration
  def change
    create_table :photos do |t|
      t.string :image
      t.timestamps
    end
  end
end

既存のモデルに追加する場合

$ rails g migration addcolumnimage
class AddColumnimage < ActiveRecord::Migration[5.1]
  def change
    add_column :posts, :image, :string
  end
end

carrierwaveの設定

uploaderクラスの追加

rails generate uploader Image
app/uploaders/image_uploader.rb
class ImageUploader < CarrierWave::Uploader::Base
  if Rails.env.development?
    storage :file
  elsif Rails.env.test?
    storage :file
  else
    storage :fog
  end

  def store_dir
    "uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
  end

  def extension_whitelist
    %w(jpg jpeg gif png)
  end
  # ここでファイル形式を指定する
  def filename
    original_filename if original_filename
  end
end

store_dir・・・fileのupload先を変更したいときに設定する。

initializerの設定

下記のファイルを新規作成する

config/initializers/carrierwave.rb
CarrierWave.configure do |config|
  config.fog_credentials = {
    provider: 'AWS',
    aws_access_key_id: '',
    aws_secret_access_key: '',
    region: 'ap-northeast-1'
  }

  config.fog_directory  = 'rails-photo-123'
  config.asset_host = "https://s3.ap-northeast-1.amazonaws.com/バケット名"
  config.cache_storage = :fog
end

aws_access_key_id・・・awsのiamのaccesskey
aws_secret_access_key・・・awsのiamのsecretaccesskey
config.fog_directory・・・バケット名
config.asset_host・・・https://s3.リージョン名.amazonaws.com/バケット名

region

各regionの表

https://docs.aws.amazon.com/ja_jp/general/latest/gr/rande.html#s3_region

modelにmount_uploader

class Post < ActiveRecord::Base
  mount_uploader :image, ImageUploader
end

引数に(カラムの属性名, 生成されたアップローダーのクラス名)をとります。

view側の設定

form_forでタグ設置

入力用のformタグはform_forで生成する

<%= form_for @post, :url => {:action => 'create'} do |f| %>
<%= f.file_field :image %>
<% end %>

form_forで生成するとpostの下に配列が入る。なのでparamsで取ってくるときは下記のように[:post][:image]のような形になる。

@post = Post.new(title:params[:title],sns_id:params[:sns_id],sns:params[:sns],image:params[:post][:image],user_id:params[:user_id],description:params[:post][:description],post_type: params[:post_type])

https://qiita.com/shunsuke227ono/items/7accec12eef6d89b0aa9

form_forについてはこの記事が詳しい。

保存した画像を表示させる

<%= image_tag photo.image.to_s %>