LoginSignup
7
5

More than 5 years have passed since last update.

Active StorageによるRails ファイルアップロード

Last updated at Posted at 2019-01-20

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を追加

Gemfile
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に追記をします。

.gitignore
# Ignore application configuration
/config/application.yml
config/application.yml
AWS_ACCESS_KEY_ID: "○○○○"
AWS_SECRET_ACCESS_KEY: "○○○○"
AWS_BUCKET: "○○○○"
DATABASE_USERNAME: "root"
DATABASE_PASSWORD: ""

storage.ymlのamazonの箇所のコメントを外します。

config/storage.yml
# 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の場合は
適時変更してください。

config/environments/development.rb
  # 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
db/migrate/20190121053311_create_comments.rb
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を指定します。

app/models/comment.rb
class Comment < ApplicationRecord
  has_one_attached :icon
  has_many_attached :images
end

コントローラーの作成

$ bundle exec rails g scaffold_controller comments 

コントローラーはpermiticonimagesを追加します。
imagesは配列で送られてくる為、images:[]と指定します。

app/controllers/comments_controller.rb
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を指定します。

app/views/comments/_form.html.erb
<%= 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をする場合は下記のように記載します。

app/views/comments/index.html.erb
<% 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 %>
7
5
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
7
5