[RUBY] [Rails6 + Vue.js] Implémenter le processus d'importation CSV à l'aide d'axios

Notez la nécessité d'importer plusieurs fichiers CSV dans leurs tables respectives à l'aide de Vue.js et de l'API Rails.

Notez s'il vous plaît

Il est écrit par un débutant qui apprend Rails, Vue.js sous forme de mémorandum. Il est possible que le contenu contienne des erreurs et qu'il existe une meilleure méthode, veuillez donc garder cela à l'esprit lorsque vous y faites référence. Si vous avez des questions, n'hésitez pas à commenter.

Ce que vous voulez réaliser

Je veux préparer une boîte de saisie et utiliser axios pour POSTER dans la table où les fichiers CSV sélectionnés (2 types) sont préparés respectivement.

csv1 ⇨ table codes_lists csv2 ⇨ tableau des finances La définition de la table est la suivante.

code_tableau des listes


  create_table "code_lists", force: :cascade do |t|
    t.string "edinet"
    t.string "securities"
    t.string "company"
    t.string "sector"
    t.datetime "created_at", precision: 6, null: false
    t.datetime "updated_at", precision: 6, null: false
    t.index ["company"], name: "index_code_lists_on_company"
    t.index ["edinet"], name: "index_code_lists_on_edinet", unique: true
    t.index ["securities"], name: "index_code_lists_on_securities"
  end

tableau des finances


  create_table "financials", force: :cascade do |t|
    t.string "edinet"
    t.date "rec_date"
    t.string "account_name"
    t.float "value"
    t.datetime "created_at", precision: 6, null: false
    t.datetime "updated_at", precision: 6, null: false
    t.index ["account_name"], name: "index_financials_on_account_name"
    t.index ["edinet", "rec_date", "account_name"], name: "index_financials_on_edinet_and_rec_date_and_account_name", unique: true
    t.index ["edinet"], name: "index_financials_on_edinet"
  end

Préparation

Ajoutez la bibliothèque à l'avance.

config/application.rb


require 'csv' #Postscript

Ajouter Gem roo et bundle install

Gemfile


gem 'roo'

Puisque des contre-mesures de jeton csrf sont nécessaires au moment de ʻaxios-post, définissez un plug-in séparé. Créez un nouveau dossier plugins`.

app/javascript/packs/plugins/vue-axios.js


const VueAxiosPlugin = {}
export default VueAxiosPlugin.install = function(Vue, { axios }) {
  const csrf_token = document.querySelector('meta[name="csrf-token"]').getAttribute('content')
  axios.defaults.headers.common = {
    "X-Requested-With": "XMLHttpRequest",
    "X-CSRF-Token": csrf_token
  }

  Vue.axios = axios
  Object.defineProperties(Vue.prototype, {
    axios: {
      get () {
        return axios
      }
    }
  })
}

Importez le plug-in dans le fichier d'entrée

hello_vue.js


import Vue from "vue/dist/vue.esm";
import axios from "axios"; //ajouter à
import VueAxiosPlugin from "./plugins/vue-axios";  //ajouter à
import App from "./components/App.vue";

Vue.use(VueAxiosPlugin, { axios: axios }) //ajouter à

new Vue({
  el: "#app",
  render: h => h(App),
})

routage

J'ai défini le routage comme suit: Seules les pièces nécessaires sont répertoriées. Chacun a des paramètres de routage de l'API Rails. Fichier CSV pour la table code_lists vers api / code_lists / import POST le fichier csv pour la table des finances dans api / financials / import.

config/routes.rb


Rails.application.routes.draw do
  (Omis ci-dessus)
  namespace :api, format: 'json' do
    resources :code_lists do
      post :import, on: :collection
    end
  end

  namespace :api, format: 'json' do
    resources :financials do
      post :import, on: :collection
    end
  end
  (Omis ci-dessous)
end

View La vue ressemble à ceci:

Import.vue


<template>
  <div>
    <div class="import-form">
      <input @change="selectedFile" type="file" name="file">
    </div>
    <div class="import-form">
      <button @click="upload('/api/code_lists/import')" type="submit">Télécharger la liste de codes</button>
    </div>
    <div class="import-form">
      <button @click="upload('/api/financials/import')" type="submit">Télécharger des données financières</button>
    </div>
  </div>
</template>

<script>
import axios from 'axios'
export default {
  data: function(){
    return {
      uploadFile: null
    };
  },
  methods: {
    selectedFile: function(e) {
      //Enregistrer les informations du fichier sélectionné
      e.preventDefault();
      let files = e.target.files;
      this.uploadFile = files[0];
    },
    upload: function(url) {
      //Fichier POST à l'aide de FormData
      let formData = new FormData();
      formData.append('file', this.uploadFile);
      // let config = {
      //     headers: {
      //         'content-type': 'multipart/form-data'
      //     }
      // };
      axios
          .post(url, formData)
          .then(function(response) {
              //traitement des réponses
          })
          .catch(function(error) {
              //la gestion des erreurs
          })
    }
  }
}
</script>

Après avoir sélectionné le fichier dans la zone de saisie, enregistrez le fichier dans uploadFile avec la méthode selectedFile. Ensuite, la méthode de téléchargement est exécutée dans l'événement de clic du bouton. POSTER le fichier à l'url de l'argument de la méthode de téléchargement (les deux URL que vous avez définies dans les routes plus tôt). Le fait est que le uploadFile enregistré à l'avance est passé à l'objet FormData lors du POSTing. J'ai commenté parce que je n'ai pas utilisé la configuration cette fois.

Contrôleur et modèle

Cette fois, ce sera une implémentation qui importe deux fichiers csv dans chaque table, et l'implémentation est requise pour chaque modèle, mais comme le contenu est presque le même, seule l'implémentation du modèle financier est décrite. Tout d'abord sur le contrôleur.

app/controllers/api/financials_controller.rb


class Api::FinancialsController < ApplicationController
  def import
    Financial.import(params[:file])
  end
end

Le contrôleur appelle uniquement la méthode Class de Financial Class.

Ensuite, la description du modèle financier est la suivante.

app/models/financial.rb


class Financial < ApplicationRecord
  validates :edinet, presence: true
  validates :rec_date, presence: true
  validates :account_name, presence: true
  validates :value, presence: true
  def self.import(file)
    CSV.foreach(file.path, headers: true) do |row|
      #Si l'ID est trouvé, appelez l'enregistrement, s'il n'est pas trouvé, créez-en un nouveau
      financial = find_by(edinet: row["edinet"], rec_date: row["rec_date"], account_name: row["account_name"]) || new
      #Obtenez des données de CSV et définissez
      financial.attributes = row.to_hash.slice(*updatable_attributes)
      #enregistrer
      financial.save
    end
  end
  def self.updatable_attributes
    ["edinet", "rec_date", "account_name", "value"]
  end
end

Entrez le nom de colonne du CSV que vous souhaitez importer dans updatable_attributes. En outre, find_by est utilisé pour vérifier si l'enregistrement a déjà été importé, et s'il a déjà été importé, il sera écrasé.

finalement

Si vous avez des questions, n'hésitez pas à commenter. Nous développons une application qui utilise les données financières des sociétés cotées. Nous développons le front-end en utilisant Vue.js et le back-end en utilisant l'API Rails. Je voudrais continuer à résumer les conclusions que j'ai acquises dans un article. Merci d'être resté avec nous jusqu'à présent!

Articles auxquels j'ai fait référence: Contre-mesure csrf: [Vue] axios peut définir le jeton CSRF par défaut Implémentation front-end: Lorsque vous souhaitez publier un fichier avec Vue.js Implémentation du backend: [Ruby on Rails] import CSV

Recommended Posts

[Rails6 + Vue.js] Implémenter le processus d'importation CSV à l'aide d'axios
[Rails] Implémentation de la fonction d'importation CSV
Implémenter la fonction de téléchargement CSV dans Rails
Pour implémenter la publication d'images à l'aide de rails
Implémenter des transitions de boutons à l'aide de link_to dans Rails
Implémenter un bouton de partage dans Rails 6 sans utiliser Gem
Mettre en œuvre la fonction de classement par étoiles en utilisant Raty dans Rails 6
[Nuxt / Rails] Implémentation POSTed en utilisant axios et devise_token_auth
Rails CSV Basic
Implémenter la pagination des rails