[Rails API + Vue] Laden Sie Bilder mit Active Storage hoch und zeigen Sie sie an

Ich werde zusammenfassen, wie Bilder mit Active Storage hochgeladen und angezeigt werden, wenn das Back-End Rails und das Front-End Vue ist, während ein Projekt von Grund auf neu erstellt wird Der Quellcode ist auf [GitHub] verfügbar (https://github.com/youichiro/rails-vue-file-uploader-sample)

Ungefähr der Ablauf des Prozesses des Hochladens und Anzeigens von Bildern

--Erstellen Sie einen Bildschirm zum Auswählen und Senden von Bildern mit Vue

Erstellen Sie ein Rails-Projekt

Ich werde es mit einer Verzeichnisstruktur wie ↓ erstellen

rails-vue-file-uploader-sample
└── backend   #Schienenprojekt
└── frontend  #Vue-Projekt

Erstellen Sie zunächst ein Rails-Projekt im API-Modus

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

Aktivieren Sie den aktiven Speicher

$ rails active_storage:install
$ rails db:migrate

Wenn Sie diese ausführen, werden zwei Tabellen mit den Namen ** active_storage_blobs ** und ** active_storage_attachments ** erstellt. Diese werden von zwei Modellen verwaltet: ** ActiveStorage :: Blob ** und ** ActiveStorage :: Attachment **.

--ActiveStorage :: Blob: Modell zum Verwalten von Metainformationen hochgeladener Dateien --ActiveStorage :: Attachment: Ein Modell, das der Zwischentabelle zwischen dem Hauptmodell und ActiveStorage :: Blob entspricht

Wenn Sie beispielsweise möchten, dass das Post-Modell ein Bild enthält, lautet die Beziehung wie folgt. スクリーンショット 2020-11-15 16.54.33.png

Erstellen Sie ein Modell

Erstellen Sie ein Post-Modell mit Titel und Bild als Attributen Geben Sie für den Bildtyp "Anhang" an

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

Wenn Sie diese ausführen, wird eine Beitragstabelle erstellt Wie Sie anhand der Migrationsdatei sehen können, wird die Bildspalte nicht in der Beitragstabelle erstellt Der Inhalt des Bildattributs wird in ActiveStorage :: Blob und ActiveStorage :: Attachment gespeichert und referenziert.

Mit Blick auf die generierte app / models / post.rb wird has_one_attached: image angegeben Mit dieser Spezifikation können Sie sich auf das Bild beziehen.

app/models/post.rb


class Post < ApplicationRecord
  has_one_attached :image
end

Erstellen Sie einen Controller

$ 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

Ich werde vorerst normal schreiben Stellen Sie auch Routen ein

config/routes.rb


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

Geben Sie die URL der gespeicherten Datei zurück

Fügen Sie eine Methode hinzu, um die URL des zugeordneten Bilds zum Post-Modell abzurufen Sie müssen Rails.application.routes.url_helpers einschließen, um die url_for -Methode zu verwenden

app/models/post.rb


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

  has_one_attached :image

  def image_url
    #Rufen Sie die URL des zugehörigen Bildes ab
    image.attached? ? url_for(image) : nil
  end
end

Fügen Sie den Wert von image_url zu dem von der Aktion zurückgegebenen JSON hinzu

app/controllers/posts.rb


class PostsController < ApplicationController
  def index
    render json: Post.all, methods: [:image_url]  #Hier ändern
  end

  def create
    post = Post.new(post_params)
    if post.save
      render json: post, methods: [:image_url]  #Hier ändern
    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

Sie müssen die folgenden Einstellungen zu config / environment / development.rb hinzufügen, um die URL des Bildes zu erhalten

config/environments/development.rb


Rails.application.configure do
  ...

  #Füge das hinzu
  Rails.application.routes.default_url_options[:host] = 'localhost'
  Rails.application.routes.default_url_options[:port] = 3000
end

Stellen Sie CORS für die API-Kommunikation mit Vue ein Kommentieren Sie "gem'rack-cors" in der Gemfile aus, führen Sie "bundle install" aus und schreiben Sie "config / initializers / cors.rb" wie folgt:

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

Erstellen Sie ein Vue-Projekt

Von hier aus werde ich Vue schreiben Kehren Sie zunächst zum Stammverzeichnis zurück und erstellen Sie ein Vue-Projekt

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

Ich habe die vue create settings wie folgt gewählt

? 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

Erstellen Sie einen Vuex-Shop

Schreiben Sie Vuex wie folgt Ich werde Axios verwenden, also installiere es

$ 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
  }
});

Erstellen Sie eine Komponente zum Hochladen von Bildern

Erstellen Sie "src / components / PostForm.vue", um das Formular zum Auswählen und Senden eines Bildes anzuzeigen

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>

Die ausgewählten Bilder können mit "e.target.files" abgerufen werden Geben Sie beim Senden einer POST-Anforderung den erforderlichen Wert für "FormData" als Parameter an.

Erstellen Sie eine Komponente, die ein Bild anzeigt

Erstellen Sie eine src / components / PostList.vue, um das gespeicherte Bild abzurufen und anzuzeigen

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>

Geben Sie die erfasste URL in src mit <img: src =" post.image_url "/> an und zeigen Sie sie an.

Bearbeiten Sie schließlich App.vue, um die Komponenten anzuzeigen

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>

Komplett

Wählen Sie ein Bild aus und drücken Sie die Upload-Taste, um das Bild zu speichern und anzuzeigen Bilder werden im Binärformat im Verzeichnis "Backend / Speicher" gespeichert

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

Der Quellcode ist auf GitHub verfügbar Ich hoffe, es hilft https://github.com/youichiro/rails-vue-file-uploader-sample

Referenz

Recommended Posts

[Rails API + Vue] Laden Sie Bilder mit Active Storage hoch und zeigen Sie sie an
[Rails] So laden Sie Bilder mit Carrierwave und Fog-Aws in AWS S3 hoch
[Rails] So laden Sie Bilder mit refile und refile-s3 in AWS S3 hoch
[rails6.0.0] Speichern von Bildern mit Active Storage im Assistentenformat
[Rails] So laden Sie Bilder mit Carrierwave hoch
Rails Active Storage verkleinert Bilder vor dem Hochladen
[Rails] So laden Sie mehrere Bilder mit Carrierwave hoch
[Rails] Zeigt Avatare in Posts mit Active Storage an
So verknüpfen Sie Bilder mit FactoryBot Active Storage
Erstellen Sie in Rails 6 einen Drag-and-Drop-Markdown-Editor (mit Active Storage, SimpleMDE und Inline-Anhang).
[Schienen] Speichern Sie Bilder mit Carrierwave
Speichern und zeigen Sie mehrere Bilder an
Erstellen wir ein Datei-Upload-System mit der Azure Computer Vision-API und dem Java SDK von Azure Storage
Zeigen Sie die API-Definition in der Swagger-Benutzeroberfläche mit Docker + Rails6 + apipie an
[Java] Laden Sie ein Bild hoch und konvertieren Sie es in Base64
[Rails 6] API-Entwicklung mit GraphQL (Query)
[Rails] Verwendung von Active Storage
Rails API-Serverumgebungskonstruktion mit Docker-Compose
Veröffentlichen / Löschen mehrerer Bilder mit Active Storage
[Java] Abrufen und Anzeigen des Datums 10 Tage später mithilfe der von Java 8 hinzugefügten Zeit-API.
[Ruby on Rails] Hinzufügen und Löschen von Tags und Anzeigen von (Erfolgs- / Fehler-) Meldungen mit Ajax.
[Rails] Wir haben die Speicherorte und die Verwendung von Entwickler- und Benutzerimages zusammengefasst.