[RUBY] Implémenter la fonction de téléchargement CSV dans Rails

Contexte

Nous avons décidé d'implémenter la fonction de téléchargement CSV dans Rails. Il y a déjà beaucoup d'exemples simples et excellents sur Qiita, et j'aurais pu l'implémenter facilement en regardant les articles ici.

La fonction de sortie CSV que j'ai trouvée au travail était beaucoup plus compliquée que celles-ci, j'ai donc décidé de l'implémenter tout en examinant ce que je pensais "Quel est ce mécanisme!" .. En gros, c'est proche du deuxième article présenté ci-dessus.

La version Rails est «5.2.4.2».

controller

Le contrôleur est presque le même que l'article présenté ci-dessus. Le format est divisé en html et csv, et lorsqu'il y a une demande au format csv, la méthode qui crée csv est appelée.

controllers/somethings_controller.rb


class SomethingsController < ApplicationController
  include SomeCsvModule #Je vais le définir

  def index
    @somethings = Something.all
    respond_to do |format|
      format.html
      format.csv do
        generate_csv(@somethings) #Je vais le définir
      end
    end
  end
end

view La vue est très simple, il suffit d'installer un bouton avec format :: csv ^^.

ruby:views/somethings/index.html.haml


= link_to "Téléchargement CSV", somethings_path(format: :csv)

module Le secret de cette vue et de ce contrôleur simples était dans le module. Puisqu'il s'agit d'une méthode courante pour divers contrôleurs, nous avons défini un module commun dans controllers / concerts /.

/controllers/concerns/some_csv_module.rb


module SomeCsvModule
  extend ActiveSupport::Concern

  def generate_csv(somethings)
    filename = "Liste d'informations_#{Date.today}.csv"
    set_csv_request_headers(filename)

    bom = "\uFEFF" #Je vais expliquer(1)
    self.response_body = Enumerator.new do |csv_data| #Je vais expliquer(2,3)
      csv_data << bom

      header = %i(contenu du nom d'identifiant)
      csv_data << header.to_csv #Je vais expliquer(4)

      somethings.each do |some|
        body = [
          some.id,
          some.name,
          some.content
        ]
        csv_data << body.to_csv
      end
    end
  end

  def set_csv_request_headers(filename, charset: 'UTF-8') #Je vais expliquer(5)
    #↓ je vais expliquer(6)
    self.response.headers['Content-Type'] ||= "text/csv; charset=#{charset}"
    self.response.headers['Content-Disposition'] = "attachment;filename=#{ERB::Util.url_encode(filename)}"
    self.response.headers['Content-Transfer-Encoding'] = 'binary'
  end
end

Explication 1: bom

BOM est une abréviation de «Byte Order Mark», qui est une courte chaîne de caractères au début d'un document écrit en «Unicode». Cette chaîne de caractères décrit la méthode de codage du document.

Le code de caractère standard d'Excel est Shift-JIS, et le monde de WEB est ʻUTF-8`, donc si vous essayez d'ouvrir les données de sortie CSV avec l'application WEB dans Excel, les caractères seront définitivement déformés.

Vous pouvez éviter les caractères déformés en disant à bom au début du document que le code de caractère de ce document est ʻUTF-8`.

Dans ce module, nous définissons bom =" \ uFEFF " et ajoutons bom au début des données au début du processus de création de données csv suivant.

De plus, l'explication de cette partie est créée en se référant à ces deux articles.

Explication 2: self.response_body

J'ai vérifié la partie self.response_body, mais je ne l'ai pas bien comprise ... Pardon. Cependant, si vous devinez d'après les articles ici ...

La partie qui définit la vue que Rails rend semble être self.response_body. La valeur par défaut est «nil» et vous pouvez créer une vue à rendre en affectant une valeur à «self.response_body».

Commentaire 3: Enumerator.new

ʻEnumerator.new` semble être une méthode ** "créer un élément de tableau" ** dans la mesure où j'ai vérifié en se référant à l'article suivant.

▼ Référence

Cette partie du code ci-dessus

self.response_body = Enumerator.new do |csv_data|
  csv_data << bom

  header = %i(contenu du nom d'identifiant)
  csv_data << header.to_csv

  somethings.each do |some|
    body = [
      #Omission
    ]
    csv_data << body.to_csv
  end
end

C'était la même chose.

csv_data = []
csv_data << bom

header = %i(contenu du nom d'identifiant)
csv_data << header.to_csv

somethings.each do |some|
  body = [
    #Omission
  ]
  csv_data << body.to_csv
end

self.response_body = csv_data

Explication 4: to_csv

to_csv est une méthode de la bibliothèque csv et semble être une méthode qui convertit un tableau au format csv. Vous trouverez ci-dessous le code extrait de ce document.

require 'csv'

csv_string = ["CSV", "data"].to_csv   # => "CSV,data"
csv_array  = "CSV,String".parse_csv   # => ["CSV", "String"]

Explication 5: Arguments de mot-clé

La partie charset: 'UTF-8' de cette méthode est appelée ** argument mot-clé **, qui est un moyen de spécifier une clé comme argument comme un hachage.

python


def set_csv_request_headers(filename, charset: 'UTF-8') 

▼ Cliquez ici pour plus de détails

En le spécifiant comme ceci, vous pouvez appeler la valeur ʻUTF-8avec le mot-clécharset` dans la méthode.

Commentaire 6: self.response.headers

Enfin, voici la partie

python


self.response.headers['Content-Type'] ||= "text/csv; charset=#{charset}"
self.response.headers['Content-Disposition'] = "attachment;filename=#{ERB::Util.url_encode(filename)}"
self.response.headers['Content-Transfer-Encoding'] = 'binary'

Spécifie un ensemble d'options à ajouter à l'en-tête de réponse lorsque la réponse est renvoyée. Cliquez ici pour une liste d'options.

Pour expliquer brièvement chacun,

... il semble. La partie (*) est écrite dans le Document officiel, mais pour l'instant je suis N'a pas réussi dans cet environnement. Pardon. .. ..

Sommaire

... c'est ça! Il a fallu beaucoup d'apprentissage pour comprendre le mécanisme, mais j'ai réussi à implémenter la fonction de sortie CSV ^^

▼ Bouton de sortie CSV créé: ensoleillé: Image from Gyazo

Le code que j'ai vu au travail contenait encore diverses options dans l'en-tête de réponse, organisait les processus qui peuvent être partagés sous une forme généralisée et était plein de savoir-faire, mais tout d'abord, cela J'apprendrai la forme et maîtriserai diverses options.

(Tout d'abord, je veux pouvoir écrire un test pour cela ...) Je vais continuer à me consacrer ♪

Recommended Posts

Implémenter la fonction de téléchargement CSV dans Rails
Implémenter la fonction d'application dans Rails
Markdown implémenté dans Rails
[Rails] Implémenter la fonction de recherche d'utilisateurs
Implémenter l'authentification LTI dans Rails
[Rails] Implémenter la fonction de publication d'images
Implémenter la fonction de recherche de publication dans l'application Rails (méthode where)
[Rails] Implémentez la fonction d'enregistrement / suppression de carte de crédit dans PAY.JP
[Rails] Implémentation de la fonction d'importation CSV
Ajoutez une fonction de recherche dans Rails.
[Rails] Implémentation de la fonction d'exportation CSV
Implémentez la fonction de connexion dans Rails simplement avec le nom et le mot de passe (1)
Implémentez la fonction de connexion dans Rails simplement avec juste un nom et un mot de passe (2)
[Ruby on Rails] Fonction de sortie CSV
Implémenter la fonction PHP implode en Java
Implémenter un formulaire de contact dans Rails
Implémentez la fonction de connexion simplement avec le nom et le mot de passe dans Rails (3)
Implémenter la fonction d'enregistrement des utilisateurs et la fonction d'enregistrement de l'entreprise séparément dans Rails concevoir
[Rails] Un moyen simple d'implémenter une fonction d'auto-introduction dans votre profil
J'ai essayé d'implémenter le traitement Ajax de la fonction similaire dans Rails
Les rails 6 (avec Webpacker en standard) implémentent la fonction de classement par étoiles
Comment implémenter la fonctionnalité de recherche dans Rails
[Rails] Restrictions de fonction dans l'appareil (connexion / déconnexion)
Comment implémenter la fonctionnalité de classement dans Rails
Implémenter des transitions de boutons à l'aide de link_to dans Rails
Rails CSV Basic
Implémenter la pagination des rails
[Rails] Fonction de catégorie
Group_by dans Rails
[Rails] Fonction de notification
Créer une fonction d'authentification dans l'application Rails à l'aide de devise
Implémenter un bouton de partage dans Rails 6 sans utiliser Gem
Personnalisez la sortie avec la fonction de téléchargement CSV de Wagby
Comment implémenter une fonctionnalité similaire dans Rails
Implémenter des itérations dans View en rendant une collection [Rails]
Fonction de notification simple dans Rails (uniquement lorsqu'elle est suivie)
Comment implémenter une fonctionnalité intéressante dans Ajax avec Rails
Association de modèles dans Rails
Ajout de colonnes dans les rails
Introduire la conception avec Rails pour implémenter la fonctionnalité de gestion des utilisateurs
Désactiver les turbolinks dans les rails
[rails] fonction de classement des balises
Mettre en œuvre le BAN du compte Rails
[Ruby on Rails] Fonction de prévisualisation de l'image dans le fichier
Je souhaite définir une fonction dans la console Rails
^, $ dans l'expression régulière Rails