[Rails API + Vue] Télécharger et afficher des images à l'aide du stockage actif

Je vais résumer comment télécharger et afficher des images à l'aide de Active Storage lorsque le back-end est Rails et le front-end est Vue, tout en créant un projet à partir de zéro Le code source est disponible sur GitHub

En gros le déroulement du processus de téléchargement et d'affichage des images

--Créez un écran pour sélectionner et envoyer des images avec Vue

Créer un projet Rails

Je vais le créer avec une structure de répertoires comme ↓

rails-vue-file-uploader-sample
└── backend   #Projet Rails
└── frontend  #Projet Vue

Tout d'abord, créez un projet Rails en mode API

$ mkdir rails-vue-file-uploader-sample
$ cd rails-vue-file-uploader-sample
$ rails _6.0_ new backend --api
$ cd backend
$ rails db:create

Activer le stockage actif

$ rails active_storage:install
$ rails db:migrate

Leur exécution créera deux tables nommées ** active_storage_blobs ** et ** active_storage_attachments ** Ceux-ci sont gérés par deux modèles, ** ActiveStorage :: Blob ** et ** ActiveStorage :: Attachment **.

--ActiveStorage :: Blob: modèle de gestion des méta-informations des fichiers téléchargés --ActiveStorage :: Attachment: Le modèle correspondant à la table intermédiaire entre le modèle principal et ActiveStorage :: Blob

Par exemple, si vous souhaitez que le modèle Post ait une image, la relation est la suivante. スクリーンショット 2020-11-15 16.54.33.png

Créer un modèle

Créer un modèle de publication avec le titre et l'image comme attributs Spécifiez «pièce jointe» pour le type d'image

$ rails g model post title:string image:attachment
$ rails db:migrate

Leur exécution créera une table de publications Comme vous pouvez le voir en regardant le fichier de migration, la colonne image n'est pas créée dans la table des publications Le contenu de l'attribut image est enregistré dans ActiveStorage :: Blob et ActiveStorage :: Attachment, et il sera référencé.

En regardant le app / models / post.rb généré, has_one_attached: image est spécifié Cette spécification vous permet de vous référer à l'image.

app/models/post.rb


class Post < ApplicationRecord
  has_one_attached :image
end

Créer un contrôleur

$ rails g controller posts

app/controllers/posts.rb


class PostsController < ApplicationController
  def index
    render json: Post.all
  end

  def create
    post = Post.new(post_params)
    if post.save
      render json: post
    else
      render json: post.errors, status: 422
    end
  end

  def destroy
    post = Post.find(params[:id])
    post.destroy!
    render json: post
  end

  private

  def post_params
    params.permit(:title, :image)
  end
end

J'écrirai normalement pour le moment Définir également des itinéraires

config/routes.rb


Rails.application.routes.draw do
  scope :api do
    resources :posts, only: [:index, :create, :destroy]
  end
end

Renvoie l'URL du fichier enregistré

Ajouter une méthode pour obtenir l'URL de l'image associée au modèle Post Vous devez inclure Rails.application.routes.url_helpers pour utiliser la méthode url_for

app/models/post.rb


class Post < ApplicationRecord
  include Rails.application.routes.url_helpers

  has_one_attached :image

  def image_url
    #Obtenez l'URL de l'image associée
    image.attached? ? url_for(image) : nil
  end
end

Ajoutez la valeur de image_url au JSON renvoyé par l'action

app/controllers/posts.rb


class PostsController < ApplicationController
  def index
    render json: Post.all, methods: [:image_url]  #Changer ici
  end

  def create
    post = Post.new(post_params)
    if post.save
      render json: post, methods: [:image_url]  #Changer ici
    else
      render json: post.errors, status: 422
    end
  end

  def destroy
    post = Post.find(params[:id])
    post.destroy!
    render json: post
  end

  private

  def post_params
    params.permit(:title, :image)
  end
end

Vous devez ajouter les paramètres suivants à config / environnements / development.rb pour obtenir l'URL de l'image

config/environments/development.rb


Rails.application.configure do
  ...

  #Ajoute ça
  Rails.application.routes.default_url_options[:host] = 'localhost'
  Rails.application.routes.default_url_options[:port] = 3000
end

Définir CORS pour la communication API avec Vue Décommentez «gem'rack-cors» dans le Gemfile, faites «bundle install» et écrivez «config / initializers / cors.rb» comme suit:

config/initializers/cors.rb


Rails.application.config.middleware.insert_before 0, Rack::Cors do
  allow do
    origins 'http://localhost:8080'

    resource '*',
      headers: :any,
      methods: [:get, :post, :put, :patch, :delete, :options, :head]
  end
end

Créer un projet Vue

De là, j'écrirai Vue Tout d'abord, retournez dans le répertoire racine et créez un projet Vue

$ cd rails-vue-file-uploader-sample
$ vue create frontend
$ cd frontend

J'ai choisi les paramètres de création de vue comme suit

? Please pick a preset: Manually select features
? Check the features needed for your project: Vuex, Linter
? Pick a linter / formatter config: Prettier
? Pick additional lint features: Lint on save
? Where do you prefer placing config for Babel, ESLint, etc.? In dedicated config files
? Save this as a preset for future projects? No

Créer un magasin Vuex

Écrivez Vuex comme suit J'utiliserai axios, alors installez-le

$ npm install --save axios

src/store/modules/posts.js


import axios from "axios";

const apiUrlBase = "http://localhost:3000/api/posts";
const headers = { "Content-Type": "multipart/form-data" };

const state = {
  posts: []
};

const getters = {
  posts: state => state.posts.sort((a, b) => b.id - a.id)
};

const mutations = {
  setPosts: (state, posts) => (state.posts = posts),
  appendPost: (state, post) => (state.posts = [...state.posts, post]),
  removePost: (state, id) =>
    (state.posts = state.posts.filter(post => post.id !== id))
};

const actions = {
  async fetchPosts({ commit }) {
    try {
      const response = await axios.get(`${apiUrlBase}`);
      commit("setPosts", response.data);
    } catch (e) {
      console.error(e);
    }
  },
  async createPost({ commit }, post) {
    try {
      const response = await axios.post(`${apiUrlBase}`, post, headers);
      commit("appendPost", response.data);
    } catch (e) {
      console.error(e);
    }
  },
  async deletePost({ commit }, id) {
    try {
      axios.delete(`${apiUrlBase}/${id}`);
      commit("removePost", id);
    } catch (e) {
      console.error(e);
    }
  }
};

export default {
  namespaced: true,
  state,
  getters,
  mutations,
  actions
};

src/store/index.js


import Vue from "vue";
import Vuex from "vuex";
import posts from "./modules/posts";

Vue.use(Vuex);

export default new Vuex.Store({
  modules: {
    posts
  }
});

Créer un composant pour télécharger des images

Créez un src / components / PostForm.vue pour afficher le formulaire pour sélectionner et soumettre une image

src/components/PostForm.vue


<template>
  <div>
    <h2>PostForm</h2>
    <section>
      <label for="title">title: </label>
      <input type="text" name="title" v-model="title" placeholder="title" />
    </section>
    <section>
      <label for="image">image: </label>
      <input type="file" id="image" name="image" accept="image/png,image/jpeg" @change="setImage" />
    </section>
    <section>
      <button type="submit" @click="upload" :disabled="title === ''">upload</button>
    </section>
  </div>
</template>

<script>
import { mapActions } from "vuex";

export default {
  name: "PostForm",
  data: () => ({
    title: "",
    imageFile: null
  }),
  methods: {
    ...mapActions("posts", ["createPost"]),
    setImage(e) {
      e.preventDefault();
      this.imageFile = e.target.files[0];
    },
    async upload() {
      let formData = new FormData();
      formData.append("title", this.title);
      if (this.imageFile !== null) {
        formData.append("image", this.imageFile);
      }
      this.createPost(formData);
      this.resetForm();
    },
    resetForm() {
      this.title = "";
      this.imageFile = null;
    }
  }
};
</script>

Les images sélectionnées peuvent être récupérées avec e.target.files Lors de l'envoi d'une requête POST, spécifiez la valeur requise pour FormData comme paramètre.

Créer un composant qui affiche une image

Créez un src / components / PostList.vue pour récupérer et afficher l'image enregistrée

src/components/PostList.vue


<template>
  <div>
    <h2>PostList</h2>
    <div v-for="post in posts" :key="post.id">
      <h3>{{ post.title }}</h3>
      <img :src="post.image_url" />
      <br />
      <button type="submit" @click="del(post.id)">delete</button>
    </div>
  </div>
</template>

<script>
import { mapActions, mapGetters } from "vuex";

export default {
  name: "PostList",
  created() {
    this.fetchPosts();
  },
  computed: {
    ...mapGetters("posts", ["posts"])
  },
  methods: {
    ...mapActions("posts", ["fetchPosts", "deletePost"]),
    del(id) {
      this.deletePost(id);
    }
  }
};
</script>

Spécifiez l'URL acquise dans src avec <img: src =" post.image_url "/> et affichez-la.

Enfin, modifiez App.vue pour afficher les composants

src/App.vue


<template>
  <div id="app">
    <PostForm />
    <PostList />
  </div>
</template>

<script>
import PostForm from "./components/PostForm.vue";
import PostList from "./components/PostList.vue";

export default {
  name: "App",
  components: {
    PostForm,
    PostList
  }
};
</script>

Achevée

Sélectionnez une image et appuyez sur le bouton de téléchargement pour enregistrer et afficher l'image Les images sont stockées au format binaire dans le répertoire backend / storage

スクリーンショット 2020-11-15 17.43.33.png

Le code source est disponible sur GitHub J'espère que ça aide https://github.com/youichiro/rails-vue-file-uploader-sample

référence

Recommended Posts

[Rails API + Vue] Télécharger et afficher des images à l'aide du stockage actif
[Rails] Comment télécharger des images sur AWS S3 à l'aide de Carrierwave et de fog-aws
[Rails] Comment télécharger des images sur AWS S3 à l'aide de refile et refile-s3
[rails6.0.0] Comment enregistrer des images en utilisant Active Storage au format assistant
[Rails] Comment télécharger des images à l'aide de Carrierwave
Rails Active Storage réduit les images avant le téléchargement
[Rails] Comment télécharger plusieurs images à l'aide de Carrierwave
[Rails] Afficher les avatars dans les messages à l'aide du stockage actif
Comment lier des images à l'aide de FactoryBot Active Storage
Créez un éditeur de démarques par glisser-déposer dans Rails 6 (à l'aide d'Active Storage, SimpleMDE et Inline Attachment)
[Rails] Enregistrez des images à l'aide de carrierwave
Enregistrer et afficher plusieurs images
Créons un système de téléchargement de fichiers à l'aide de l'API Azure Computer Vision et du SDK Java d'Azure Storage
Afficher la définition d'API dans l'interface utilisateur Swagger à l'aide de Docker + Rails6 + apipie
[Java] Téléchargez une image et convertissez-la en Base64
[Rails 6] Développement d'API à l'aide de GraphQL (Query)
[Rails] Comment utiliser Active Storage
Construction de l'environnement du serveur API Rails à l'aide de docker-compose
Publier / supprimer plusieurs images avec Active Storage
[Java] Obtenez et affichez la date 10 jours plus tard à l'aide de l'API Time ajoutée à partir de Java 8.
[Ruby on Rails] Ajoutez et supprimez des balises et affichez les messages (succès / erreur) en utilisant ajax.
[Rails] Nous avons résumé les emplacements de stockage et l'utilisation des images des développeurs et des utilisateurs.