AXLSX – Vos fichiers xlsx, tout simplement en Ruby – En CSV



AXLSX – Vos fichiers xlsx, tout simplement en Ruby – En CSV

0 0


introducing-AXLSX

Slides of my speach at Paris.rb meetup

On Github pimpin / introducing-AXLSX

AXLSX

Vos fichiers xlsx, tout simplement en Ruby

Présentation de Pierre Merlin, le 7 janvier 2012, au Paris.rb

Bonjour

Pierre Merlin, développeur freelance. e-mail: pierre at apido.org

: Pimpin

Agiliste webdev dispo heureux rugby.

Le besoin du client :

Je voudrais récupérer mes chiffres de production dans mon tableur. KISS

En CSV

Grâce à la librairie CSV de Ruby 1.9, vous pouvez exporter des données.

Modifiez votre contrôleur,

##/app/controllers/products_controller.rb

class ProductsController < ApplicationController
  def index
    @products = Product.order(:name)
    respond_to do |format|
      format.html
      format.csv { render text: @products.to_csv }
    end
  end
end
            
send_data pour downloader le fichier au lieu d'avoir un rendu en ligne cf http://apidock.com/rails/ActionController/Streaming/send_data format.csv { send_data @products.to_csv } format.xls { send_data @products.to_csv(col_sep: "\t") }

Equipez votre modèle,

##/app/models/product.rb

class Product < ActiveRecord::Base
  attr_accessible :name, :price, :released_on
  
  def self.to_csv
    CSV.generate do |csv|
      csv << column_names
      all.each do |product|
        csv << product.attributes.values_at(*column_names)
      end
    end
  end
end
            

Et voila !

Oui, mais...

Quand on ouvre la base de donnée ça marche pas. On peut pas faire un fichier Excel "normal"? KISS

OK : on fait du "EXCEL"

On déclare le nouveau type,

##/config/initializers/mime_types.rb

Mime::Type.register "application/xls", :xls
            

on adapte son contrôleur,

##/app/controllers/products_controller.rb

class ProductsController < ApplicationController
  def index
    @products = Product.order(:name)
    respond_to do |format|
      format.html
      format.csv { send_data @products.to_csv }
      format.xls { send_data @products.to_csv(col_sep: "\t") }
    end
  end
end
            
We’ll need to modify our controller now so that it responds to this type. The data needs to be tab-separated to open up properly in Excel; fortunately the csv library supports a column separator option that we can pass a tab character to to do this.

Oui, mais...

C'est pas très joli. Mes colonnes ne s'alignent pas comme il faut etc...

Soit. Développons une mise ne forme plus poussée à l'aide d'un template.

Instead of rendering the data in the controller we’ll create a template file for rendering the xls file. First we’ll remove the block from the xls’s format in the controller.

On allège le contrôleur (bonne pratique)

##app/controllers/products.rb

class ProductsController < ApplicationController
  def index
    @products = Product.order(:name)
    respond_to do |format|
      format.html
      format.csv { send_data @products.to_csv }
      format.xls
    end
  end
end
            

Et on crée un template

/app/views/products/index.xls.erb

<table border="1">
  <tr>
    <th>ID</th>
    <th>Name</th>
    <th>Release Date</th>
    <th>Price</th>
  </tr>
  <% @products.each do |product| %>

  <tr>
    <td><%= product.id %></td>
    <td><%= product.name %></td>
    <td><%= product.released_on %></td>
    <td><%= product.price %></td>
  </tr>
  <% end %>

</table>'

en "Excel"

Construire des fichiers EXCEL "à la mano", Ce n'est pas compliqué : RTFM.

Et voila un template "minimaliste".

/app/views/products/index.xls.erb

'<?xml version="1.0"?>'
<Workbook xmlns="urn:schemas-microsoft-com:office:spreadsheet"
  xmlns:o="urn:schemas-microsoft-com:office:office"
  xmlns:x="urn:schemas-microsoft-com:office:excel"
  xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet"
  xmlns:html="http://www.w3.org/TR/REC-html40">
  <Worksheet ss:Name="Sheet1">
    <Table>
      <Row>
        <Cell><Data ss:Type="String">ID</Data></Cell>
        <Cell><Data ss:Type="String">Name</Data></Cell>
        <Cell><Data ss:Type="String">Release Date</Data></Cell>
        <Cell><Data ss:Type="String">Price</Data></Cell>
      </Row>
    <% @products.each do |product| %>
      <Row>
        <Cell><Data ss:Type="Number"><%= product.id %></Data></Cell>
        <Cell><Data ss:Type="String"><%= product.name %></Data></Cell>
        <Cell><Data ss:Type="String"><%= product.released_on %></Data></Cell>
        <Cell><Data ss:Type="Number"><%= product.price %></Data></Cell>
      </Row>
    <% end %>
    </Table>
  </Worksheet>
</Workbook>

Oui, mais...

Et je peux avoir des couleurs ? Chaque fois, je fais le même graphique; j'aimerais récupérer un fichier avec ce graphique déjà inclus... Et ma secrétaire n'a pas de licence Microsoft Excel, ce serait bien qu'elle puisse ouvrir le fichier avec Open Office.

Attention la doc.

Instead of rendering the data in the controller we’ll create a template file for rendering the xls file. First we’ll remove the block from the xls’s format in the controller.

AXLSXà la rescousse

fonctionalités :

prise en charge des données formatées en UTF-8

formatage les pourcentage en tant que chiffres, des dates en tant que date etc.

intégration des formules de calcul dans le fichier Excel

création de fichiers avec plusieurs feuilles

Vous en voulez plus ?

édition de graph en battons, camemberts, histogrammes....

insertion d'images

gestion des styles

protection par mot de passe

gestion de la mise en forme pour impression

...

AXLSX en pratique

La base :

p = Axlsx::Package.new
wb = p.workbook
wb.add_worksheet(:name => "Ventes") do |sheet|
  sheet.add_row Product.attribute_name
  @products.each do |product|
    sheet.add_row product.attributes.values
  end
end
p.serialize('ventes.xlsx')

ajoutons du style

p = Axlsx::Package.new
wb = p.workbook

wb.styles do |s|
  black_cell = s.add_style :bg_color => "00", :fg_color => "FF", :sz => 14, :alignment => { :horizontal=> :center }
  blue_cell = s.add_style :bg_color => "0000FF", :fg_color => "FF", :sz => 20, :alignment => { :horizontal=> :center }
end

wb.add_worksheet(:name => "Ventes") do |sheet|
  sheet.add_row Product.attribute_name
  @products.each do |product|
    sheet.add_row product.attributes.values, :style => [black_cell, blue_cell, black_cell]
  end
end
p.serialize('ventes.xlsx')
          

Vous prendrez bien du camembert ?

wb.add_worksheet(:name => "statistiques") do |sheet|
  sheet.add_row ["catégorie"] + sells_by_categorie.map(&:category)
  sheet.add_row ["Volume de vente"] + sells_by_categorie.map(&:amount)

  sheet.add_chart(Axlsx::Pie3DChart,
    :start_at => [0,5],
    :end_at => [10, 20],
    :title => "Répartition des ventes par catégorie") do |chart|
      chart.add_series :data => sheet["B2:B6"],
        :labels => sheet["A2:A6"],
        :colors => ['FF0000', '00FF00', '0000FF']
  end
end
          

Et enfin...

cerise sur le gateau

distribué sous licence MIT

trés bonne couverture

documenté

support actif

intégration continue sur Travis CI

utilisez, contribuez, participez.

Merci

Des questions ?

Crédits et liens utiles: