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
--Créez un écran pour sélectionner et envoyer des images avec Vue
storage
et renvoie l'URL de l'image enregistrée
--Recevoir et afficher l'URL de l'image avec VueJe 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
$ 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.
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
$ 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
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
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
É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é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é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>
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
Le code source est disponible sur GitHub J'espère que ça aide https://github.com/youichiro/rails-vue-file-uploader-sample
Recommended Posts