CarrierWaveとActive Storageでのファイルアップロードの説明を書きます。
この記事はActive Storageになります。
前提
AWSアカウント作成済み
IAMユーザのアクセスキーを取得済み
S3のバケット作成済み
Active Storageとは
Rails5.2から使えるようになったRails標準の機能になります。
CarrierWaveをよく使っていましたが、今後はActive Storageを使う機会が
増えると思います。
ですが、バリデーションの機能はないため、自前で作成する必要があります。
環境
ruby 2.5.1
rails 5.2.2
githubでソースを公開しています。
手順
gemを追加
gem 'mini_magick', '~> 4.8'
gem "aws-sdk-s3", require: false
gem "figaro", "~> 1.1.1"
mini_magick: 画像をリサイズする為に必要なgem
aws-sdk-s3: s3にファイルアップロードする為に必要なgem
figraro: 環境変数を設定するgem
$ bundle install --path vendor/bundler
Active Storageの設定
下記のコマンドを実行して
active_storage_blobs
active_storage_attachments
のテーブルを作成します。
$ bundle exec rails active_storage:install
$ bundle exec rake db:migrate
figaroの設定
下記のコマンドを実行して、application.ymlを生成します
$ bundle exec figaro install
s3の設定
ここでaccess_keyやsecret_access_key,backet名は
application.ymlに設定しています(figraroのgem)
application.ymlにはaccess_keyなどが記載されていますので
.gitignoreに追記をします。
# Ignore application configuration
/config/application.yml
AWS_ACCESS_KEY_ID: "○○○○"
AWS_SECRET_ACCESS_KEY: "○○○○"
AWS_BUCKET: "○○○○"
DATABASE_USERNAME: "root"
DATABASE_PASSWORD: ""
storage.yml
のamazonの箇所のコメントを外します。
# Use rails credentials:edit to set the AWS secrets (as aws:access_key_id|secret_access_key)
amazon:
service: S3
access_key_id: <%= ENV["AWS_ACCESS_KEY_ID"] %>
secret_access_key: <%= ENV["AWS_SECRET_ACCESS_KEY"] %>
region: ap-northeast-1
bucket: <%= ENV["AWS_BUCKET"] %>
development.rb
のstorageのserviceをamazonにします(上記のキー名)
今回はローカル環境のdevelopmentのenvironmentで設定をしますが
皆さんの開発環境でローカルはfile storage、本番環境はaws s3の場合は
適時変更してください。
# Store uploaded files on the local file system (see config/storage.yml for options)
config.active_storage.service = :amazon
モデルの作成、修正
Commentモデルを作成します。
contentカラムを追加します。
$ bundle exec rails g model comment
class CreateComments < ActiveRecord::Migration[5.2]
def change
create_table :comments do |t|
t.string :content
t.timestamps
end
end
end
$ bundle exec rake db:migrate
Commentモデルに
1つの画像を送付する場合はhas_one_attached
を指定します。
複数の画像を送付する場合はhas_many_attached
を指定します。
class Comment < ApplicationRecord
has_one_attached :icon
has_many_attached :images
end
コントローラーの作成
$ bundle exec rails g scaffold_controller comments
コントローラーはpermit
にicon
とimages
を追加します。
imagesは配列で送られてくる為、images:[]
と指定します。
class CommentsController < ApplicationController
before_action :set_comment, only: [:show, :edit, :update]
# GET /comments
def index
@comments = Comment.all
end
# GET /comments/1
def show
end
# GET /comments/new
def new
@comment = Comment.new
end
# GET /comments/1/edit
def edit
end
# POST /comments
def create
@comment = Comment.new(comment_params)
respond_to do |format|
if @comment.save
format.html { redirect_to @comment, notice: 'Comment was successfully created.' }
else
format.html { render :new }
end
end
end
# PATCH/PUT /comments/1
def update
respond_to do |format|
if @comment.update(comment_params)
format.html { redirect_to @comment, notice: 'Comment was successfully updated.' }
else
format.html { render :edit }
end
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_comment
@comment = Comment.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def comment_params
params.fetch(:comment, {}).permit(:content, :icon, images: [])
end
end
アップロード
viewでは複数ファイルの送付の場合はmultiple: true
を指定します。
<%= form_with(model: comment, local: true) do |form| %>
<% if comment.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(comment.errors.count, "error") %> prohibited this comment from being saved:</h2>
<ul>
<% comment.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="actions">
アイコンアップロード<br /><%= form.file_field :icon %><br>
イメージアップロード<br /><%= form.file_field :images, multiple: true %><br>
<%= form.text_area :content %><br>
<%= form.submit %>
</div>
<% end %>
画像表示
1つの画像(icon)を表示する場合と複数の画像(images)を表示する場合
resizeをする場合は下記のように記載します。
<% if comment.icon.attached? %>
<%= image_tag comment.icon.variant(resize: "200x200") %>
<% end %>
<% if comment.images.attached? %>
<% comment.images.each do |image| %>
<%= image_tag image.variant(resize: "200x200") %>
<% end %>
<% end %>