VueとRailsで画像投稿

前回の続きで、画像投稿機能を作成します

Active Storage とは

Active Storageは、ファイルアップロードを行うための機能です。

セットアップ

docker-compose run web rails active_storage:install
docker-compose run web rails db:migrate
echo 'gem "aws-sdk-s3"' >> web/Gemfile
docker-compose run web bundle
docker-compose exec web bash
apt install -y emacs
EDITOR=emacs bin/rails credentials:edit
aws:
  access_key_id: AKIAJS7O5KJPISTNNTMQ
  secret_access_key: 0pRlACR98i3BOyDei9rPaHRHLWZ3gKcE//WlNdhZ
  s3:
    region: ap-northeast-1
    bucket: activestorage-sample-bucket

[web/config/storage.yml]

test:
  service: Disk
  root: <%= Rails.root.join("tmp/storage") %>

local:
  service: Disk
  root: <%= Rails.root.join("storage") %>

# Use rails credentials:edit to set the AWS secrets (as aws:access_key_id|secret_access_key)
amazon:
  service: S3
  access_key_id: <%= Rails.application.credentials.dig(:aws, :access_key_id) %>
  secret_access_key: <%= Rails.application.credentials.dig(:aws, :secret_access_key) %>
  region: <%= Rails.application.credentials.dig(:aws, :s3, :region) %>
  bucket: <%= Rails.application.credentials.dig(:aws, :s3, :bucket) %>	

[web/config/environments/development.rb]

# ファイルをAmazon S3に保存する
config.active_storage.service = :amazon

[web/app/models/book.rb]

class Book < ApplicationRecord
  has_one_attached :avatar
end

[web/app/controllers/books_controller.rb]

class BooksController < ApplicationController
  before_action :set_book, only: [:show, :update, :destroy]

  def index
    @books = Book.all
    render json: @books
  end

  def show
    send_data @book.avatar.download,
      filename:    "sample.jpeg",
      type:        "image/jpeg",
      disposition: "inline"
  end

  def create
    file = params[:avatar]
    @book = Book.new
    @book.name = "flie"
    @book.avatar = file
    if @book.save
      render :json => { id: @book.id }
    else
      
    end
  end

  def destroy
    @book.destroy
  end

  private
    def set_book
      @book = Book.find(params[:id])
    end

    def book_params
      params.require(:book).permit(:name, :avatar)
    end
end

[vue/src/views/About.vue]

<template>
  <div class="about">
    <h1>投稿のサンプルページ</h1>
    <input :value="imagefile" @change="selectedFile" type="file" name="file">
    <button @click="upload" type="submit">アップロード</button>
    <div v-for="(book, index) in books" v-bind:key="book.id">
      <img :src="book.id | item">
      <button v-on:click="destroy(book.id, index)">
	削除
      </button>
    </div>
  </div>
</template>

<script>
 import axios from 'axios'
 export default{
   data: function () {
     return {
       books: [],
       uploadFile: null,
       addlist: null,
       imagefile: null
     }
   },
   created: function(){
     axios
       .get(`/books.json`)
       .then(response => (this.books = response.data))
       .catch(error => console.log(error))
     console.log(this.books)
     console.log(this.addlist)
   },
   methods: {
     selectedFile: function(e) {
       // 選択された File の情報を保存しておく
       e.preventDefault();
       let files = e.target.files;
       this.uploadFile = files[0];
     },
     upload: function() {
       // FormData を利用して File を POST する
       let formData = new FormData();
       formData.append('avatar', this.uploadFile);
       let config = {
         headers: {
           'content-type': 'multipart/form-data'
         }
       };
       axios
         .post('books', formData, config)
	 .then(response => {
	   this.books.push({
	     id: response.data.id
	   });
	   this.imagefile = null;
	   this.uploadFile = null;
	 })
         .catch(function(error) {
           console.log(error)
         })
     },
     destroy: function(id, index){
       axios
         .delete(`books/${id}.json`)
         .then(response => {
           this.books.splice(index, 1);
         })
         .catch(error => console.log(error))
     }
   },
   filters: {
     item: function(val){
       return "/books/" + String(val)
     }
   }
 }
</script>
Nakano
Nakano
Back-end engineer

AWS,Rails,UE4,vue.js,hugo,その他なんでもやりたい

関連項目