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)
--Erstellen Sie einen Bildschirm zum Auswählen und Senden von Bildern mit Vue
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
$ 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.
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
$ 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
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
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
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 "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 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>
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
Der Quellcode ist auf GitHub verfügbar Ich hoffe, es hilft https://github.com/youichiro/rails-vue-file-uploader-sample
Recommended Posts