<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>ASCIIcasts - Full Episode Feed</title>
    <description>The latest episodes from ASCIIcasts</description>
    <link>http://asciicasts.com/</link>
    <pubDate>Mon, 24 Oct 2011 10:25:21 +0000</pubDate>
    <ttl>1440</ttl>
    <item>
      <title>Active Admin</title>
      <description>&lt;p&gt;Dans cet &amp;eacute;pisode, nous allons voir &lt;a href="http://activeadmin.info"&gt;Active&amp;nbsp;Admin&lt;/a&gt;. Cette gem vous permet d&amp;#x27;ajouter facilement une interface d&amp;#x27;administration &amp;agrave; vos applications Rails. Elle cr&amp;eacute;e de jolies pages d&amp;#x27;administration et est tr&amp;egrave;s param&amp;eacute;trable. Vous pouvez jeter un &amp;oelig;il &amp;agrave; la &lt;a href="http://demo.activeadmin.info/admin"&gt;d&amp;eacute;mo live&lt;/a&gt; pour vous faire une id&amp;eacute;e.&lt;/p&gt;

&lt;p&gt;Nous allons ajouter Active&amp;nbsp;Admin &amp;agrave; une application Rails existante. L&amp;#x27;application que nous utiliserons est un simple syst&amp;egrave;me d&amp;#x27;e-commerce contenant un certain nombre de produits, chacun ayant un prix et appartenant &amp;agrave; une cat&amp;eacute;gorie. Nous allons utiliser Active&amp;nbsp;Admin pour cr&amp;eacute;er un interface d&amp;#x27;administration pour g&amp;eacute;rer nos produits.&lt;/p&gt;

&lt;div class="imageWrapper"&gt;
  &lt;img src="/system/photos/735/original/E284I01.png" width="799" height="460" alt="Notre application."/&gt;
&lt;/div&gt;

&lt;h3&gt;Installer Active Admin&lt;/h3&gt;

&lt;p&gt;Active&amp;nbsp;Admin est distribu&amp;eacute;e sous forme de gem et s&amp;#x27;installe, comme d&amp;#x27;habitude, gr&amp;acirc;ce &amp;agrave; une r&amp;eacute;f&amp;eacute;rence dans le &lt;code&gt;Gemfile&lt;/code&gt; et &amp;agrave; un appel &amp;agrave; &lt;code&gt;bundle&lt;/code&gt;. Notre application a &amp;eacute;t&amp;eacute; d&amp;eacute;velopp&amp;eacute;e avec Rails&amp;nbsp;3.1, nous devons donc nous assurer qu&amp;#x27;elle inclut bien &lt;code&gt;sass-rails&lt;/code&gt; car Active&amp;nbsp;Admin en d&amp;eacute;pend. Sous Rails&amp;nbsp;3.0, ce n&amp;#x27;est pas un probl&amp;egrave;me et nous n&amp;#x27;avons pas besoin de l&amp;#x27;inclure.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/Gemfile&lt;/p&gt;
&lt;pre class="ruby"&gt;gem &amp;#x27;activeadmin&amp;#x27;&lt;/pre&gt;

&lt;p&gt;Une fois que Bundler a termin&amp;eacute;, nous devons lancer un g&amp;eacute;n&amp;eacute;rateur pour ajouter les fichiers d&amp;#x27;Active&amp;nbsp;Admin &amp;agrave; notre application. Ce g&amp;eacute;n&amp;eacute;rateur va nous fournir les instructions sur les r&amp;eacute;glages que nous allons devoir effectuer apr&amp;egrave;s son lancement. Nous devons ajouter l&amp;#x27;option &lt;code&gt;host&lt;/code&gt; &amp;agrave; la configuration du Mailer dans l&amp;#x27;environnement de d&amp;eacute;veloppement, nous assurer que nous avons une URL root et que les messages flash &lt;code&gt;notice&lt;/code&gt; et &lt;code&gt;alert&lt;/code&gt; sont bien affich&amp;eacute;s dans le layout de l&amp;#x27;application.&lt;/p&gt;

&lt;pre class="terminal"&gt;$ rails g active_admin:install
      invoke  devise
    generate    devise:install
      create    config/initializers/devise.rb
      create    config/locales/devise.en.yml

==================================================================

Some setup you must do manually if you haven&amp;#x27;t yet:

  1. Setup default url options for your specific environment. Here is an example of development environment:

       config.action_mailer.default_url_options = { :host =&amp;gt; &amp;#x27;localhost:3000&amp;#x27; }

     This is a required Rails configuration. In production it must be the actual host of your application

  2. Ensure you have defined root_url to *something* in your config/routes.rb.
     For example:

       root :to =&amp;gt; &amp;quot;home#index&amp;quot;

  3. Ensure you have flash messages in app/views/layouts/application.html.erb. For example:

       &amp;lt;p class=&amp;quot;notice&amp;quot;&amp;gt;&amp;lt;%= notice %&amp;gt;&amp;lt;/p&amp;gt;
       &amp;lt;p class=&amp;quot;alert&amp;quot;&amp;gt;&amp;lt;%= alert %&amp;gt;&amp;lt;/p&amp;gt;&lt;/pre&gt;

&lt;p&gt;Nous avons d&amp;eacute;j&amp;agrave; fait tout cela pour notre application, nous sommes donc pr&amp;ecirc;ts &amp;agrave; continuer.&lt;/p&gt;

&lt;p&gt;La commande cr&amp;eacute;e &amp;eacute;galement quelques migrations, nous allons donc les lancer maintenant.&lt;/p&gt;

&lt;pre class="terminal"&gt;$ rake db:migrate&lt;/pre&gt;

&lt;h3&gt;Utiliser Active Admin&lt;/h3&gt;

&lt;p&gt;Si nous regardons la &lt;a href="http://activeadmin.info/documentation.html"&gt;documentation d&amp;#x27;Active Admin&lt;/a&gt;, nous allons voir que lorsque nous l&amp;#x27;installons, elle cr&amp;eacute;e un utilisateur ayant &lt;code&gt;admin@example.com&lt;/code&gt; comme nom d&amp;#x27;utilisateur et &lt;code&gt;password&lt;/code&gt; comme mot de passe. Nous pouvons utiliser ces identifiants pour nous connecter (vous pouvez les configurer en &amp;eacute;ditant &lt;code&gt;devise_create_admin_users.rb&lt;/code&gt; avant de lancer les migrations). Si nous visitons &lt;a href="http://localhost:3000/admin"&gt;http://localhost:3000/admin&lt;/a&gt;, une fois le serveur Rails lanc&amp;eacute;, nous allons voir un formulaire de connexion via lequel nous pouvons nous connecter avec les identifiants vus pr&amp;eacute;c&amp;eacute;demment.&lt;/p&gt;

&lt;div class="imageWrapper"&gt;
  &lt;img src="/system/photos/736/original/E284I02.png" width="799" height="458" alt="La page de connexion d&amp;#x27;Active Admin."/&gt;
&lt;/div&gt;

&lt;p&gt;Une fois que nous nous sommes connect&amp;eacute;s, nous allons &amp;ecirc;tre redirig&amp;eacute;s vers le tableau de bord d&amp;#x27;Active&amp;nbsp;Admin. Il n&amp;#x27;y aura, cependant, pas grand chose &amp;agrave; voir pour le moment.&lt;/p&gt;

&lt;div class="imageWrapper"&gt;
  &lt;img src="/system/photos/737/original/E284I03.png" width="799" height="458" alt="Tableau de bord d&amp;#x27;Active Admin."/&gt;
&lt;/div&gt;

&lt;p&gt;Nous voulons g&amp;eacute;rer nos produits. Nous allons donc ajouter notre ressource &lt;code&gt;Product&lt;/code&gt; dans Active&amp;nbsp;Admin en lan&amp;ccedil;ant cette commande&amp;nbsp;:&lt;/p&gt;

&lt;pre class="terminal"&gt;$ rails g active_admin:resource product
      create  app/admin/products.rb&lt;/pre&gt;

&lt;p&gt;Ce g&amp;eacute;n&amp;eacute;rateur va cr&amp;eacute;er un fichier &lt;code&gt;products.rb&lt;/code&gt; dans le dossier &lt;code&gt;app/admin&lt;/code&gt; de notre application. Lorsque nous rafraichissons le tableau de bord, nous allons voir un lien &amp;ldquo;Products&amp;rdquo;&amp;nbsp;; si nous cliquons sur ce lien, nous allons &amp;ecirc;tre dirig&amp;eacute;s vers une page contenant tout ce dont nous avons besoin pour g&amp;eacute;rer nos produits.&lt;/p&gt;

&lt;div class="imageWrapper"&gt;
  &lt;img src="/system/photos/738/original/E284I04.png" width="802" height="474" alt="La page d&amp;#x27;administration des produits."/&gt;
&lt;/div&gt;

&lt;p&gt;Cette page a des options de tri et de filtrage des produits sur chaque attributs. Active&amp;nbsp;Admin va m&amp;ecirc;me d&amp;eacute;tecter la relation &lt;code&gt;belongs_to&lt;/code&gt; avec &lt;code&gt;Category&lt;/code&gt; et nous fournir un menu d&amp;eacute;roulant pour filtrer nos produits par cat&amp;eacute;gorie. Cela fonctionne &amp;eacute;galement lorsque nous cr&amp;eacute;ons un nouveau produit. Les cat&amp;eacute;gories sont montr&amp;eacute;es sous forme de menu d&amp;eacute;roulant et les autres attributs seront saisis dans des champs correspondant &amp;agrave; leur type.&lt;/p&gt;
 
&lt;div class="imageWrapper"&gt;
  &lt;img src="/system/photos/739/original/E284I05.png" width="802" height="474" alt="La page de cr&amp;eacute;ation d&amp;#x27;un produit."/&gt;
&lt;/div&gt;

&lt;p&gt;Personnaliser ce comportement est tr&amp;egrave;s facile. Nous allons commencer par personnaliser la page d&amp;#x27;index des produits et en r&amp;eacute;duire le nombre de colonnes affich&amp;eacute;es. Pour cela, nous allons modifier le fichier &lt;code&gt;/app/admin/products.rb&lt;/code&gt; g&amp;eacute;n&amp;eacute;r&amp;eacute; pr&amp;eacute;c&amp;eacute;demment. Nous modifions la page d&amp;#x27;index en surchargeant la m&amp;eacute;thode &lt;code&gt;index&lt;/code&gt;. Cette m&amp;eacute;thode prend en param&amp;egrave;tre un bloc. Dans ce dernier, nous sp&amp;eacute;cifions les colonnes que nous voulons voir sur la page en appelant &lt;code&gt;column&lt;/code&gt;.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/admin/products.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;ActiveAdmin.register Product do
  index do
    column :name
    column :category
    column :released_at
    column :price
  end
end&lt;/pre&gt;

&lt;p&gt;Lorsque nous rechargeons la page des produits, nous allons voir les colonnes que nous avons choisies.&lt;/p&gt;

&lt;div class="imageWrapper"&gt;
  &lt;img src="/system/photos/740/original/E284I06.png" width="802" height="474" alt="La page des procuits montre notre choix de colonnes."/&gt;
&lt;/div&gt;

&lt;p&gt;Notez que l&amp;#x27;association &lt;code&gt;Category&lt;/code&gt; a &amp;eacute;t&amp;eacute; d&amp;eacute;tect&amp;eacute;e et que la bonne cat&amp;eacute;gorie est affich&amp;eacute;e pour chaque produit.&lt;/p&gt;

&lt;p&gt;Nous pouvons pousser plus loin cette personnalisation et changer le titre d&amp;#x27;une colonne en passant un titre en premier argument de l&amp;#x27;appel &amp;agrave; &lt;code&gt;column&lt;/code&gt;. Nous allons nous en servir pour modifier le titre de la colonne &lt;code&gt;released_at&lt;/code&gt;.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/admin/products.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;ActiveAdmin.register Product do
  index do
    column :name
    column :category
    column &amp;quot;Release Date&amp;quot;, :released_at
    column :price
  end
end&lt;/pre&gt;

&lt;p&gt;Si nous voulons changer les valeurs d&amp;#x27;une colonne, nous pouvons le faire en passant un bloc &amp;agrave; &lt;code&gt;column&lt;/code&gt;. Le champ &lt;code&gt;price&lt;/code&gt; ne montre pas le symbole de monnaie mais nous pouvons changer cela pour que &amp;ccedil;a soit le cas. La m&amp;eacute;thode &lt;code&gt;column&lt;/code&gt; peut prendre un bloc et, lorsqu&amp;#x27;elle en re&amp;ccedil;oit un, lui passe la ressource courante, dans notre cas un &lt;code&gt;Product&lt;/code&gt;. Ce que le bloc retourne est affich&amp;eacute; comme valeur dans la colonne concern&amp;eacute;e. Nous avons acc&amp;egrave;s aux helpers, nous pouvons donc utiliser &lt;code&gt;number_to_currency&lt;/code&gt; pour afficher le prix correctement.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/admin/products.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;ActiveAdmin.register Product do
  index do
    column :name
    column :category
    column &amp;quot;Release Date&amp;quot;, :released_at
    column :price do |product|
      number_to_currency product.price, :unit =&amp;gt; &amp;quot;&amp;amp;pound;&amp;quot;
    end
  end
end&lt;/pre&gt;

&lt;p&gt;Si nous rechargeons la page, nous allons voir le titre &amp;ldquo;Release Date&amp;rdquo; et chaque prix de produit sera affich&amp;eacute; sous forme de valeur mon&amp;eacute;taire.&lt;/p&gt;

&lt;div class="imageWrapper"&gt;
  &lt;img src="/system/photos/741/original/E284I07.png" width="802" height="474" alt="La colonne des prix affiche maintenant des valeurs mon&amp;eacute;taires."/&gt;
&lt;/div&gt;

&lt;p&gt;Personnaliser la valeur retourn&amp;eacute;e par le champ &lt;code&gt;price&lt;/code&gt; signifie que le champ n&amp;#x27;est plus triable. Il nous manque &amp;eacute;galement les liens de modification et de suppression de chaque produit. Nous allons donc corriger cela. Lorsque nous utilisons un bloc pour personnaliser une valeur, nous devons utiliser l&amp;#x27;option &lt;code&gt;:sortable&lt;/code&gt; pour pr&amp;eacute;ciser &amp;agrave; Active&amp;nbsp;Admin comment trier ce champ. Nous allons donc faire cela et ajouter un appel &amp;agrave; &lt;code&gt;default_actions&lt;/code&gt; pour retrouver les liens d&amp;#x27;&amp;eacute;dition et de suppression.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/admin/products.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;ActiveAdmin.register Product do
  index do
    column :name
    column :category
    column &amp;quot;Release Date&amp;quot;, :released_at
    column :price, :sortable =&amp;gt; :price do |product|
      number_to_currency product.price, :unit =&amp;gt; &amp;quot;&amp;amp;pound;&amp;quot;
    end
    default_actions
  end
end&lt;/pre&gt;

&lt;p&gt;Le champ &lt;code&gt;price&lt;/code&gt; est bien affich&amp;eacute; sous forme mon&amp;eacute;taire mais il serait pr&amp;eacute;f&amp;eacute;rable que la valeur soit &amp;eacute;galement align&amp;eacute;e &amp;agrave; droite. Nous pouvons changer cela dans les CSS mais pour que tout fonctionne, il nous faut un moyen de r&amp;eacute;f&amp;eacute;rencer une colonne en particulier. Active&amp;nbsp;Admin fournit un moyen similaire &amp;agrave; &lt;a href="http://markaby.github.com/"&gt;Markaby&lt;/a&gt; pour g&amp;eacute;n&amp;eacute;rer du HTML. Tout ce que nous avons &amp;agrave; faire, c&amp;#x27;est de passer une option &lt;code&gt;:class&lt;/code&gt; pour donner &amp;agrave; la balise une r&amp;eacute;f&amp;eacute;rence utilisable dans nos CSS.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/admin/products.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;ActiveAdmin.register Product do
  index do
    column :name
    column :category
    column &amp;quot;Release Date&amp;quot;, :released_at
    column :price, :sortable =&amp;gt; :price do |product|
      div :class =&amp;gt; &amp;quot;price&amp;quot; do
        number_to_currency product.price, :unit =&amp;gt; &amp;quot;&amp;amp;pound;&amp;quot;
      end
    end
    default_actions
  end
end&lt;/pre&gt;

&lt;p&gt;Nous pouvons maintenant styliser cette colonne en modifiant le fichier &lt;code&gt;active_admin.css.scss&lt;/code&gt;.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/assets/stylesheets/active_admin.css.scss&lt;/p&gt;
&lt;pre class="css"&gt;// Active Admin CSS Styles
@import &amp;quot;active_admin/mixins&amp;quot;;
@import &amp;quot;active_admin/base&amp;quot;;

// To customize the Active Admin interfaces, add your
// styles here:
.price {
  text-align :right;
}&lt;/pre&gt;

&lt;p&gt;La colonne &lt;code&gt;price&lt;/code&gt; est maintenant align&amp;eacute;e correctement.&lt;/p&gt;

&lt;div class="imageWrapper"&gt;
  &lt;img src="/system/photos/742/original/E284I08.png" width="802" height="472" alt="La colonne des prix est maintenant align&amp;eacute;e &amp;agrave; droite."/&gt;
&lt;/div&gt;

&lt;h3&gt;Les Scopes&lt;/h3&gt;

&lt;p&gt;Les scopes sont une autre fonctionnalit&amp;eacute; int&amp;eacute;ressante d&amp;#x27;Active&amp;nbsp;Admin. Ils agissent comme des filtres pr&amp;eacute;-existants et leur cr&amp;eacute;ation consiste en deux &amp;eacute;tapes. Tout d&amp;#x27;abord, nous ajoutons un appel &amp;agrave; &lt;code&gt;scope&lt;/code&gt;, dans le fichier de configuration Active&amp;nbsp;Admin pour nos produits, en lui passant en param&amp;egrave;tre le nom d&amp;#x27;un scope.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/admin/products.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;ActiveAdmin.register Product do
  scope :unreleased
  index do
    column :name
    column :category
    column &amp;quot;Release Date&amp;quot;, :released_at
    column :price, :sortable =&amp;gt; :price do |product|
      div :class =&amp;gt; &amp;quot;price&amp;quot; do
        number_to_currency product.price, :unit =&amp;gt; &amp;quot;&amp;amp;pound;&amp;quot;
      end
    end
    default_actions
  end
end&lt;/pre&gt;

&lt;p&gt;Nous devons ensuite &amp;eacute;crire ce scope dans le mod&amp;egrave;le &lt;code&gt;Product&lt;/code&gt;.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/models/product.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;class Product &amp;lt; ActiveRecord::Base
  belongs_to :category
  scope :unreleased, where(:released_at =&amp;gt; nil)
end&lt;/pre&gt;

&lt;p&gt;Si nous rechargeons la page des produits, nous voyons le scope list&amp;eacute;. Lorsque nous cliquons sur celui-ci, la liste des produits est filtr&amp;eacute;e &amp;agrave; partir de ce scope.&lt;/p&gt;

&lt;div class="imageWrapper"&gt;
  &lt;img src="/system/photos/743/original/E284I09.png" width="802" height="472" alt="Les produits filtr&amp;eacute;s par le scope unreleased."/&gt;
&lt;/div&gt;

&lt;h3&gt;Personnaliser le Tableau de Bord&lt;/h3&gt;

&lt;p&gt;Nous allons maintenant voir la personnalisation du Tableau de Bord. Il est vide par d&amp;eacute;faut. Nous allons donc le modifier pour faire en sorte qu&amp;#x27;il affiche une liste des produits les plus r&amp;eacute;cents. Cela se fait dans le fichier &lt;code&gt;/app/admin/dashboards.rb&lt;/code&gt;. Les commentaires de ce fichier sont une documentation utile, ils expliquent les diff&amp;eacute;rentes mani&amp;egrave;res de personnaliser le tableau de bord.&lt;/p&gt;

&lt;p&gt;Pour ajouter une section au tableau de bord, nous utilisons la m&amp;eacute;thode &lt;code&gt;section&lt;/code&gt;. Nous voulons lister les produits les plus r&amp;eacute;cents dans un tableau et nous pouvons le faire en utilisant la m&amp;eacute;thode &lt;code&gt;table_for&lt;/code&gt;. Dans son bloc, nous pr&amp;eacute;cisons les colonnes que nous voulons afficher gr&amp;acirc;ce &amp;agrave; &lt;code&gt;column&lt;/code&gt;, comme nous l&amp;#x27;avons fait pour la page des produits.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/admin/dashboards.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;ActiveAdmin::Dashboards.build do
  section &amp;quot;Recent Products&amp;quot; do
    table_for Product.order(&amp;quot;released_at desc&amp;quot;).limit(5) do
      column :name
      column :released_at
    end
    strong { link_to &amp;quot;View All Products&amp;quot;, admin_products_path }
  end
end&lt;/pre&gt;

&lt;p&gt;Lorsque nous rechargeons la page, nous voyons maintenant les cinq derniers produits ainsi qu&amp;#x27;un lien pointant vers la page de tous les produits.&lt;/p&gt;

&lt;div class="imageWrapper"&gt;
  &lt;img src="/system/photos/744/original/E284I10.png" width="802" height="472" alt="Les produits les plus r&amp;eacute;cents pr&amp;eacute;sent&amp;eacute;s dans le tableau de bord."/&gt;
&lt;/div&gt;

&lt;p&gt;La page serait plus pratique si chaque produit de la liste &amp;eacute;tait un lien vers la page d&amp;#x27;administration de ce produit. Nous pouvons faire cela en passant &amp;agrave; nouveau un bloc &amp;agrave; l&amp;#x27;appel de &lt;code&gt;column&lt;/code&gt;, comme nous l&amp;#x27;avons pr&amp;eacute;c&amp;eacute;demment fait pour la colonne &lt;code&gt;price&lt;/code&gt;.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/admin/dashboards.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;ActiveAdmin::Dashboards.build do
  section &amp;quot;Recent Products&amp;quot; do
    table_for Product.order(&amp;quot;released_at desc&amp;quot;).limit(5) do
      column :name do |product|
        link_to product.title, admin_product_path(product)
      end
      column :released_at
    end
    strong { link_to &amp;quot;View All Products&amp;quot;, admin_products_path }
  end
end&lt;/pre&gt;

&lt;p&gt;Il existe un moyen plus court de d&amp;eacute;finir le chemin dans &lt;code&gt;link_to&lt;/code&gt;. Au lieu d&amp;#x27;utiliser &lt;code&gt;admin_product_path(product)&lt;/code&gt;, nous pouvons passer un tableau ayant un symbole comme premi&amp;egrave;re valeur et le produit comme seconde, comme ceci&amp;nbsp;:&lt;/p&gt;

&lt;pre class="ruby"&gt;link_to product.title, [:admin, product]&lt;/pre&gt;

&lt;p&gt;Si nous rechargeons le tableau de bord, nous allons voir que chaque titre de produit est un lien. Lorsque nous cliquons sur l&amp;#x27;un d&amp;#x27;eux, nous somme dirig&amp;eacute;s vers la page d&amp;#x27;administration du produit concern&amp;eacute;.&lt;/p&gt;

&lt;h3&gt;Corriger les CSS&lt;/h3&gt;

&lt;p&gt;Un probl&amp;egrave;me existe lorsque nous utilisons Active&amp;nbsp;Admin avec Rails&amp;nbsp;3.1. Nous pouvons le voir en allant sur une page de notre application autre que l&amp;#x27;administration.&lt;/p&gt;

 &lt;div class="imageWrapper"&gt;
  &lt;img src="/system/photos/745/original/E284I11.png" width="801" height="435" alt="La page d'accueil a un style incorrect."/&gt;
&lt;/div&gt;

&lt;p&gt;La page ne ressemble plus vraiment &amp;agrave; ce qu&amp;#x27;elle &amp;eacute;tait avant car les CSS d&amp;#x27;Active&amp;nbsp;Admin sont incluses sur toutes les pages. Par d&amp;eacute;faut, Rails&amp;nbsp;3.1 inclut toutes les CSS en raison de la ligne &lt;code&gt;require_tree .&lt;/code&gt; dans le manifest &lt;code&gt;application.css&lt;/code&gt;. Ce n&amp;#x27;est pas ce que nous voulons et il est de toute mani&amp;egrave;re de bon ton de supprimer cette ligne pour nous donner plus de contr&amp;ocirc;le sur les CSS de notre application. Nous n&amp;#x27;avons qu&amp;#x27;une seule autre CSS dans l&amp;#x27;application principale, nous allons donc remplacer &lt;code&gt;require_tree .&lt;/code&gt; par &lt;code&gt;require products&lt;/code&gt;.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/assets/stylesheets/application.css&lt;/p&gt;
&lt;pre class="css"&gt;/*
 * This is a manifest file that&amp;#x27;ll automatically include all the stylesheets available in this directory
 * and any sub-directories. You&amp;#x27;re free to add application-wide styles to this file and they&amp;#x27;ll appear at
 * the top of the compiled file, but it&amp;#x27;s generally better to create a new file per style scope.
 *= require_self
 *= require products
*/

/* Rest of file omitted */&lt;/pre&gt;

&lt;p&gt;Une solution encore meilleure est de passer &amp;agrave; la commande &lt;code&gt;import&lt;/code&gt; de SASS. Nous pouvons transformer le principal fichier CSS de notre application en lui ajoutant une extension &lt;code&gt;.scss&lt;/code&gt;. Nous pouvons ensuite supprimer le manifest au d&amp;eacute;but du fichier (la partie du fichier que vous pouvez voir ci-dessus) et ajouter la commande &lt;code&gt;import&lt;/code&gt; en fin de fichier.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/assets/stylesheets/application.css.scss&lt;/p&gt;
&lt;pre class="css"&gt;/* Styles omitted */

@import &amp;quot;products&amp;quot;;&lt;/pre&gt;

&lt;p&gt;Lorsque nous rechargeons la page d&amp;#x27;accueil, seules les CSS ad&amp;eacute;quates sont incluses et la page a un rendu correct.&lt;/p&gt;

&lt;h3&gt;Configuration Globale&lt;/h3&gt;

&lt;p&gt;Active&amp;nbsp;Admin a un autre fichier de configuration dans le dossier &lt;code&gt;/config/initializers&lt;/code&gt; et nous terminerons cet &amp;eacute;pisode par un coup d&amp;#x27;&amp;oelig;il sur celui-ci. Le fichier contient un grand nombre d&amp;#x27;options de configuration, la plupart &amp;eacute;tant comment&amp;eacute;e. Une qui ne l&amp;#x27;est pas est le titre de l&amp;#x27;interface d&amp;#x27;administration et nous allons le changer.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/config/initializers/active_admin.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;ActiveAdmin.setup do |config|

  # == Site Title
  #
  # Set the title that is displayed on the main layout
  # for each of the active admin pages.
  #
  config.site_title = &amp;quot;Eifion&amp;#x27;s Store&amp;quot;

  # Other configuration options omitted.
end&lt;/pre&gt;

&lt;p&gt;Nous devons red&amp;eacute;marrer le serveur pour voir le changement pris en compte.&lt;/p&gt;

&lt;div class="imageWrapper"&gt;
  &lt;img src="/system/photos/746/original/E284I12.png" width="801" height="435" alt="Le nouveau titre est affich&amp;eacute;."/&gt;
&lt;/div&gt;

&lt;p&gt;C&amp;#x27;est tout pour cet &amp;eacute;pisode. Active&amp;nbsp;Admin regorge de fonctionnalit&amp;eacute;s que nous n&amp;#x27;avons pas vues ici, nous vous encourageons donc &amp;agrave; consulter la documentation pour voir tout ce dont elle est capable. Nous pouvons personnaliser le rendu et les fonctionnalit&amp;eacute;s de chaque page d&amp;#x27;administration pour les adapter &amp;agrave; nos besoins et cela en fait une puissante solution d&amp;#x27;administration pour Rails.&lt;/p&gt;
</description>
      <pubDate>Mon, 24 Oct 2011 08:21:47 +0000</pubDate>
      <guid>http://fr.asciicasts.com/episodes/284-active-admin</guid>
      <link>http://fr.asciicasts.com/episodes/284-active-admin</link>
    </item>
    <item>
      <title>Authentification avec Sorcery</title>
      <description>&lt;p&gt;Dans l&amp;#x27;&amp;eacute;pisode 250 [&lt;a href="http://railscasts.com/episodes/250-authentication-from-scratch"&gt;regarder&lt;/a&gt;, &lt;a href="http://fr.asciicasts.com/episodes/250-authentication-from-scratch"&gt;lire&lt;/a&gt;], nous avons ajout&amp;eacute;, from scratch, un m&amp;eacute;canisme d&amp;#x27;authentification dans une application Rails. Si vous pr&amp;eacute;f&amp;eacute;rez utiliser une solution tierce, il existe bon nombre de gems r&amp;eacute;pondant &amp;agrave; ce besoin. Dans cet &amp;eacute;pisode, nous allons jeter un &amp;oelig;il sur celle nomm&amp;eacute;e &lt;a href="https://github.com/NoamB/sorcery"&gt;Sorcery&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Sorcery est une solution simple. Elle ne propose qu&amp;#x27;une vingtaine de m&amp;eacute;thodes mais cela suffit amplement pour r&amp;eacute;pondre &amp;agrave; notre besoin. Malgr&amp;eacute; sa simplicit&amp;eacute;, elle est tr&amp;egrave;s compl&amp;egrave;te et modulaire, nous pouvons donc choisir les parties que nous voulons utiliser, la r&amp;eacute;initialisation de mot de passe, par exemple. Sorcery fonctionne &amp;agrave; un niveau plus bas que les autres solutions d&amp;#x27;authentification et nous laisse le soin d&amp;#x27;&amp;eacute;crire les couches contr&amp;ocirc;leurs et vues. Dans cet &amp;eacute;pisode, nous allons l&amp;#x27;utiliser pour ajouter un m&amp;eacute;canisme d&amp;#x27;authentification &amp;agrave; une application existante.&lt;/p&gt;

&lt;h3&gt;D&amp;eacute;marrer&lt;/h3&gt;

&lt;p&gt;L&amp;#x27;application avec laquelle nous allons travailler est tr&amp;egrave;s simple. Elle a une page d&amp;#x27;accueil contenant un lien vers une page &amp;ldquo;secr&amp;egrave;te&amp;rdquo;. La page secr&amp;egrave;te est, pour le moment, visible par tout le monde. Nous voulons en restreindre l&amp;#x27;acc&amp;egrave;s aux utilisateurs connect&amp;eacute;s. Pour ce faire, nous devons ajouter une couche d&amp;#x27;authentification &amp;agrave; l&amp;#x27;application et c&amp;#x27;est la que Sorcery entre en jeu.&lt;/p&gt;

&lt;div class="imageWrapper"&gt;
  &lt;img src="/system/photos/730/original/E283I01.png" width="804" height="366" alt="Notre application."/&gt;
&lt;/div&gt;

&lt;p&gt;Sorcery est fournie sous forme de gem et s&amp;#x27;installe de fa&amp;ccedil;on classique, &lt;code&gt;Gemfile&lt;/code&gt; et &lt;code&gt;bundle&lt;/code&gt;.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/Gemfile&lt;/p&gt;
&lt;pre class="ruby"&gt;gem &amp;#x27;sorcery&amp;#x27;&lt;/pre&gt;

&lt;p&gt;Une fois cela fait, nous devons lancer la commande suivante pour cr&amp;eacute;er l&amp;#x27;initializer de Sorcery (nous reviendrons dessus plus loin).&lt;/p&gt;

&lt;pre class="ruby"&gt;$ rake sorcery:bootstrap&lt;/pre&gt;

&lt;p&gt;Nous allons ensuite g&amp;eacute;n&amp;eacute;rer une migration &lt;code&gt;sorcery_migration&lt;/code&gt;. Elle va nous servir &amp;agrave; choisir les modules de Sorcery que nous voulons inclure. Nous allons ajouter le module &lt;code&gt;core&lt;/code&gt;, qui permet une authentification par mot de passe, et le module &lt;code&gt;remember_me&lt;/code&gt;. Pour une liste compl&amp;egrave;te des modules, consultez le &lt;a href="https://github.com/NoamB/sorcery/blob/master/README.rdoc"&gt;README&lt;/a&gt; de Sorcery.&lt;/p&gt;

&lt;pre class="terminal"&gt;$ rails g sorcery_migration core remember_me
      create  db/migrate/20110914221626_sorcery_core.rb
      create  db/migrate/20110914221627_sorcery_remember_me.rb&lt;/pre&gt;

&lt;p&gt;La commande cr&amp;eacute;e un certain nombre de fichiers de migration en fonction des modules choisis. Si nous regardons la migration &lt;code&gt;sorcery_core&lt;/code&gt;, nous allons voir les attributs ajout&amp;eacute;s &amp;agrave; la table &lt;code&gt;users&lt;/code&gt;.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/db/migrate/20110914221626_sorcery_core.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;class SorceryCore &amp;lt; ActiveRecord::Migration
  def self.up
    create_table :users do |t|
      t.string :username,         :null =&amp;gt; false  
      t.string :email,            :default =&amp;gt; nil 
      t.string :crypted_password, :default =&amp;gt; nil
      t.string :salt,             :default =&amp;gt; nil
      t.timestamps
    end
  end

  def self.down
    drop_table :users
  end
end&lt;/pre&gt;

&lt;p&gt;Par d&amp;eacute;faut, la migration cr&amp;eacute;e un champ &lt;code&gt;username&lt;/code&gt;. Nous n&amp;#x27;en avons pas besoin, nous allons donc commenter cette ligne.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/db/migrate/20110914221626_sorcery_core.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;class SorceryCore &amp;lt; ActiveRecord::Migration
  def self.up
    create_table :users do |t|
      # t.string :username,         :null =&amp;gt; false
      t.string :email,            :default =&amp;gt; nil
      t.string :crypted_password, :default =&amp;gt; nil
      t.string :salt,             :default =&amp;gt; nil
      t.timestamps
    end
  end
end&lt;/pre&gt;

&lt;p&gt;Nous allons &amp;eacute;galement devoir configurer Sorcery pour qu&amp;#x27;il utilise le champs &lt;code&gt;email&lt;/code&gt; plut&amp;ocirc;t que le champ &lt;code&gt;username&lt;/code&gt;. Cela se fait en modifiant l&amp;#x27;initializer de Sorcery. Au d&amp;eacute;but de ce fichier, nous devons sp&amp;eacute;cifier les modules que nous voulons activer. En dehors du module &lt;code&gt;core&lt;/code&gt;, nous n&amp;#x27;utilisons que le module &lt;code&gt;remember_me&lt;/code&gt;, c&amp;#x27;est donc le seul que nous devons ajouter.&lt;/p&gt;

&lt;pre class="codeFilePath"&gt;/config/initializers/sorcery.rb&lt;/pre&gt;
&lt;pre class="ruby"&gt;# The first thing you need to configure is which modules you need in your app.
# The default is nothing which will include only core features (password encryption, login/logout).
# Available submodules are: :user_activation, :http_basic_auth, :remember_me, 
# :reset_password, :session_timeout, :brute_force_protection, :activity_logging, :external
Rails.application.config.sorcery.submodules = [:remember_me]

# Rest of file omitted.&lt;/pre&gt;

&lt;p&gt;Il y a d&amp;#x27;autres options de configuration que nous pouvons utiliser. Elles sont toutes document&amp;eacute;es dans le fichier. Nous n&amp;#x27;avons pas besoin de modifier la plupart d&amp;#x27;entre elles. La seule que nous devons changer est &lt;code&gt;username_attribute_name&lt;/code&gt;. Nous allons lui donner comme valeur &lt;code&gt;:email&lt;/code&gt; afin de sp&amp;eacute;cifier que c&amp;#x27;est ce champ qui sera utilis&amp;eacute; pour identifier les utilisateurs.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/config/initializers/sorcery.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;config.user_config do |user|
  # -- core --
  user.username_attribute_name = :email
  # change default username
  # attribute, for example,
  # to use :email as the login.

  # Other options omitted.
end
# This line must come after the &amp;#x27;user config&amp;#x27; block.
config.user_class = &amp;quot;User&amp;quot;
# define which model authenticates
# with sorcery.
end&lt;/pre&gt;

&lt;p&gt;&amp;Agrave; la fin du fichier, on peut trouver un &amp;eacute;l&amp;eacute;ment de configuration qui permet de sp&amp;eacute;cifier le nom du mod&amp;egrave;le utilis&amp;eacute; par Sorcery pour l&amp;#x27;authentification (&lt;code&gt;User&lt;/code&gt; par d&amp;eacute;faut). Notre application n&amp;#x27;a pas encore de mod&amp;egrave;le &lt;code&gt;User&lt;/code&gt;, nous allons donc le cr&amp;eacute;er. Nous avons d&amp;eacute;j&amp;agrave; un fichier de migration pour sp&amp;eacute;cifier les champs de &lt;code&gt;User&lt;/code&gt;, nous allons donc dire &amp;agrave; Rails de ne pas g&amp;eacute;n&amp;eacute;rer de migration pour ce mod&amp;egrave;le.&lt;/p&gt;

&lt;pre class="terminal"&gt;$ rails g model user --skip-migration&lt;/pre&gt;

&lt;p&gt;Pour activer Sorcery dans le mod&amp;egrave;le &lt;code&gt;User&lt;/code&gt;, nous avons juste une ligne de code &amp;agrave; ajouter.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/models/user.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;class User &amp;lt; ActiveRecord::Base
  authenticates_with_sorcery!
end&lt;/pre&gt;

&lt;p&gt;Cela ajoute au mod&amp;egrave;le &lt;code&gt;User&lt;/code&gt; un certain nombre de m&amp;eacute;thodes pour g&amp;eacute;rer l&amp;#x27;authentification. Les attributs ne sont, cependant, ni valid&amp;eacute;s ni prot&amp;eacute;g&amp;eacute;s&amp;nbsp;; c&amp;#x27;est &amp;agrave; nous d&amp;#x27;&amp;eacute;crire ce code.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/models/user.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;class User &amp;lt; ActiveRecord::Base
  authenticates_with_sorcery!

  attr_accessible :email, :password, :password_confirmation

  validates_confirmation_of :password
  validates_presence_of :password, :on =&amp;gt; :create
  validates_presence_of :email
  validates_uniqueness_of :email
end&lt;/pre&gt;

&lt;p&gt;Il est maintenant temps de lancer les migrations pour que la table &lt;code&gt;users&lt;/code&gt; soit cr&amp;eacute;e.&lt;/p&gt;

&lt;pre class="terminal"&gt;$ rake db:migrate&lt;/pre&gt;

&lt;h3&gt;Ajouter les Contr&amp;ocirc;leurs et les Vues&lt;/h3&gt;

&lt;p&gt;Maintenant que nous avons le mod&amp;egrave;le &lt;code&gt;User&lt;/code&gt;, nous allons g&amp;eacute;n&amp;eacute;rer quelques contr&amp;ocirc;leurs pour l&amp;#x27;accompagner. Nous allons commencer par &lt;code&gt;UsersController&lt;/code&gt; pour g&amp;eacute;rer le processus d&amp;#x27;inscription.&lt;/p&gt;

&lt;pre class="terminal"&gt;$ rails g controller users new&lt;/pre&gt;

&lt;p&gt;Nous allons &amp;eacute;galement avoir besoin de &lt;code&gt;SessionsController&lt;/code&gt; pour g&amp;eacute;rer les connexions.&lt;/p&gt;

&lt;pre class="terminal"&gt;$ rails g controller sessions new&lt;/pre&gt;

&lt;p&gt;Cela ressemble beaucoup &amp;agrave; ce que nous avons fait dans l&amp;#x27;&amp;eacute;pisode 250, sur l&amp;#x27;authentification from scratch, nous allons donc passer rapidement sur ce sujet. &lt;code&gt;UsersController&lt;/code&gt; va &amp;ecirc;tre relativement standard, construire un nouvel utilisateur dans l&amp;#x27;action &lt;code&gt;new&lt;/code&gt; et en cr&amp;eacute;er un bas&amp;eacute; sur les informations fournies dans l&amp;#x27;action &lt;code&gt;create&lt;/code&gt;.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/controllers/users_controller.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;class UsersController &amp;lt; ApplicationController
  def new
    @user = User.new
  end
  
  def create
    @user = User.new(params[:user])
    if @user.save
      redirect_to root_url, :notice =&amp;gt; &amp;quot;Signed up!&amp;quot;
    else
      render :new
    end
  end
end&lt;/pre&gt;

&lt;p&gt;Le template &lt;code&gt;new&lt;/code&gt; va &amp;ecirc;tre assez standard &amp;eacute;galement, un formulaire permettant de cr&amp;eacute;er un nouvel utilisateur avec les champs &lt;code&gt;email&lt;/code&gt;, &lt;code&gt;password&lt;/code&gt; et &lt;code&gt;password_confirmation&lt;/code&gt; ainsi qu&amp;#x27;un peu de code pour afficher les erreurs de validation.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/views/users/new.html.erb&lt;/p&gt;
&lt;pre class="ruby"&gt;&amp;lt;h1&amp;gt;Sign Up&amp;lt;/h1&amp;gt;

&amp;lt;%= form_for @user do |f| %&amp;gt;
  &amp;lt;% if @user.errors.any? %&amp;gt;
    &amp;lt;div class=&amp;quot;error_messages&amp;quot;&amp;gt;
      &amp;lt;h2&amp;gt;Form is invalid&amp;lt;/h2&amp;gt;
      &amp;lt;ul&amp;gt;
        &amp;lt;% for message in @user.errors.full_messages %&amp;gt;
          &amp;lt;li&amp;gt;&amp;lt;%= message %&amp;gt;&amp;lt;/li&amp;gt;
        &amp;lt;% end %&amp;gt;
      &amp;lt;/ul&amp;gt;
    &amp;lt;/div&amp;gt;
  &amp;lt;% end %&amp;gt;
  &amp;lt;div class=&amp;quot;field&amp;quot;&amp;gt;
    &amp;lt;%= f.label :email %&amp;gt;
    &amp;lt;%= f.text_field :email %&amp;gt;
  &amp;lt;/div&amp;gt;
  &amp;lt;div class=&amp;quot;field&amp;quot;&amp;gt;
    &amp;lt;%= f.label :password %&amp;gt;
    &amp;lt;%= f.password_field :password %&amp;gt;
  &amp;lt;/div&amp;gt;
  &amp;lt;div class=&amp;quot;field&amp;quot;&amp;gt;
    &amp;lt;%= f.label :password_confirmation %&amp;gt;
    &amp;lt;%= f.password_field :password_confirmation %&amp;gt;
  &amp;lt;/div&amp;gt;
  &amp;lt;div class=&amp;quot;actions&amp;quot;&amp;gt;&amp;lt;%= f.submit %&amp;gt;&amp;lt;/div&amp;gt;
&amp;lt;% end %&amp;gt;&lt;/pre&gt;

&lt;p&gt;&lt;code&gt;SessionsController&lt;/code&gt; est bien plus int&amp;eacute;ressant. Nous avons une action &lt;code&gt;new&lt;/code&gt; mais celle-ci ne n&amp;eacute;cessite aucun code, nous allons donc voir son template. Ici, nous allons avoir besoin d&amp;#x27;un simple formulaire de connexion avec des champs texte pour &lt;code&gt;email&lt;/code&gt; et &lt;code&gt;password&lt;/code&gt;, et une checkbox pour le champ &lt;code&gt;remember_me&lt;/code&gt;.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/views/sessions/new.html.erb&lt;/p&gt;
&lt;pre class="ruby"&gt;&amp;lt;h1&amp;gt;Log in&amp;lt;/h1&amp;gt;

&amp;lt;%= form_tag sessions_path do %&amp;gt;
  &amp;lt;div class=&amp;quot;field&amp;quot;&amp;gt;
    &amp;lt;%= label_tag :email %&amp;gt;
    &amp;lt;%= text_field_tag :email, params[:email] %&amp;gt;
  &amp;lt;/div&amp;gt;
  &amp;lt;div class=&amp;quot;field&amp;quot;&amp;gt;
    &amp;lt;%= label_tag :password %&amp;gt;
    &amp;lt;%= password_field_tag :password %&amp;gt;
  &amp;lt;/div&amp;gt;
  &amp;lt;div class=&amp;quot;field&amp;quot;&amp;gt;
    &amp;lt;%= check_box_tag :remember_me, 1, params[:remember_me] %&amp;gt;
    &amp;lt;%= label_tag :remember_me %&amp;gt;
  &amp;lt;/div&amp;gt;
  &amp;lt;div class=&amp;quot;actions&amp;quot;&amp;gt;&amp;lt;%= submit_tag &amp;quot;Log in&amp;quot; %&amp;gt;&amp;lt;/div&amp;gt;
&amp;lt;% end %&amp;gt;&lt;/pre&gt;

&lt;p&gt;Nous devons &amp;eacute;crire une action &lt;code&gt;create&lt;/code&gt; pour g&amp;eacute;rer le formulaire de connexion. Sorcery fournit une m&amp;eacute;thode appel&amp;eacute;e &lt;code&gt;login&lt;/code&gt; qui peut prendre trois param&amp;egrave;tres, un nom d&amp;#x27;utilisateur ou une adresse email, un mot de passe et la valeur du champ &lt;code&gt;remember_me&lt;/code&gt;. Cette m&amp;eacute;thode va effectuer l&amp;#x27;authentification et retourner un &lt;code&gt;User&lt;/code&gt; en cas de succ&amp;egrave;s. Nous pouvons donc v&amp;eacute;rifier son retour et rediriger vers la page d&amp;#x27;accueil si un utilisateur est trouv&amp;eacute;. Dans le cas contraire, nous allons afficher un message flash et afficher de nouveau le formulaire de connexion.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/views/controllers/sessions_controller.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;class SessionsController &amp;lt; ApplicationController
  def new
  end
  
  def create
    user = login(params[:email], params[:password], &amp;crarr;
      params[:remember_me])
    if user
      redirect_back_or_to root_url, :notice =&amp;gt; &amp;quot;Logged in!&amp;quot;
    else
      flash.now.alert = &amp;quot;Email or password was invalid.&amp;quot;
    end
  end
end&lt;/pre&gt;

&lt;p&gt;Au lieu d&amp;#x27;utiliser &lt;code&gt;redirect_to&lt;/code&gt; pour rediriger sur la page d&amp;#x27;accueil lorsqu&amp;#x27;un utilisateur est trouv&amp;eacute;, nous allons utiliser une m&amp;eacute;thode fournie par Sorcery et appel&amp;eacute;e &lt;code&gt;redirect_back_or_to&lt;/code&gt;. Son comportement est similaire &amp;agrave; &lt;code&gt;redirect_to&lt;/code&gt; mais si une URL est stock&amp;eacute;e par Sorcery, la redirection se fera vers cette URL plut&amp;ocirc;t que vers celle sp&amp;eacute;cifi&amp;eacute;e dans le code. Ce fonctionnement est bien pratique car cela signifie que si un utilisateur tente d&amp;#x27;acc&amp;eacute;der &amp;agrave; une certaine page et qu&amp;#x27;il est redirig&amp;eacute; vers le formulaire de connexion, il sera redirig&amp;eacute; vers cette page un fois connect&amp;eacute;.&lt;/p&gt;

&lt;p&gt;Il nous reste encore &amp;agrave; fournir un moyen de se d&amp;eacute;connecter. Nous allons donc ajouter une action &lt;code&gt;destroy&lt;/code&gt; au contr&amp;ocirc;leur. Sorcery fournit une m&amp;eacute;thode &lt;code&gt;logout&lt;/code&gt; et c&amp;#x27;est tout ce dont nous avons besoin pour d&amp;eacute;connecter un utilisateur. Une fois l&amp;#x27;utilisateur d&amp;eacute;connecter, nous allons le rediriger vers la page d&amp;#x27;accueil.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/views/controllers/sessions_controller.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;def destroy
  logout
  redirect_to root_url, :notice =&amp;gt; &amp;quot;Logged out!&amp;quot;
end&lt;/pre&gt;

&lt;p&gt;Nous allons ensuite aller dans la configuration de nos routes et remplacer les actions g&amp;eacute;n&amp;eacute;r&amp;eacute;es par d&amp;eacute;faut par ceci&amp;nbsp;:&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/config/routes.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;Auth::Application.routes.draw do
  get &amp;quot;logout&amp;quot; =&amp;gt; &amp;quot;sessions#destroy&amp;quot;, :as =&amp;gt; &amp;quot;logout&amp;quot;
  get &amp;quot;login&amp;quot; =&amp;gt; &amp;quot;sessions#new&amp;quot;, :as =&amp;gt; &amp;quot;login&amp;quot;
  get &amp;quot;signup&amp;quot; =&amp;gt; &amp;quot;users#new&amp;quot;, :as =&amp;gt; &amp;quot;signup&amp;quot;
  resources :users
  resources :sessions
  get &amp;quot;secret&amp;quot; =&amp;gt; &amp;quot;home#secret&amp;quot;, :as =&amp;gt; &amp;quot;secret&amp;quot;
  root :to =&amp;gt; &amp;quot;home#index&amp;quot;
end&lt;/pre&gt;

&lt;p&gt;Nous avons &amp;agrave; pr&amp;eacute;sent diff&amp;eacute;rentes routes nomm&amp;eacute;es et deux ressources nous permettant de g&amp;eacute;rer toute la couche authentification.&lt;/p&gt;

&lt;p&gt;Maintenant que nous avons ces nouvelles pages, nous allons avoir besoin de quelques liens pour que les utilisateurs puissent y acc&amp;eacute;der. Nous allons les ajouter au layout afin de les rendre disponibles sur toutes les pages. Nous pouvons utiliser la m&amp;eacute;thode &lt;code&gt;current_user&lt;/code&gt; pour v&amp;eacute;rifier si l&amp;#x27;utilisateur est connect&amp;eacute; ou non. Si c&amp;#x27;est le cas, nous allons afficher son adresse email suivie d&amp;#x27;un lien &amp;ldquo;Log out&amp;rdquo;. Si, au contraire, il n&amp;#x27;est pas connect&amp;eacute;, nous allons afficher les liens d&amp;#x27;inscription et de connexion.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/views/layouts/application.html.erb&lt;/p&gt;
&lt;pre class="ruby"&gt;&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html&amp;gt;
&amp;lt;head&amp;gt;
  &amp;lt;title&amp;gt;Auth Example&amp;lt;/title&amp;gt;
  &amp;lt;%= stylesheet_link_tag    &amp;quot;application&amp;quot; %&amp;gt;
  &amp;lt;%= javascript_include_tag &amp;quot;application&amp;quot; %&amp;gt;
  &amp;lt;%= csrf_meta_tags %&amp;gt;
&amp;lt;/head&amp;gt;
&amp;lt;body class=&amp;quot;&amp;lt;%= params[:controller] %&amp;gt;&amp;quot;&amp;gt;
  &amp;lt;div id=&amp;quot;container&amp;quot;&amp;gt;
    &amp;lt;div class=&amp;quot;user_nav&amp;quot;&amp;gt;
      &amp;lt;% if current_user %&amp;gt;
        Logged in as &amp;lt;%= current_user.email %&amp;gt;.
        &amp;lt;%= link_to &amp;quot;Log out&amp;quot;, logout_path %&amp;gt;
      &amp;lt;% else %&amp;gt;
        &amp;lt;%= link_to &amp;quot;Sign up&amp;quot;, signup_path %&amp;gt; or
        &amp;lt;%= link_to &amp;quot;Log in&amp;quot;, login_path  %&amp;gt;.
      &amp;lt;% end %&amp;gt;
    &amp;lt;/div&amp;gt;
    &amp;lt;% flash.each do |name, msg| %&amp;gt;
      &amp;lt;%= content_tag :div, msg, :id =&amp;gt; &amp;quot;flash_#{name}&amp;quot; %&amp;gt;
    &amp;lt;% end %&amp;gt;
    &amp;lt;%= yield %&amp;gt;
  &amp;lt;/div&amp;gt;
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;&lt;/pre&gt;

&lt;p&gt;Nous sommes pr&amp;ecirc;ts &amp;agrave; tester notre site. Si nous nous rendons sur la page d&amp;#x27;accueil, nous allons maintenant voir les liens &amp;ldquo;Sign up&amp;rdquo; et &amp;ldquo;Log in&amp;rdquo;.&lt;/p&gt;

&lt;div class="imageWrapper"&gt;
  &lt;img src="/system/photos/731/original/E283I02.png" width="798" height="380" alt="Chaque page contient maintenant les liens &amp;ldquo;Sign up&amp;rdquo; et &amp;ldquo;Log in&amp;rdquo;."/&gt;
&lt;/div&gt;

&lt;p&gt;Si nous cliquons sur &amp;ldquo;Sign up&amp;rdquo;, nous allons voir le formulaire d&amp;#x27;inscription et nous pouvons nous inscrire sur le site. Nous pouvons ensuite cliquer sur &amp;ldquo;Log in&amp;rdquo; et nous connecter avec nos identifiants.&lt;/p&gt;
 
&lt;div class="imageWrapper"&gt;
  &lt;img src="/system/photos/732/original/E283I03.png" width="803" height="397" alt="Connexion."/&gt;
&lt;/div&gt;

&lt;h3&gt;Autorisation&lt;/h3&gt;

&lt;p&gt;Maintenant que nous sommes connect&amp;eacute;s sur le site, nous pouvons visiter la page secr&amp;egrave;te. Cependant, si nous nous d&amp;eacute;connectons et tentons de visiter la page, nous pouvons toujours la voir. Nous devons ajouter un m&amp;eacute;canisme d&amp;#x27;autorisation pour restreindre l&amp;#x27;acc&amp;egrave;s &amp;agrave; la page aux utilisateurs connect&amp;eacute;s.&lt;/p&gt;

&lt;p&gt;La page secr&amp;egrave;te est une action du contr&amp;ocirc;leur &lt;code&gt;HomeController&lt;/code&gt;. Nous pouvons utiliser un &lt;code&gt;before_filter&lt;/code&gt; fournit par Sorcery, &lt;code&gt;require_login&lt;/code&gt;, pour limiter l&amp;#x27;acc&amp;egrave;s aux actions. Nous allons l&amp;#x27;utiliser pour prot&amp;eacute;ger la page secr&amp;egrave;te.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/controllers/home_controller.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;class HomeController &amp;lt; ApplicationController
  before_filter :require_login, :only =&amp;gt; :secret

  def index
  end

  def secret
  end
end&lt;/pre&gt;

&lt;p&gt;Lorsque ce filtre est d&amp;eacute;clench&amp;eacute;, Sorcery appelle sa m&amp;eacute;thode &lt;code&gt;not_authenticated&lt;/code&gt;. Nous pouvons surcharger cette m&amp;eacute;thode dans &lt;code&gt;ApplicationController&lt;/code&gt; pour contr&amp;ocirc;ler ce qu&amp;#x27;il se passe lorsque l&amp;#x27;autorisation &amp;eacute;choue. Nous allons rediriger vers la page de connexion et afficher un message d&amp;#x27;alerte.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/controllers/application_controller.rb&lt;/p&gt;
&lt;pre class="rubby"&gt;class ApplicationController &amp;lt; ActionController::Base
  protect_from_forgery
  
  private
  def not_authenticated
    redirect_to login_url, :alert =&amp;gt; &amp;quot;First log in to view &amp;crarr;
    this page.&amp;quot;
  end
  
end&lt;/pre&gt;

&lt;p&gt;Si nous essayons de consulter la page secr&amp;egrave;te sans &amp;ecirc;tre connect&amp;eacute;s, nous allons &amp;ecirc;tre redirig&amp;eacute;s vers la page de connexion et le message d&amp;#x27;alerte sera affich&amp;eacute;.&lt;/p&gt;

&lt;div class="imageWrapper"&gt;
  &lt;img src="/system/photos/733/original/E283I04.png" width="803" height="436" alt="Si nous essayons de voir la page secr&amp;egrave;te sans &amp;ecirc;tre connect&amp;eacute;s, nous sommes redirig&amp;eacute;s."/&gt;
&lt;/div&gt;

&lt;p&gt;Lorsque nous nous connectons, nous sommes redirig&amp;eacute;s vers la page secr&amp;egrave;te, Sorcery se souvenant de la page &amp;agrave; laquelle nous tentions d&amp;#x27;acc&amp;eacute;der avant d&amp;#x27;&amp;ecirc;tre redirig&amp;eacute;s.&lt;/p&gt;

&lt;div class="imageWrapper"&gt;
  &lt;img src="/system/photos/734/original/E283I05.png" width="803" height="436" alt="Une fois connect&amp;eacute;s, nous pouvons voir la page."/&gt;
&lt;/div&gt;

&lt;p&gt;C&amp;#x27;est tout pour cet &amp;eacute;pisode sur Sorcery. De nombreuses fonctionnalit&amp;eacute;s n&amp;#x27;ont pas &amp;eacute;t&amp;eacute; vues ici, pour en savoir plus, rendez-vous dans la &lt;a href="https://github.com/NoamB/sorcery"&gt;documentation&lt;/a&gt;. Si vous cherchez une solution d&amp;#x27;authentification fonctionnant &amp;agrave; un niveau relativement bas, Sorcery vaut la peine d&amp;#x27;y jeter un &amp;oelig;il.&lt;/p&gt;
</description>
      <pubDate>Sun, 16 Oct 2011 22:14:01 +0000</pubDate>
      <guid>http://fr.asciicasts.com/episodes/283-authentification-avec-sorcery</guid>
      <link>http://fr.asciicasts.com/episodes/283-authentification-avec-sorcery</link>
    </item>
    <item>
      <title>Migrer vers Rails 3.1</title>
      <description>&lt;p&gt;Rails&amp;nbsp;3.1 est enfin sorti. On trouve un bon aper&amp;ccedil;u des nouvelles fonctionnalit&amp;eacute;s dans les &lt;a href="http://guides.rubyonrails.org/3_1_release_notes.html"&gt;Release Notes sur le site RailsGuides&lt;/a&gt;. Certaines ont d&amp;eacute;j&amp;agrave; &amp;eacute;t&amp;eacute; abord&amp;eacute;es sur &lt;a href="http://railscasts.com/?tag_id=31"&gt;Railscasts&lt;/a&gt; ainsi que sur &lt;a href="http://asciicasts.com/tags/rails-31"&gt;Asciicasts&lt;/a&gt;. Dans cet &amp;eacute;pisode, nous allons nous concentrer sur la migration de Rails&amp;nbsp;3.0 &amp;agrave; Rails&amp;nbsp;3.1 et nous utiliserons le site Railscasts pour la d&amp;eacute;monstration.&lt;/p&gt;

&lt;h3&gt;Pr&amp;eacute;parer Le Site&lt;/h3&gt;

&lt;p&gt;Avant de passer le site sous Rails&amp;nbsp;3.1, nous allons avoir besoin d&amp;#x27;effectuer quelques op&amp;eacute;rations de pr&amp;eacute;paration. Si le site n&amp;#x27;utilise pas encore la derni&amp;egrave;re version de Rails&amp;nbsp;3.0 (&lt;code&gt;3.0.10&lt;/code&gt; actuellement), nous allons devoir le mettre &amp;agrave; jour. Nous pouvons le faire en changeant la version dans le Gemfile et en lan&amp;ccedil;ant &lt;code&gt;bundle&lt;/code&gt;.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/Gemfile&lt;/p&gt;
&lt;pre class="ruby"&gt;gem &amp;quot;rails&amp;quot;, &amp;quot;3.0.10&amp;quot;&lt;/pre&gt;

&lt;p&gt;Nous allons ensuite lancer la suite de tests de l&amp;#x27;application afin de s&amp;#x27;assurer qu&amp;#x27;elle passe toujours et que nous n&amp;#x27;avons pas d&amp;#x27;erreur de d&amp;eacute;preciation. Si nous en rencontrons, nous devons les corriger avant de continuer. Le code de Railscasts passe, nous pouvons donc passer &amp;agrave; la migration.&lt;/p&gt;

&lt;h3&gt;Migration&lt;/h3&gt;

&lt;p&gt;Nous sommes maintenant pr&amp;ecirc;ts &amp;agrave; migrer le site. Nous allons le faire dans un nouvelle branche Git que nous appellerons &lt;code&gt;rails31&lt;/code&gt;.&lt;/p&gt;

&lt;pre class="terminal"&gt;$ git checkout -b rails31&lt;/pre&gt;

&lt;p&gt;Migrer vers Rails&amp;nbsp;3.1 est plut&amp;ocirc;t simple. Nous avons juste besoin d&amp;#x27;aller dans le Gemfile de notre application et de changer &amp;agrave; nouveau la version de Rails pour mettre le num&amp;eacute;ro de la derni&amp;egrave;re (actuellement &lt;code&gt;3.1.0&lt;/code&gt;).&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/Gemfile&lt;/p&gt;
&lt;pre class="ruby"&gt;gem &amp;quot;rails&amp;quot;, &amp;quot;3.1.0&amp;quot;&lt;/pre&gt;

&lt;p&gt;Nous pouvons maintenant lancer &lt;code&gt;bundle update&lt;/code&gt; pour installer la nouvelle version. Le seul autre changement que nous devons op&amp;eacute;rer a lieu dans le fichier de configuration &lt;code&gt;development.rb&lt;/code&gt;. Nous devons supprimer ou commenter la ligne suivante.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/config/development.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;# config.action_view.debug_rjs = true&lt;/pre&gt;

&lt;p&gt;Si nous lan&amp;ccedil;ons nos tests &amp;agrave; nouveau, nous allons voir qu&amp;#x27;ils passent toujours. Nous pouvons m&amp;ecirc;me d&amp;eacute;marrer le serveur Rails et tester dans notre navigateur.&lt;/p&gt;

&lt;div class="imageWrapper"&gt;
  &lt;img src="/system/photos/728/original/E282I01.png" width="802" height="567" alt="Le site fonctionne avec Rails 3.1."/&gt;
&lt;/div&gt;

&lt;h3&gt;Modifier notre application pour qu&amp;#x27;elle utilise l&amp;#x27;Asset Pipeline&lt;/h3&gt;

&lt;p&gt;L&amp;#x27;asset pipeline est une des plus importantes fonctionnalit&amp;eacute;s de Rails&amp;nbsp;3.1. Toutefois, les images, CSS et JavaScripts de notre application se situent toujours dans le dossier &lt;code&gt;/public&lt;/code&gt; de notre application, nous n&amp;#x27;en tirons donc pas avantage. L&amp;#x27;asset pipeline est totalement optionnel et n&amp;#x27;est pas actif tant que nous ne le demandons pas. De cette mani&amp;egrave;re, si nous ne sommes pas s&amp;ucirc;rs de vouloir l&amp;#x27;utiliser, cela ne nous emp&amp;ecirc;che pas de migrer vers Rails&amp;nbsp;3.1. &amp;Eacute;tant donn&amp;eacute; la facilit&amp;eacute; de migration, il y a tr&amp;egrave;s peu de raisons de ne pas sauter le pas.&lt;/p&gt;

&lt;p&gt;Si nous voulons utiliser l&amp;#x27;asset pipeline, nous devons l&amp;#x27;activer. Pour ce faire, nous devons ajouter les lignes suivantes &amp;agrave; notre &lt;code&gt;Gemfile&lt;/code&gt; (extraites du &lt;code&gt;Gemfile&lt;/code&gt; g&amp;eacute;n&amp;eacute;r&amp;eacute; par Rails&amp;nbsp;3.1).&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/Gemfile&lt;/p&gt;
&lt;pre class="ruby"&gt;# Gems used only for assets and not required
# in production environments by default.
group :assets do
  gem &amp;#x27;sass-rails&amp;#x27;, &amp;quot; ~&amp;gt; 3.1.0&amp;quot;
  gem &amp;#x27;coffee-rails&amp;#x27;, &amp;quot; ~&amp;gt; 3.1.0&amp;quot;
  gem &amp;#x27;uglifier&amp;#x27;
end

gem &amp;#x27;jquery-rails&amp;#x27;&lt;/pre&gt;

&lt;p&gt;Ce code cr&amp;eacute;e un groupe &lt;code&gt;assets&lt;/code&gt; et y place quelques gems relatives aux assets. On y trouve la gem &lt;code&gt;jquery-rails&lt;/code&gt;, nous pourrons donc utiliser jQuery (si vous pr&amp;eacute;f&amp;eacute;rez Prototype, vous pouvez utiliser la gem &lt;a href="https://github.com/rails/prototype-rails"&gt;&lt;code&gt;prototype-rails&lt;/code&gt; gem&lt;/a&gt;). Nous allons &amp;eacute;galement devoir modifier le fichier &lt;code&gt;/config/application.rb&lt;/code&gt; pour remplacer ce code&amp;nbsp;:&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/config/application.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;# If you have a Gemfile, require the gems listed there, including any gems
# you&amp;#x27;ve limited to :test, :development, or :production.
Bundler.require(:default, Rails.env) if defined?(Bundler)&lt;/pre&gt;

&lt;p&gt;par celui-ci&amp;nbsp;:&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/config/application.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;if defined?(Bundler)
  # If you precompile assets before deploying to production, 
    use this line
  Bundler.require *Rails.groups(:assets =&amp;gt; %w(development test))
  # If you want your assets lazily compiled in production, 
    use this line
  # Bundler.require(:default, :assets, Rails.env)
end&lt;/pre&gt;

&lt;p&gt;Ce code ajoute le groupe &lt;code&gt;assets&lt;/code&gt; aux groupes requis par &lt;code&gt;Bundler&lt;/code&gt;. Nous allons de plus devoir activer l&amp;#x27;asset pipeline dans ce fichier. Cela se fait en ajoutant les lignes suivantes dans la classe &lt;code&gt;Application&lt;/code&gt;&amp;nbsp;:&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/config/application.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;# Enable the asset pipeline
config.assets.enabled = true

# Version of your assets, change this if you want to expire all your assets
config.assets.version = &amp;#x27;1.0&amp;#x27;&lt;/pre&gt;

&lt;p&gt;Ce code active l&amp;#x27;asset pipeline et lui donne un num&amp;eacute;ro de version. Ce num&amp;eacute;ro peut &amp;ecirc;tre chang&amp;eacute; pour expirer les assets.&lt;/p&gt;

&lt;p&gt;Il nous faut &amp;eacute;galement changer la configuration de chaque environnement. Nous allons commencer par &lt;code&gt;development.rb&lt;/code&gt;. Nous avons deux changements &amp;agrave; faire de fa&amp;ccedil;on &amp;agrave; ce que les assets ne soient pas compress&amp;eacute;s et pour activer le debug des assets.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/config/environments/development.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;  # Do not compress assets
  config.assets.compress = false
  
  # Expands the lines which load the assets
  config.assets.debug = true&lt;/pre&gt;
  
&lt;p&gt;Passons &amp;agrave; &lt;code&gt;production.rb&lt;/code&gt;.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/config/environments/production.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;# Compress JavaScript and CSS
config.assets.compress = true
   
# Don&amp;#x27;t fallback to assets pipeline
config.assets.compile = false
   
# Generate digests for assets URLs
config.assets.digest = true&lt;/pre&gt;

  &lt;p&gt;En mode production, nous voulons voir les assets compress&amp;eacute;s mais nous mettons &lt;code&gt;compile&lt;/code&gt; &amp;agrave; &lt;code&gt;false&lt;/code&gt; car nous ne voulons pas que l&amp;#x27;asset pipeline soit appel&amp;eacute; alors que nous allons pr&amp;eacute;compiler les assets. Nous mettons &lt;code&gt;digest&lt;/code&gt; &amp;agrave; &lt;code&gt;true&lt;/code&gt; de fa&amp;ccedil;on &amp;agrave; ce que les URLs des assets aient une &lt;a href="http://guides.rubyonrails.org/asset_pipeline.html#what-is-fingerprinting-and-why-should-i-care"&gt;fingerprint&lt;/a&gt;. Bien s&amp;ucirc;r, nous pouvons configurer tout cela pour l&amp;#x27;adapter aux besoins de notre application en production.&lt;/p&gt;

&lt;p&gt;Enfin, nous allons modifier l&amp;#x27;environnement de test. Ici nous pr&amp;eacute;cisons que les fichiers statiques doivent &amp;ecirc;tre servis et mis en cache. Nous activons &amp;eacute;galement le debug des assets.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/config/environments/test.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;# Configure static asset server for tests with Cache-Control for performance
config.serve_static_assets = true
config.static_cache_control = &amp;quot;public, max-age=3600&amp;quot;

# Allow pass debug_assets=true as a query parameter to load pages with unpackaged assets
config.assets.allow_debugging = true&lt;/pre&gt; 

&lt;p&gt;Si nous utilisons Git pour contr&amp;ocirc;ler les sources de notre application, nous pouvons &amp;eacute;galement modifier le fichier &lt;code&gt;.gitignore&lt;/code&gt; et ajouter le dossier &lt;code&gt;.sass-cache&lt;/code&gt; &amp;agrave; la liste des &amp;eacute;l&amp;eacute;ments ignor&amp;eacute;s. Nous ne voulons pas le cache de SASS dans Git.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/.gitignore&lt;/p&gt;
&lt;pre class="ruby"&gt;.sass-cache/&lt;/pre&gt;

&lt;h3&gt;D&amp;eacute;placer les assets&lt;/h3&gt;

&lt;p&gt;Maintenant que notre asset pipeline est configur&amp;eacute;, il est temps de cr&amp;eacute;er un dossier &lt;code&gt;/app/assets&lt;/code&gt;. Nous pouvons ensuite d&amp;eacute;placer les dossiers &lt;code&gt;images&lt;/code&gt;, &lt;code&gt;javascripts&lt;/code&gt; et &lt;code&gt;stylesheets&lt;/code&gt; de &lt;code&gt;/public&lt;/code&gt; vers &lt;code&gt;/app/assets&lt;/code&gt;.&lt;/p&gt;

&lt;pre class="terminal"&gt;$ mkdir app/assets
$ mv public/images/ app/assets/
$ mv public/javascripts/ app/assets/
$ mv public/stylesheets/ app/assets/&lt;/pre&gt;

&lt;p&gt;Certains fichiers que nous avons d&amp;eacute;plac&amp;eacute;s ne sont plus n&amp;eacute;cessaires, ceux li&amp;eacute;s &amp;agrave; jQuery dans le dossier &lt;code&gt;javascripts&lt;/code&gt; par exemple. Ils sont inclus dans la gem jQuery, nous pouvons donc supprimer les fichiers &lt;code&gt;jquery.js&lt;/code&gt;, &lt;code&gt;jquery.min.js&lt;/code&gt; et &lt;code&gt;rails.js&lt;/code&gt;. Il est maintenant temps de d&amp;eacute;cider de si nous devons placer certains fichiers, comme les plugins jQuery, dans &lt;code&gt;/lib/assets&lt;/code&gt; ou &lt;code&gt;/vendor/assets&lt;/code&gt;, tel que vu dans l&amp;#x27;&amp;eacute;pisode 279 [&lt;a href="http://railscasts.com/episodes/279-understanding-the-asset-pipeline"&gt;regarder&lt;/a&gt;, &lt;a href="http://fr.asciicasts.com/episodes/279-understanding-the-asset-pipeline"&gt;lire&lt;/a&gt;].&lt;/p&gt;

&lt;p&gt;Nous devons ensuite cr&amp;eacute;er les fichiers de manifest. Cette application contient d&amp;eacute;j&amp;agrave; les fichiers &lt;code&gt;application.js&lt;/code&gt; et &lt;code&gt;application.css&lt;/code&gt;, nous n&amp;#x27;avons donc pas besoin de les cr&amp;eacute;er. Nous allons commencer par le fichier CSS. Pour le transformer en manifest, nous devons ajouter, au d&amp;eacute;but de celui-ci, quelques commentaires qui indiqueront &amp;agrave; &lt;a href="https://github.com/sstephenson/sprockets"&gt;Sprockets&lt;/a&gt; quels fichiers inclure (la syntaxe de Sprockets est &amp;eacute;galement vue dans l&amp;#x27;&amp;eacute;pisode 279). Nous allons dire &amp;agrave; Sprockets d&amp;#x27;inclure le reste du fichier ainsi que tout ceux pr&amp;eacute;sents dans le dossier &lt;code&gt;stylesheets&lt;/code&gt; et ses sous dossiers.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/assets/stylesheets/application.css&lt;/p&gt;
&lt;pre class="css"&gt;/*
*= require_self
*= require_tree .
*/

/* rest of file omitted */&lt;/pre&gt;

&lt;p&gt;Nous pouvons faire la m&amp;ecirc;me chose pour le fichier &lt;code&gt;application.js&lt;/code&gt; mais ce sera l&amp;eacute;g&amp;egrave;rement diff&amp;eacute;rent car nous voulons inclure jQuery.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/assets/javascripts/application.js&lt;/p&gt;
&lt;pre class="javascript"&gt;//= require jquery
//= require jquery_ujs
//= require_self
//= require_tree .

/* rest of file omitted */&lt;/pre&gt;

&lt;p&gt;Pour rappel, nous ajoutons &lt;code&gt;require_self&lt;/code&gt; ici car le reste du fichier contient du code et &lt;code&gt;require_tree&lt;/code&gt; pour inclure les fichiers contenus dans le m&amp;ecirc;me dossier.&lt;/p&gt;

&lt;p&gt;Nous allons devoir aller dans le layout de l&amp;#x27;application pour changer les lignes d&amp;#x27;inclusion des fichiers CSS et JavaScript afin qu&amp;#x27;elles r&amp;eacute;f&amp;eacute;rencent uniquement les fichiers n&amp;eacute;cessaires, puisque les autres fichiers sont inclus via les manifests.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/views/layouts/application.html.erb&lt;/p&gt;
&lt;pre class="ruby"&gt;&amp;lt;%= stylesheet_link_tag &amp;quot;application&amp;quot; %&amp;gt;
&amp;lt;%= javascript_include_tag &amp;quot;application&amp;quot;, &amp;quot;http://cdn.sublimevideo.net/js/3s7oes9q.js&amp;quot; %&amp;gt;&lt;/pre&gt;

&lt;p&gt;Les fichiers JavaScript n&amp;eacute;cessaires &amp;agrave; l&amp;#x27;application comprennent un fichier externe qui ne sera pas inclus par l&amp;#x27;asset pipeline. Pour celui-ci, nous avons toujours besoin d&amp;#x27;une inclusion explicite comme ci-dessus.&lt;/p&gt;

&lt;p&gt;Il est maintenant temps de tester notre application dans le navigateur pour nous assurer que toutes nos modifications ont fonctionn&amp;eacute;. Avant cela, nous allons lancer une nouvelle fois &lt;code&gt;bundle&lt;/code&gt; pour installer les gems que nous avons ajout&amp;eacute;es. Cela fait, nous pouvons lancer le serveur.&lt;/p&gt;

&lt;pre class="terminal"&gt;$ rails s&lt;/pre&gt;

&lt;p&gt;En dehors de quelques images cass&amp;eacute;es (le logo en haut de l&amp;#x27;&amp;eacute;cran par exemple), tout semble fonctionner.&lt;/p&gt;

&lt;div class="imageWrapper"&gt;
  &lt;img src="/system/photos/729/original/E282I02.png" width="804" height="381" alt="Le site fonctionne toujours bien que quelques images soient cass&amp;eacute;es."/&gt;
&lt;/div&gt;

&lt;p&gt;Le probl&amp;egrave;me est que les URLs des images ont &amp;eacute;t&amp;eacute; hard-cod&amp;eacute;e dans le fichier de layout.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/views/layouts/application.html.erb&lt;/p&gt;
&lt;pre class="ruby"&gt;&amp;lt;img src=&amp;quot;/images/railscasts_logo.png&amp;quot; width=&amp;quot;423&amp;quot; height=&amp;quot;56&amp;quot; alt=&amp;quot;RailsCasts = Ruby on Rails Screencasts&amp;quot;/&amp;gt;&lt;/pre&gt;
  
&lt;p&gt;Cela ne peut pas fonctionner puisque les images de notre application ne sont plus dans le dossier &lt;code&gt;/public/images&lt;/code&gt;. La solution la plus simple pourrait &amp;ecirc;tre de changer l&amp;#x27;url de l&amp;#x27;image de &lt;code&gt;/images/railscasts_logo.png&lt;/code&gt; &amp;agrave; &lt;code&gt;/assets/railscasts_logo.png&lt;/code&gt; mais bien que cela marche en d&amp;eacute;veloppement, ce ne sera pas le cas en production. Si l&amp;#x27;option &lt;code&gt;assets.digest&lt;/code&gt; est activ&amp;eacute;e, un hash sera ajout&amp;eacute; au nom de fichier, la r&amp;eacute;f&amp;eacute;rence statique vers celui-ci ne fonctionnera plus. Nous devons donc toujours utiliser le helper. Celui-ci va lier l&amp;#x27;image correctement en d&amp;eacute;veloppement comment en production.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/views/layouts/application.html.erb&lt;/p&gt;
&lt;pre class="ruby"&gt;&amp;lt;%= image_tag(&amp;quot;railscasts_logo.png&amp;quot;, :size =&amp;gt; &amp;quot;423x56&amp;quot;, :alt =&amp;gt; &amp;quot;RailsCasts - Ruby on Rails Screencasts&amp;quot;) %&amp;gt;&lt;/pre&gt;

&lt;p&gt;Nous allons devoir chercher, dans notre application, toues les r&amp;eacute;f&amp;eacute;rences statiques et faire en sorte qu&amp;#x27;elles utilisent le helper, comme ci-dessus. Si nous rechargeons la page, l&amp;#x27;image apparait, nous indiquant que notre asset pipeline fonctionne correctement.&lt;/p&gt;

&lt;p&gt;Nous avons termin&amp;eacute; notre migration vers Rails&amp;nbsp;3.1. Il y a d&amp;#x27;autres fonctionnalit&amp;eacute;s dont vous pouvez tirer avantage. Cela vaut la peine de jeter un &amp;oelig;il sur les autres &amp;eacute;pisodes autour de Rails&amp;nbsp;3.1 pour voir ce qui pourra vous &amp;ecirc;tre utile.&lt;/p&gt;
</description>
      <pubDate>Sun, 16 Oct 2011 22:10:38 +0000</pubDate>
      <guid>http://fr.asciicasts.com/episodes/282-migrer-vers-rails-3-1</guid>
      <link>http://fr.asciicasts.com/episodes/282-migrer-vers-rails-3-1</link>
    </item>
    <item>
      <title>Foreman</title>
      <description>&lt;p&gt;Ryan Bates &amp;agrave; demand&amp;eacute; il y a peu, via Twitter, quelle &amp;eacute;tait la meilleure fa&amp;ccedil;on de g&amp;eacute;rer les processus en arri&amp;egrave;re-plan sur lesquels repose une application Rails pendant son d&amp;eacute;veloppement. Plusieurs personnes ont recommand&amp;eacute; &lt;a href="https://github.com/ddollar/foreman"&gt;Foreman&lt;/a&gt;. Nous allons donc vous le pr&amp;eacute;senter dans cet &amp;eacute;pisode.&lt;/p&gt;

&lt;p&gt;Par exemple, pour utiliser l&amp;#x27;application &lt;a href="https://github.com/ryanb/govsgo"&gt;GoVsGo&lt;/a&gt; de Ryan en d&amp;eacute;veloppement, nous devons lancer un certain nombre de processus en arri&amp;egrave;re-plan. On a par exemple besoin de Beanstalkd, processus &lt;code&gt;script/worker&lt;/code&gt; et un serveur Faye. Nous devons lancer chacun d&amp;#x27;eux chaque fois que nous voulons utiliser l&amp;#x27;application. Il serait agr&amp;eacute;able d&amp;#x27;avoir une solution simple permettant de g&amp;eacute;rer tous ces processus et c&amp;#x27;est pour &amp;ccedil;a que Foreman est fait.&lt;/p&gt;

&lt;h3&gt;Installer et Utiliser Foreman&lt;/h3&gt;

&lt;p&gt;Foreman est fournit sous forme de gem et s&amp;#x27;installe de mani&amp;egrave;re classique.&lt;/p&gt;

&lt;pre class="terminal"&gt;$ gem install foreman&lt;/pre&gt;

&lt;p&gt;Foreman trouve la liste des processus &amp;agrave; g&amp;eacute;rer dans un fichier &lt;code&gt;Procfile&lt;/code&gt; &amp;agrave; la racine de l&amp;#x27;application, nous devons donc le cr&amp;eacute;er. Dans ce fichier, nous allons lister les processus que nous voulons voir g&amp;eacute;r&amp;eacute;s par Foreman. Chacun d&amp;#x27;eux est d&amp;eacute;finit par un nom, suivi par le catact&amp;egrave;re deux-points et du processus &amp;agrave; lancer. Notre liste ressemble &amp;agrave; ceci&amp;nbsp;:&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/Procfile&lt;/p&gt;
&lt;pre class="ruby"&gt;beanstalk:  beanstalkd
worker:     ./script/worker
faye:       rackup faye.ru -s thin -E production&lt;/pre&gt;

&lt;p&gt;Une fois notre &lt;code&gt;Procfile&lt;/code&gt; &amp;eacute;crit, nous pouvons v&amp;eacute;rifier sa validit&amp;eacute; en lan&amp;ccedil;ant la commande &lt;code&gt;foreman check&lt;/code&gt;.&lt;/p&gt;

&lt;pre class="terminal"&gt;$ foreman check
valid procfile detected (beanstalk, worker, faye)&lt;/pre&gt;

&lt;p&gt;Si nous utilisons des tabulations au lieu d&amp;#x27;espaces pour s&amp;eacute;parer le nom de la commande, nous allons voir des erreurs de d&amp;eacute;pr&amp;eacute;ciation, nous devons donc garder cela en t&amp;ecirc;te lors de l&amp;#x27;&amp;eacute;criture de notre &lt;code&gt;Procfile&lt;/code&gt;. Si notre fichier est consid&amp;eacute;r&amp;eacute; comme valide, nous pouvons tenter de lancer Foreman avec la commande &lt;code&gt;foreman start&lt;/code&gt;.&lt;/p&gt;

&lt;pre class="terminal"&gt;$ foreman start
20:06:35 beanstalk.1  | started with pid 23140
20:06:35 worker.1     | started with pid 23141
20:06:35 faye.1       | started with pid 23143
20:06:36 faye.1       | &amp;gt;&amp;gt; Thin web server (v1.2.11 codename Bat-Shit Crazy)
20:06:36 faye.1       | &amp;gt;&amp;gt; Maximum connections set to 1024
20:06:36 faye.1       | &amp;gt;&amp;gt; Listening on 0.0.0.0:9292, CTRL+C to stop
20:06:38 worker.1     | [2011-08-29 20:06:38 +0100] Working 1 jobs: [ Game.move ]&lt;/pre&gt;

&lt;p&gt;Lorsque nous le faisons, chaque processus sp&amp;eacute;cifi&amp;eacute; dans notre &lt;code&gt;Procfile&lt;/code&gt; va &amp;ecirc;tre lanc&amp;eacute; et list&amp;eacute;, suivi de ses affichages, dans le terminal. Si nous tapons &lt;code&gt;CTRL+C&lt;/code&gt; dans cette fen&amp;ecirc;tre de terminal, tous les processus sont stopp&amp;eacute;s.&lt;/p&gt;

&lt;p&gt;Foreman a une &lt;a href="http://ddollar.github.com/foreman/"&gt;page de manuel&lt;/a&gt; utile qui documente ses fonctionnalit&amp;eacute;s et les diff&amp;eacute;rentes options que l&amp;#x27;on peut lui passer. Si nous voulons lancer seulement un processus, nous pouvons directement passer son nom en param&amp;egrave;tre.&lt;/p&gt;

&lt;pre class="terminal"&gt;$ foreman start faye
20:35:41 faye.1       | started with pid 23322
20:35:41 faye.1       | &amp;gt;&amp;gt; Thin web server (v1.2.11 codename Bat-Shit Crazy)
20:35:41 faye.1       | &amp;gt;&amp;gt; Maximum connections set to 1024
20:35:41 faye.1       | &amp;gt;&amp;gt; Listening on 0.0.0.0:9292, CTRL+C to stop&lt;/pre&gt;

&lt;p&gt;Si nous voulons d&amp;eacute;marrer plusieurs copies d&amp;#x27;un m&amp;ecirc;me processus, nous pouvons le faire en passant l&amp;#x27;option &lt;code&gt;-c&lt;/code&gt;. Par exemple, nous pouvons lancer 4 processus worker en appelant &lt;code&gt;foreman start -c worker=4&lt;/code&gt;.&lt;/p&gt;

&lt;pre class="terminal"&gt;$ foreman start -c worker=4
20:39:41 beanstalk.1  | started with pid 23366
20:39:41 worker.1     | started with pid 23368
20:39:41 worker.2     | started with pid 23370
20:39:41 worker.3     | started with pid 23372
20:39:41 worker.4     | started with pid 23374
20:39:41 faye.1       | started with pid 23376
20:39:42 faye.1       | &amp;gt;&amp;gt; Thin web server (v1.2.11 codename Bat-Shit Crazy)
20:39:42 faye.1       | &amp;gt;&amp;gt; Maximum connections set to 1024
20:39:42 faye.1       | &amp;gt;&amp;gt; Listening on 0.0.0.0:9292, CTRL+C to stop
20:39:46 worker.3     | [2011-08-29 20:39:46 +0100] Working 1 jobs: [ Game.move ]
20:39:46 worker.1     | [2011-08-29 20:39:46 +0100] Working 1 jobs: [ Game.move ]
20:39:46 worker.2     | [2011-08-29 20:39:46 +0100] Working 1 jobs: [ Game.move ]
20:39:47 worker.4     | [2011-08-29 20:39:47 +0100] Working 1 jobs: [ Game.move ]&lt;/pre&gt;

&lt;p&gt;Cela va lancer chaque processus une fois, sauf worker qui sera lanc&amp;eacute; quatre fois.&lt;/p&gt;

&lt;h3&gt;Exporter les Processus&lt;/h3&gt;

&lt;p&gt;Forman fournit une commande &lt;code&gt;export&lt;/code&gt; qui permet d&amp;#x27;exporter la liste des processus dans un format utilisable sur un serveur de production. Les formats support&amp;eacute;s sont pour l&amp;#x27;instant &lt;code&gt;inittab&lt;/code&gt; et &lt;code&gt;upstart&lt;/code&gt;. Si nous lan&amp;ccedil;ons la commande &lt;code&gt;foreman export upstart .&lt;/code&gt;, Forman va &amp;eacute;crire un certain nombre de fichiers de configuration upstart dans le dossier courant. Si nous regardons l&amp;#x27;un d&amp;#x27;eux de plus pr&amp;egrave;s, nous allons voir qu&amp;#x27;il va lancer une commande pour d&amp;eacute;marrer &lt;code&gt;beanstalkd&lt;/code&gt; et g&amp;eacute;rer les logs.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/govsgo-beanstalk-1.conf&lt;/p&gt;
&lt;pre class="terminal"&gt;start on starting govsgo-beanstalk
stop on stopping govsgo-beanstalk
respawn

exec su - govsgo -c &amp;#x27;cd /Users/eifion/govsgo; export PORT=5000; beanstalkd &amp;gt;&amp;gt; /var/log/govsgo/beanstalk-1.log 2&amp;gt;&amp;amp;1&amp;#x27;&lt;/pre&gt;

&lt;p&gt;C&amp;#x27;est tout pour cet &amp;eacute;pisode sur Foreman. Il est plus court que d&amp;#x27;habitude mais Foreman est une solution simple r&amp;eacute;pondant parfaitement &amp;agrave; un probl&amp;egrave;me sp&amp;eacute;cifique. Si vous avez besoin de lancer un certain nombre de processus pour faire fonctionner votre application Rails en d&amp;eacute;veloppement, Foreman vaut la peine d&amp;#x27;&amp;ecirc;tre consid&amp;eacute;r&amp;eacute;.&lt;/p&gt;
</description>
      <pubDate>Sun, 16 Oct 2011 22:06:47 +0000</pubDate>
      <guid>http://fr.asciicasts.com/episodes/281-foreman</guid>
      <link>http://fr.asciicasts.com/episodes/281-foreman</link>
    </item>
    <item>
      <title>Pry avec Rails</title>
      <description>&lt;p&gt;&lt;a href="http://pry.github.com/"&gt;Pry&lt;/a&gt; est une alternative &amp;agrave; IRB et, comme IRB, il fournit une invite de commande permettant d&amp;#x27;ex&amp;eacute;cuter du code Ruby. Ce qui fait la diff&amp;eacute;rence, c&amp;#x27;est un nombre important de fonctionnalit&amp;eacute;s en plus. Dans cet &amp;eacute;pisode, nous allons vous montrer comment Pry fonctionne et comment l&amp;#x27;int&amp;eacute;grer dans vos applications Rails.&lt;/p&gt;

&lt;p&gt;Pry est fournit sous forme de gem et est facile &amp;agrave; installer. Nous allons &amp;eacute;galement installer la gem &lt;code&gt;pry-doc&lt;/code&gt;, nous reviendrons dessus plus loin.&lt;/p&gt;

&lt;pre class="terminal"&gt;$ gem install pry pry-doc&lt;/pre&gt;

&lt;p&gt;Comme nous utilisons les gemsets RVM, nous allons installer Pry de mani&amp;egrave;re &amp;agrave; ce qu&amp;#x27;il soit accessible globalement, peu importe le gemset utilis&amp;eacute;. Nous pouvons le faire gr&amp;acirc;ce aux deux commandes suivantes.&lt;/p&gt;

&lt;pre class="terminal"&gt;$ rvm gemset use global
$ gem install pry pry-doc&lt;/pre&gt;

&lt;p&gt;Une fois Pry install&amp;eacute;, nous pouvons lancer la commande &lt;code&gt;pry&lt;/code&gt; et ex&amp;eacute;cuter du code Ruby comme nous le ferions avec irb.&lt;/p&gt;

&lt;pre class="terminal"&gt;$ pry
pry(main)&amp;gt; 1 + 2
=&amp;gt; 3&lt;/pre&gt;

&lt;p&gt;Pry est bien plus qu&amp;#x27;un simple calculateur mais, avant d&amp;#x27;aller plus loin, nous allons voir comment le faire fonctionner avec une application Rails. Nous allons utiliser l&amp;#x27;application de blog qui nous a d&amp;eacute;j&amp;agrave; servi dans de pr&amp;eacute;c&amp;eacute;dents &amp;eacute;pisodes.&lt;/p&gt;

&lt;div class="imageWrapper"&gt;
  &lt;img src="/system/photos/727/original/E280I01.png" width="815" height="452" alt="Notre application de blog."/&gt;
&lt;/div&gt;

&lt;p&gt;Si nous lan&amp;ccedil;ons &lt;code&gt;rails c&lt;/code&gt; depuis le dossier de l&amp;#x27;application, IRB va d&amp;eacute;marrer. Pour utiliser Pry &amp;agrave; la place, nous devons juste appeler la commande &lt;code&gt;pry&lt;/code&gt; et lui passer le fichier d&amp;#x27;environnement Rails. Cela fait, nous pouvons acc&amp;eacute;der aux mod&amp;egrave;les de notre application, comme dans la console Rails classique.&lt;/p&gt;

&lt;pre class="terminal"&gt;$ pry -r ./config/environment
pry(main)&amp;gt; Article.count
=&amp;gt; 3&lt;/pre&gt;

&lt;p&gt;Maintenant que Pry est en place, nous pouvons voir certaines de ses fonctionnalit&amp;eacute;s de plus pr&amp;egrave;s. Si nous tapons &lt;code&gt;help&lt;/code&gt;, nous allons obtenir la liste de toutes les commandes &amp;agrave; notre disposition. Les deux que nous allons utiliser le plus souvent sont &lt;code&gt;cd&lt;/code&gt; et &lt;code&gt;ls&lt;/code&gt;, jetons-y un &amp;oelig;il. La commande &lt;code&gt;cd&lt;/code&gt; change le scope courant. Si nous tapons &lt;code&gt;cd Article&lt;/code&gt;, nous allons nous placer dans la classe &lt;code&gt;Article&lt;/code&gt;. Nous pouvons connaitre le scope courant &amp;agrave; tout moment en appelant &lt;code&gt;self&lt;/code&gt;.&lt;/p&gt;

&lt;pre class="terminal"&gt;pry(main)&amp;gt; cd Article
pry(#&amp;lt;Class:0x1022f60e0&amp;gt;):1&amp;gt; self
=&amp;gt; Article(id: integer, name: string, content: text, created_at: datetime, updated_at: datetime, published_at: datetime)&lt;/pre&gt;

&lt;p&gt;Maintenant que nous somme dans la classe Article, nous pouvons appeler n&amp;#x27;importe laquelle de ses m&amp;eacute;thodes, &lt;code&gt;first&lt;/code&gt; par exemple, pour retourner le premier article, comme si nous appelions &lt;code&gt;Article.first&lt;/code&gt;.&lt;/p&gt;

&lt;pre class="terminal"&gt;pry(#&amp;lt;Class:0x1022f60e0&amp;gt;):1&amp;gt; first
=&amp;gt; #&amp;lt;Article id: 1, name: &amp;quot;What is Music&amp;quot;, content: &amp;quot;Music is an art form in which the medium is sound o...&amp;quot;, created_at: &amp;quot;2011-08-24 20:35:29&amp;quot;, updated_at: &amp;quot;2011-08-24 20:37:22&amp;quot;, published_at: &amp;quot;2011-05-13 23:00:00&amp;quot;&amp;gt;&lt;/pre&gt;

&lt;p&gt;Nous pouvons &amp;eacute;galement faire &lt;code&gt;cd&lt;/code&gt; sur un objet. Si nous appelons &lt;code&gt;cd first&lt;/code&gt; en &amp;eacute;tant dans le scope &lt;code&gt;Article&lt;/code&gt;, nous allons changer de scope pour &amp;ecirc;tre dans celui du premier article. Nous pouvons d&amp;egrave;s lors appeler n&amp;#x27;importe quelle m&amp;eacute;thode ou propri&amp;eacute;t&amp;eacute; dessus, &lt;code&gt;name&lt;/code&gt; par exemple.&lt;/p&gt;

&lt;pre class="terminal"&gt;pry(#&amp;lt;Class:0x1022f60e0&amp;gt;):1&amp;gt; cd first
pry(#&amp;lt;Article:0x102300c98&amp;gt;):2&amp;gt; name
=&amp;gt; &amp;quot;What is Music&amp;quot;&lt;/pre&gt;

&lt;p&gt;Nous pouvons m&amp;ecirc;me faire &lt;code&gt;cd&lt;/code&gt; dans le &lt;code&gt;name&lt;/code&gt; de l&amp;#x27;article et appeler des m&amp;eacute;thodes sur cette chaine de caract&amp;egrave;res.&lt;/p&gt;

&lt;pre class="terminal"&gt;pry(#&amp;lt;Article:0x102300c98&amp;gt;):2&amp;gt; cd name
pry(&amp;quot;What is Music&amp;quot;):3&amp;gt; upcase
=&amp;gt; &amp;quot;WHAT IS MUSIC&amp;quot;&lt;/pre&gt;

&lt;p&gt;Pry conserve une trace de nos d&amp;eacute;placements que nous pouvons voir en appelant &lt;code&gt;nesting&lt;/code&gt;.&lt;/p&gt;

&lt;pre class="terminal"&gt;pry(&amp;quot;What is Music&amp;quot;):3&amp;gt; nesting
Nesting status:
--
0. main (Pry top level)
1. #&amp;lt;Class:0x1022f60e0&amp;gt;
2. #&amp;lt;Article:0x102300c98&amp;gt;
3. &amp;quot;What is Music&amp;quot;&lt;/pre&gt;

&lt;p&gt;Cette commande retourne une liste des objets que nous avons travers&amp;eacute;. Si nous tapons &lt;code&gt;exit&lt;/code&gt;, nous allons remonter dans l&amp;#x27;objet pr&amp;eacute;c&amp;eacute;dant, dans notre cas, le premier article. Si nous remontons de nouveau, nous serons de retour dans la classe &lt;code&gt;Article&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;L&amp;#x27;autre commande fr&amp;eacute;quemment utilis&amp;eacute;e est &lt;code&gt;ls&lt;/code&gt;. Cette commande liste les variables et m&amp;eacute;thodes. Par d&amp;eacute;faut, elle va lister celles du scope courant. Si, par exemple, nous sommes dans la classe &lt;code&gt;Article&lt;/code&gt;, nous verrons ses m&amp;eacute;thodes lorsque nous appellerons &lt;code&gt;ls&lt;/code&gt;.&lt;/p&gt;

&lt;pre class="terminal"&gt;pry(#&amp;lt;Class:0x1022f60e0&amp;gt;):1&amp;gt; ls
[:_, :_pry_, :inp, :out, :@_create_callbacks, :@_defined_class_methods, :@_save_callbacks, :@_update_callbacks, :@_validate_callbacks, :@arel_engine, :@arel_table, :@attribute_methods_generated, :@cached_attributes, :@column_names, :@columns, :@columns_hash, :@finder_needs_type_condition, :@generated_attribute_methods, :@inheritable_attributes, :@inheritance_column, :@parent_name, :@quoted_primary_key, :@quoted_table_name, :@relation]&lt;/pre&gt;

&lt;p&gt;Certaines commandes Pry supportent des options et nous pouvons obtenir une liste des options d&amp;#x27;une commande en la lan&amp;ccedil;ant avec l&amp;#x27;option &lt;code&gt;-h&lt;/code&gt;. Si nous lan&amp;ccedil;ons &lt;code&gt;ls -h&lt;/code&gt;, nous verrons la liste des options qu&amp;#x27;elle supporte, y compris &lt;code&gt;-m&lt;/code&gt; qui permet de lister les m&amp;eacute;thodes de classe et &lt;code&gt;-M&lt;/code&gt; qui liste les m&amp;eacute;thodes d&amp;#x27;instance. Nous pouvons &amp;eacute;galement passer en param&amp;egrave;tre un objet ou une classe pour obtenir une liste des m&amp;eacute;thodes de celui-ci plut&amp;ocirc;t que pour le scope courant.&lt;/p&gt;

&lt;p&gt;Une autre commande Pry utile est &lt;code&gt;show-doc&lt;/code&gt;. Disons que nous voulons savoir comment fonctionne la m&amp;eacute;thode &lt;code&gt;in_groups_of&lt;/code&gt; de la classe &lt;code&gt;Array&lt;/code&gt;. Nous pouvons le savoir en lan&amp;ccedil;ant &lt;code&gt;show-doc Array#in_groups_of&lt;/code&gt;.&lt;/p&gt;

&lt;pre class="terminal"&gt;pry(#&amp;lt;Class:0x1022f60e0&amp;gt;):1&amp;gt; show-doc Array#in_groups_of

From: /Users/eifion/.rvm/gems/ruby-1.9.2-p290/gems/activesupport-3.0.10/lib/active_support/core_ext/array/grouping.rb @ line 19:
Number of lines: 15

signature: in_groups_of(number, fill_with=?)

Splits or iterates over the array in groups of size number,
padding any remaining slots with fill_with unless it is false.

  %w(1 2 3 4 5 6 7).in_groups_of(3) {|group| p group}
  [&amp;quot;1&amp;quot;, &amp;quot;2&amp;quot;, &amp;quot;3&amp;quot;]
  [&amp;quot;4&amp;quot;, &amp;quot;5&amp;quot;, &amp;quot;6&amp;quot;]
  [&amp;quot;7&amp;quot;, nil, nil]

  %w(1 2 3).in_groups_of(2, &amp;#x27;&amp;amp;nbsp;&amp;#x27;) {|group| p group}
  [&amp;quot;1&amp;quot;, &amp;quot;2&amp;quot;]
  [&amp;quot;3&amp;quot;, &amp;quot;&amp;amp;nbsp;&amp;quot;]

  %w(1 2 3).in_groups_of(2, false) {|group| p group}
  [&amp;quot;1&amp;quot;, &amp;quot;2&amp;quot;]
  [&amp;quot;3&amp;quot;]&lt;/pre&gt;

&lt;p&gt;Nous pouvons &amp;eacute;galement appeler &lt;code&gt;show-doc&lt;/code&gt; directement sur un objet. Notre scope courant est celui de la classe &lt;code&gt;Article&lt;/code&gt;, nous pouvons donc appeler &lt;code&gt;all&lt;/code&gt; pour obtenir un tableau des articles. Nous pouvons ensuite lancer &lt;code&gt;show-doc all.in_groups_of&lt;/code&gt; pour voir la m&amp;ecirc;me documentation que ci-dessus.&lt;/p&gt;

&lt;p&gt;Autre commande utile, &lt;code&gt;show-method&lt;/code&gt;. Cette derni&amp;egrave;re nous montre le code source d&amp;#x27;une m&amp;eacute;thode. Nous pouvons l&amp;#x27;utiliser pour voir la source de &lt;code&gt;in_groups_of&lt;/code&gt; (notons que Pry offre l&amp;#x27;auto-compl&amp;eacute;tion des commandes gr&amp;acirc;ce &amp;agrave; la touche TAB). &lt;/p&gt;

&lt;pre class="terminal"&gt;pry(#&amp;lt;Class:0x104e63de0&amp;gt;):1&amp;gt; show-method all.in_groups_of

From: /Users/eifion/.rvm/gems/ruby-1.9.2-p290/gems/activesupport-3.0.10/lib/active_support/core_ext/array/grouping.rb @ line 19:
Number of lines: 19

def in_groups_of(number, fill_with = nil)
  if fill_with == false
    collection = self
  else
    # size % number gives how many extra we have;
    # subtracting from number gives how many to add;
    # modulo number ensures we don&amp;#x27;t add group of just fill.
    padding = (number - size % number) % number
    collection = dup.concat([fill_with] * padding)
  end

  if block_given?
    collection.each_slice(number) { |slice| yield(slice) }
  else
    groups = []
    collection.each_slice(number) { |group| groups &amp;lt;&amp;lt; group }
    groups
  end
end&lt;/pre&gt;

&lt;p&gt;Conjointement, nous trouvons la commande &lt;code&gt;edit-method&lt;/code&gt;. Lorsque nous la lan&amp;ccedil;ons en lui passant une m&amp;eacute;thode en param&amp;egrave;tre, elle va ouvrir le fichier ad&amp;eacute;quat dans un &amp;eacute;diteur de texte et nous placer sur la ligne appropri&amp;eacute;e.&lt;/p&gt;

&lt;p&gt;Nous pouvons &amp;eacute;galement lancer une commande shell en la pr&amp;eacute;fixant d&amp;#x27;un point. Si nous lan&amp;ccedil;ons &lt;code&gt;.ls&lt;/code&gt; dans Pry, la commande shell &lt;code&gt;ls&lt;/code&gt; va &amp;ecirc;tre appel&amp;eacute;e et va lister les fichiers du dossier courant.&lt;/p&gt;

&lt;p&gt;Pry est &amp;eacute;galement tr&amp;egrave;s utile pour le debug. Dans notre mod&amp;egrave;le &lt;code&gt;Article&lt;/code&gt;, nous avons une m&amp;eacute;thode &lt;code&gt;word_count&lt;/code&gt; qui devrait retourner le nombre de mots dans le contenu d&amp;#x27;un article. Il y a un bug dans cette m&amp;eacute;thode car elle retourne toujours &lt;code&gt;0&lt;/code&gt;, quelque soit le contenu de l&amp;#x27;article. Nous pouvons voir la m&amp;eacute;thode en faisant &lt;code&gt;cd&lt;/code&gt; dans le premier &lt;code&gt;Article&lt;/code&gt; et en lan&amp;ccedil;ant &lt;code&gt;edit-method word_count&lt;/code&gt;. Cette m&amp;eacute;thode ressemble &amp;agrave; ceci&amp;nbsp;:&lt;/p&gt;

&lt;pre class="codeFilePath"&gt;/app/models/article.rb&lt;/pre&gt;
&lt;pre class="ruby"&gt;class Article &amp;lt; ActiveRecord::Base
  attr_accessible :name, :content, :published_at
  has_many :comments

  def word_count
    words = content.scan(/\\w+/)
    words.size
  end
end&lt;/pre&gt;

&lt;p&gt;Nous pouvons ajouter un breakpoint &amp;agrave; n&amp;#x27;importe quel endroit du code en appelant &lt;code&gt;binding.pry&lt;/code&gt;. Si nous le faisons juste avant la ligne &lt;code&gt;words.size&lt;/code&gt; et sauvons le fichier, lorsque nous appelons la m&amp;eacute;thode &lt;code&gt;word_count&lt;/code&gt; de nouveau, l&amp;#x27;ex&amp;eacute;cution va s&amp;#x27;arr&amp;ecirc;ter sur &lt;code&gt;binding.pry&lt;/code&gt; et nous redonner la main sur Pry.&lt;/p&gt;

&lt;pre class="terminal"&gt;&amp;gt; word_count

From: /Users/eifion/blog/app/models/article.rb @ line 7 in Article#word_count:

     2:   attr_accessible :name, :content, :published_at
     3:   has_many :comments
     4: 
     5:   def word_count
     6:     words = content.scan(/\\w+/)
 =&amp;gt;  7:     binding.pry
     8:     words.size
     9:   end
    10: end&lt;/pre&gt;

&lt;p&gt;Nous avons acc&amp;egrave;s &amp;agrave; toutes les variables locales &amp;agrave; la m&amp;eacute;thode. Nous pouvons donc appeler &lt;code&gt;words&lt;/code&gt; pour voir le contenu du tableau &lt;code&gt;words&lt;/code&gt;.&lt;/p&gt;

&lt;pre class="terminal"&gt;pry(#&amp;lt;Article:0x1008c3f38&amp;gt;):3&amp;gt; words
=&amp;gt; []&lt;/pre&gt;

&lt;p&gt;Le tableau est vide, il semble donc qu&amp;#x27;il y ait un probl&amp;egrave;me avec l&amp;#x27;expression r&amp;eacute;guli&amp;egrave;re qui scanne le contenu. Si nous y jetons un &amp;oelig;il, nous voyons qu&amp;#x27;il y a deux backslashes l&amp;agrave; o&amp;ugrave; il ne devrait y en avoir qu&amp;#x27;un seul. Pour corriger cela, nous pouvons de nouveau faire appel &amp;agrave; &lt;code&gt;edit-method word_count&lt;/code&gt;, corriger l&amp;#x27;expression, retirer &lt;code&gt;binding.pry&lt;/code&gt; et sauver le fichier.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/models/article.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;class Article &amp;lt; ActiveRecord::Base
  attr_accessible :name, :content, :published_at
  has_many :comments

  def word_count
    words = content.scan(/\w+/)
    words.size
  end
end&lt;/pre&gt;

&lt;p&gt;Nous pouvons tester notre correctif en appelant une nouvelle fois &lt;code&gt;word_count&lt;/code&gt;. Cette fois, elle fonctionne comme d&amp;eacute;sir&amp;eacute;.&lt;/p&gt;

&lt;pre class="terminal"&gt;pry(#&amp;lt;Article:0x1008c3f38&amp;gt;):3&amp;gt; word_count
=&amp;gt; 55&lt;/pre&gt;

&lt;p&gt;Nous avons parfois besoin de debugger un contr&amp;ocirc;leur ou une vue de notre application et la console Rails n&amp;#x27;est pas toujours le plus simple pour cela. Pry nous aide &amp;eacute;galement &amp;agrave; le faire. Tout d&amp;#x27;abord, nous devons ajouter Pry &amp;agrave; notre Gemfile.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/Gemfile&lt;/p&gt;
&lt;pre class="ruby"&gt;source &amp;#x27;http://rubygems.org&amp;#x27;

gem &amp;#x27;rails&amp;#x27;, &amp;#x27;3.0.10&amp;#x27;
gem &amp;#x27;sqlite3&amp;#x27;
gem &amp;#x27;nifty-generators&amp;#x27;
gem &amp;#x27;pry&amp;#x27;, :group =&amp;gt; :development&lt;/pre&gt;

&lt;p&gt;Nous appelons ensuite &lt;code&gt;bundle&lt;/code&gt; pour installer la gem puis nous lan&amp;ccedil;ons &lt;code&gt;rails s&lt;/code&gt; pour d&amp;eacute;marrer le serveur. Nous pouvons maintenant ajouter un appel &amp;agrave; &lt;code&gt;binding.pry&lt;/code&gt; n&amp;#x27;importe o&amp;ugrave; dans nos contr&amp;ocirc;leurs pour ajouter un breakpoint.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/controllers/articles_controller.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;def index
  @articles = Article.all
  binding.pry
end&lt;/pre&gt;

&lt;p&gt;Si nous visitons cette page dans le navigateur, elle va bloquer sur le chargement. Dans le terminal, on peut voir une invite de commande Pry et nous sommes dans le contexte du breakpoint. Comme nous le faisions dans les mod&amp;egrave;les, nous pouvons inspecter les valeurs de toutes les variables locales. Une fois notre travail termin&amp;eacute;, nous pouvons taper &lt;code&gt;exit-all&lt;/code&gt; pour permettre &amp;agrave; la requ&amp;ecirc;te de se terminer.&lt;/p&gt;

&lt;pre class="terminal"&gt;From: /Users/eifion/blog/app/controllers/articles_controller.rb @ line 4 in ArticlesController#index:

     1: class ArticlesController &amp;lt; ApplicationController
     2:   def index
     3:     @articles = Article.all
 =&amp;gt;  4:     binding.pry
     5:   end
     6: 
     7:   def show
     8:     @article = Article.find(params[:id])
     9:   end&lt;/pre&gt;
     
&lt;p&gt;C&amp;#x27;est tout pour cet &amp;eacute;pisode sur Pry. C&amp;#x27;est une gem tr&amp;egrave;s utile et elle fournit bien plus de fonctionnalit&amp;eacute;s que ce que nous venons de vous montrer. Le &lt;a href="https://github.com/pry/pry/wiki"&gt;wiki&lt;/a&gt; couvre beaucoup plus et contient un lien vers un tr&amp;egrave;s bon &lt;a href="http://vimeo.com/26391171"&gt;screencast&lt;/a&gt; r&amp;eacute;alis&amp;eacute; par Joshua Cheek.&lt;/p&gt;
</description>
      <pubDate>Sun, 02 Oct 2011 22:16:47 +0000</pubDate>
      <guid>http://fr.asciicasts.com/episodes/280-pry-avec-rails</guid>
      <link>http://fr.asciicasts.com/episodes/280-pry-avec-rails</link>
    </item>
    <item>
      <title>Comprendre l&amp;apos;Asset Pipeline</title>
      <description>&lt;p&gt;L&amp;#x27;asset pipeline est une des plus importantes fonctionnalit&amp;eacute;s de Rails&amp;nbsp;3.1. Elle peut cependant &amp;ecirc;tre difficile &amp;agrave; appr&amp;eacute;hender. Dans cet &amp;eacute;pisode, nous allons tenter de la d&amp;eacute;mystifier un peu en montrant comment elle g&amp;egrave;re les ressources media (assets) de vos applications Rails. Si le sujet vous est totalement inconnu, un bon point de d&amp;eacute;part est le &lt;a href="http://ryanbigg.com/guides/asset_pipeline.html"&gt;Guide Rails sur l&amp;#x27;asset pipeline&lt;/a&gt; qui aborde bon nombre de ses fonctionnalit&amp;eacute;s.&lt;/p&gt;

&lt;p&gt;Si vous avez &amp;eacute;crit une application Rails&amp;nbsp;3.1, vous savez probablement qu&amp;#x27;en visitant &lt;code&gt;&lt;a href="http://localhost:3000/assets/application.js"&gt;http://localhost:3000/assets/application.js&lt;/a&gt;&lt;/code&gt;, vous allez obtenir un fichier contenant tous les fichiers JavaScript de votre application. Mais comment cela fonctionne-t-il&amp;nbsp;?&lt;/p&gt;

&lt;p&gt;Le fichier &lt;code&gt;application.js&lt;/code&gt; n&amp;#x27;a rien de particulier. Tout fichier plac&amp;eacute; dans le dossier &lt;code&gt;/app/assets/javascripts&lt;/code&gt; est tout autant accessible. Si, par exemple, nous cr&amp;eacute;ons, dans ce dossier, un fichier nomm&amp;eacute; &lt;code&gt;greeting.txt&lt;/code&gt;, nous pouvons le voir dans le navigateur en visitant &lt;a href="http://localhost:3000/assets/greeting.txt"&gt;&lt;code&gt;http://localhost:3000/assets/greeting.txt&lt;/code&gt;&lt;/a&gt;. Bien que le fichier soit dans &lt;code&gt;/app/assets/javascripts&lt;/code&gt;, l&amp;#x27;URL par laquelle nous y acc&amp;eacute;dons est &lt;code&gt;/assets/greeting.txt&lt;/code&gt;. Cela s&amp;#x27;applique, peu importe, dans quel sous dossier de &lt;code&gt;/app/assets&lt;/code&gt; nous pla&amp;ccedil;ons le fichier. Nous pouvons m&amp;ecirc;me cr&amp;eacute;er un nouveau dossier et y placer le fichier, il sera toujours accessible &amp;agrave; la m&amp;ecirc;me URL. Si nous cr&amp;eacute;ons effectivement un nouveau dossier, nous devrons tout de m&amp;ecirc;me relancer le serveur avant que les fichiers que l&amp;#x27;on y place soient accessibles.&lt;/p&gt;

&lt;p&gt;Le dossier &lt;code&gt;/app/assets&lt;/code&gt; n&amp;#x27;est pas le seul dans lequel nous pouvons ajouter des assets. Si nous cr&amp;eacute;ons un dossier &lt;code&gt;assets&lt;/code&gt; dans &lt;code&gt;/lib&lt;/code&gt;, tout fichier plac&amp;eacute; dans celui-ci sera accessible comme s&amp;#x27;il &amp;eacute;tait mis dans le dossier &lt;code&gt;/app/assets&lt;/code&gt;. Cela s&amp;#x27;applique &amp;eacute;galement &amp;agrave; tout fichier plac&amp;eacute; dans le dossier &lt;code&gt;/vendor/assets&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Si vous avez des assets qui ne sont pas vraiment sp&amp;eacute;cifiques &amp;agrave; l&amp;#x27;application courante, les dossiers &lt;code&gt;assets&lt;/code&gt; situ&amp;eacute;s dans &lt;code&gt;/lib&lt;/code&gt; ou &lt;code&gt;/vendor&lt;/code&gt; sont leur destination id&amp;eacute;ale. Si l&amp;#x27;application utilise un plugin jQuery, le dossier &lt;code&gt;/vendor/assets&lt;/code&gt; est l&amp;#x27;endroit o&amp;ugrave; placer ses fichiers JavaScript puisqu&amp;#x27;ils sont maintenus par quelqu&amp;#x27;un d&amp;#x27;autre. Pour les assets maintenus par nos soins mais qui ne sont pas sp&amp;eacute;cifiques &amp;agrave; l&amp;#x27;application, le choix se portera plut&amp;ocirc;t sur le dossier &lt;code&gt;/lib&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Dans sa forme la plus basique, l&amp;#x27;asset pipeline est une liste de chemins de chargement (loadpaths). Nous pouvons voir cette liste en lan&amp;ccedil;ant la console Rails et en inspectant &lt;code&gt;Rails.application.config.assets.paths&lt;/code&gt;. Nous afficherons le r&amp;eacute;sultat en YAML pour plus de lisibilit&amp;eacute;.&lt;/p&gt;

&lt;pre class="terminal"&gt;&amp;gt; y Rails.application.config.assets.paths
--- 
- /Users/eifion/store/app/assets/images
- /Users/eifion/store/app/assets/javascripts
- /Users/eifion/store/app/assets/stylesheets
- /Users/eifion/store/lib/assets/greeting.txt
- /Users/eifion/store/vendor/assets/stylesheets
- /Users/eifion/.rvm/gems/ruby-1.9.2-p180@railspre/gems/jquery-rails-1.0.13/vendor/assets/javascripts&lt;/pre&gt;

&lt;p&gt;Le r&amp;eacute;sultat est une liste de tous les dossiers contenus dans &lt;code&gt;/app/assets&lt;/code&gt; ainsi que ceux pr&amp;eacute;sents dans &lt;code&gt;/lib/assets&lt;/code&gt; et &lt;code&gt;/vendor/assets&lt;/code&gt;. On trouve toutefois un dossier int&amp;eacute;ressant &amp;agrave; la fin de la liste. Celui-ci provient de la gem &lt;code&gt;jquery-rails&lt;/code&gt;, incluse dans notre application. Nous pouvons voir son contenu gr&amp;acirc;ce &amp;agrave; la commande &lt;code&gt;bundle open&lt;/code&gt;.&lt;/p&gt;

&lt;pre class="terminal"&gt;$ bundle open jquery-rails&lt;/pre&gt;

&lt;p&gt;Cela ouvre la gem avec l&amp;#x27;&amp;eacute;diteur d&amp;eacute;finit dans les variables d&amp;#x27;environnement &lt;code&gt;BUNDLER_EDITOR&lt;/code&gt; ou &lt;code&gt;EDITOR&lt;/code&gt;. Si nous jetons un &amp;oelig;il aux fichiers de la gem, nous allons voir un dossier &lt;code&gt;vendor/asset/javascripts&lt;/code&gt; contenant un certain nombre de fichiers jQuery que nous pouvons charger via l&amp;#x27;asset pipeline.&lt;/p&gt;

&lt;div class="imageWrapper"&gt;
  &lt;img src="/system/photos/723/original/E279I01.png" width="801" height="377" alt="La structure des fichiers et dossiers de la gem jquery-rails."/&gt;
&lt;/div&gt;

&lt;p&gt;Comme vous pouvez vous y attendre, nous pouvons acc&amp;eacute;der &amp;agrave; chacun de ces fichiers, via le navigateur, sous le chemin &lt;code&gt;assets&lt;/code&gt; puisque le dossier les contenant est list&amp;eacute; dans le loadpath de l&amp;#x27;asset pipeline.&lt;/p&gt;

&lt;div class="imageWrapper"&gt;
  &lt;img src="/system/photos/724/original/E279I02.png" width="801" height="437" alt="Le fichier jquery.js est accessible dans le dossier assets."/&gt;
&lt;/div&gt;

&lt;p&gt;Ce qu&amp;#x27;il est int&amp;eacute;ressant de noter, c&amp;#x27;est que cela signifie que les gems Ruby n&amp;#x27;ont plus pour unique but de g&amp;eacute;rer du code Ruby. Nous pouvons les utiliser pour g&amp;eacute;rer des fichiers JavaScript ou tout autre type d&amp;#x27;asset. Il est &amp;agrave; pari&amp;eacute; que nous verrons, sous peu, de nombreuses librairies JavaScript distribu&amp;eacute;es sous forme de gems Ruby, nous pourrons alors profiter des avantages de Bundler et de sa gestion des d&amp;eacute;pendances.&lt;/p&gt;

&lt;h3&gt;G&amp;eacute;rer les Assets avec Sprockets&lt;/h3&gt;

&lt;p&gt;Retournons au fichier &lt;code&gt;application.js&lt;/code&gt; de notre application et jetons-y un &amp;oelig;il.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/assets/javascripts/application.js&lt;/p&gt;
&lt;pre class="javascript"&gt;// This is a manifest file that&amp;#x27;ll be compiled into including all the files listed below.
// Add new JavaScript/Coffee code in separate files in this directory and they&amp;#x27;ll automatically
// be included in the compiled file accessible from http://example.com/assets/application.js
// It&amp;#x27;s not advisable to add code directly here, but if you do, it&amp;#x27;ll appear at the bottom of the
// the compiled file.
//
//= require jquery
//= require jquery_ujs
//= require_tree .&lt;/pre&gt;

&lt;p&gt;Le fichier contient uniquement des commentaires mais certains ont une signification. Ce type de fichier est un manifest et est g&amp;eacute;r&amp;eacute; par &lt;a href="http://getsprockets.org/"&gt;Sprockets&lt;/a&gt;. Lorsqu&amp;#x27;une requ&amp;ecirc;te pour ce fichier arrive, Sprockets lit le manifest et compile tous les fichiers mentionn&amp;eacute;s dans celui-ci puis inclut leur contenu avant le code du manifest.&lt;/p&gt;

&lt;p&gt;Le loadpath fonctionne &amp;eacute;galement ici. Nous trouvons une ligne &lt;code&gt;require jquery&lt;/code&gt; dans ce fichier (l&amp;#x27;extension &lt;code&gt;.js&lt;/code&gt; est facultative). Sprockets va chercher ce fichier dans le loadpath et, dans le cas de jquery, le charger depuis le dossier &lt;code&gt;vendor/asset/javascripts&lt;/code&gt; de l&amp;#x27;engine &lt;code&gt;jquery-rails&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Nous pouvons ajouter n&amp;#x27;importe quel fichier JavaScript se trouvant dans le loadpath. Si nous ajoutons &lt;code&gt;require jquery-ui&lt;/code&gt; au manifest, le fichier &lt;code&gt;jquery-ui.js&lt;/code&gt; sera inclus. Cela s&amp;#x27;applique &amp;eacute;galement aux fichiers CoffeeScript. Si nous ajoutons &lt;code&gt;require home&lt;/code&gt;, le fichier &lt;code&gt;/app/assets/javascripts/home.js.coffee&lt;/code&gt; va &amp;ecirc;tre analys&amp;eacute; et inclus.&lt;/p&gt;

&lt;p&gt;Inclure ce fichier &lt;code&gt;home&lt;/code&gt; n&amp;#x27;est pas n&amp;eacute;cessaire car, en bas du fichier, on trouve &lt;code&gt;require_tree .&lt;/code&gt;. Le point repr&amp;eacute;sente ici le dossier courant. Cela signifie que tout fichier JavaScript ou CoffeeScript pr&amp;eacute;sent dans ce dossier et ses sous dossiers sera inclus.&lt;/p&gt;

&lt;p&gt;Si nous voulons exclure certains fichiers de l&amp;#x27;arborescence, nous le pouvons. Disons que nous avons des pages d&amp;#x27;administration sur notre site et que certains fichiers JavaScript doivent &amp;ecirc;tre inclus uniquement sur ces pages. Par d&amp;eacute;faut, ces fichiers vont &amp;ecirc;tre inclus sur toutes les pages du site.&lt;/p&gt;

&lt;p&gt;Si nous voulons voir les fichiers inclus, nous pouvons ajouter un param&amp;egrave;tre &lt;code&gt;debug_assets=1&lt;/code&gt; &amp;agrave; l&amp;#x27;URL. Cela va stopper l&amp;#x27;agr&amp;eacute;gation des fichiers JavaScript et, lorsque nous consultons le code source de la page, nous allons voir tous les fichiers que Sprockets inclurait, y compris les fichiers du dossier admin.&lt;/p&gt;

&lt;div class="imageWrapper"&gt;
  &lt;img src="/system/photos/725/original/E279I03.png" width="789" height="322" alt="Les fichiers JavaScript ne sont pas agr&amp;eacute;g&amp;eacute;s si nous ajoutons le param&amp;egrave;tre debug_assets &amp;agrave; la query string."/&gt;
&lt;/div&gt;

&lt;p&gt;Il existe deux fa&amp;ccedil;ons de r&amp;eacute;soudre ce probl&amp;egrave;me. Nous pourrions utiliser &lt;code&gt;require_directory&lt;/code&gt; au lieu de &lt;code&gt;require_tree&lt;/code&gt;. Cela permettrait de charger uniquement les fichiers du dossier courant et non ceux de ses sous dossiers. Si nous voulions plus de contr&amp;ocirc;le sur les fichiers inclus, nous pourrions faire appel &amp;agrave; &lt;code&gt;require&lt;/code&gt; sur chaque fichier plut&amp;ocirc;t que sur le dossier. Nous pourrions &amp;eacute;galement d&amp;eacute;placer les fichiers JavaScript que nous souhaitons inclure sur toutes les pages dans un sous dossier &lt;code&gt;public&lt;/code&gt; et utiliser &lt;code&gt;require_tree ./public&lt;/code&gt; pour inclure uniquement ces fichiers.&lt;/p&gt;

&lt;p&gt;Si vous vous demandez quelles commandes peuvent &amp;ecirc;tre utilis&amp;eacute;es dans un manifest Sprockets, il n&amp;#x27;existe pas encore de bonne documentation mais, dans le code source du fichier &lt;code&gt;&lt;a href="https://github.com/sstephenson/sprockets/blob/master/lib/sprockets/directive_processor.rb"&gt;directive_processor.rb&lt;/a&gt;&lt;/code&gt;, on peut trouver des commentaires expliquant comment tout cela fonctionne et quelles sont les commandes utilisables.&lt;/p&gt;

&lt;h3&gt;Pr&amp;eacute;traitement&lt;/h3&gt;

&lt;p&gt;L&amp;#x27;asset pipeline permet &amp;eacute;galement de faire du pr&amp;eacute;traitement. Pour montrer comment cela fonctionne, nous allons cr&amp;eacute;er un fichier nomm&amp;eacute; &lt;code&gt;greeting.txt&lt;/code&gt; dans un nouveau dossier &lt;code&gt;/app/assets/anything&lt;/code&gt;. Tel quel, c&amp;#x27;est simplement un fichier texte statique mais, nous pouvons ajouter une autre extension au nom de fichier et sp&amp;eacute;cifier un processeur, par exemple &lt;code&gt;.erb&lt;/code&gt;. Nous pouvons maintenant ajouter du code ERB dans ce fichier et il sera trait&amp;eacute;.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/assets/anything/greeting.txt.erb&lt;/p&gt;
&lt;pre class="ruby"&gt;hello world &amp;lt;%= 1 + 1 %&amp;gt;&lt;/pre&gt;

&lt;p&gt;Si nous regardons ce fichier dans un navigateur, nous allons voir que le code ERB a &amp;eacute;t&amp;eacute; ex&amp;eacute;cut&amp;eacute;. Notez que nous n&amp;#x27;incluons pas l&amp;#x27;extension du pr&amp;eacute;processeur dans l&amp;#x27;URL.&lt;/p&gt;

&lt;div class="imageWrapper"&gt;
  &lt;img src="/system/photos/726/original/E279I04.png" width="801" height="280" alt="Le code erb est trait&amp;eacute; avant que le fichier soit envoy&amp;eacute; au navigateur."/&gt;
&lt;/div&gt;

&lt;p&gt;C&amp;#x27;est essentiellement la mani&amp;egrave;re de fonctionner de SASS et CoffeeScript. Lorsqu&amp;#x27;un fichier a une extension &lt;code&gt;.scss&lt;/code&gt;, elle est trait&amp;eacute;e comme une extension de pr&amp;eacute;processeur et le fichier passera par le processeur SASS. Nous pouvons m&amp;ecirc;me cha&amp;icirc;ner les extensions et cr&amp;eacute;er un fichier avec, par exemple, une extension &lt;code&gt;.scss.erb&lt;/code&gt;. Ce fichier passerait d&amp;#x27;abord par le processeur ERB puis par le processeur SASS.&lt;/p&gt;

&lt;p&gt;Le pr&amp;eacute;traitement est tr&amp;egrave;s configurable. Nous pouvons ajouter notre propre processeur ou &amp;eacute;changer ceux existants. Tout est g&amp;eacute;r&amp;eacute; par la gem &lt;a href="https://github.com/rtomayko/tilt/"&gt;Tilt&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;Les diff&amp;eacute;rences en mode Production&lt;/h3&gt;

&lt;p&gt;C&amp;#x27;est tout pour notre tour rapide de l&amp;#x27;asset pipeline. Il existe quelques diff&amp;eacute;rences sur son fonctionnement en production et nous allons terminer cet &amp;eacute;pisode en les abordant. Tout d&amp;#x27;abord, nous allons lancer notre serveur en mode production.&lt;/p&gt;

&lt;pre class="terminal"&gt;$ rails s -e production&lt;/pre&gt;

&lt;p&gt;Si nous visitons la page d&amp;#x27;accueil de notre application et regardons son code source, nous allons voir que nos assets sont d&amp;eacute;livr&amp;eacute;s diff&amp;eacute;remment.&lt;/p&gt;

&lt;pre class="terminal"&gt;&amp;lt;link href=&amp;quot;/assets/application-412fe22651f4486c51e54176003a9f57.css&amp;quot; media=&amp;quot;screen&amp;quot; rel=&amp;quot;stylesheet&amp;quot; type=&amp;quot;text/css&amp;quot; /&amp;gt;
  &amp;lt;script src=&amp;quot;/assets/application-3e3a5167191afa70c7b72440eee7dd40.js&amp;quot; type=&amp;quot;text/javascript&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;/pre&gt;

&lt;p&gt;Les noms de fichiers incluent un hash pr&amp;eacute;vu pour le cache. Cela fonctionne bien mieux que l&amp;#x27;ancienne m&amp;eacute;thode, bas&amp;eacute;e sur la query string et utilis&amp;eacute;e par Rails&amp;nbsp;3.0, car le nom des fichiers est modifi&amp;eacute;. Si nous regardons le contenu des fichiers, nous pouvons voir qu&amp;#x27;il sont minifi&amp;eacute;s pour &amp;eacute;conomiser de la bande passante.&lt;/p&gt;

&lt;p&gt;Ces assets sont automatiquement mis en cache et servis par le middleware Rack Cache pour plus de rapidit&amp;eacute;. Si nous voulons que le serveur web se charge lui-m&amp;ecirc;me de servir et h&amp;eacute;berger ces assets, nous pouvons les pr&amp;eacute;compiler en lan&amp;ccedil;ant&lt;/p&gt;

&lt;pre class="terminal"&gt;$ rake assets:precompile&lt;/pre&gt;

&lt;p&gt;Cela va pr&amp;eacute;compiler les assets dans le dossier &lt;code&gt;/public&lt;/code&gt; pour les rendre facilement accessibles par le serveur web.&lt;/p&gt;

&lt;p&gt;C&amp;#x27;est tout pour cet &amp;eacute;pisode sur l&amp;#x27;asset pipeline. N&amp;#x27;oubliez pas de regarder le &lt;a href="http://ryanbigg.com/guides/asset_pipeline.html"&gt;Guide Rails&lt;/a&gt; pour plus d&amp;#x27;informations.&lt;/p&gt;
</description>
      <pubDate>Wed, 28 Sep 2011 18:38:08 +0000</pubDate>
      <guid>http://fr.asciicasts.com/episodes/279-comprendre-l-asset-pipeline</guid>
      <link>http://fr.asciicasts.com/episodes/279-comprendre-l-asset-pipeline</link>
    </item>
    <item>
      <title>Recherche avec Sunspot</title>
      <description>&lt;p&gt;&lt;a href="http : //outoftime.github.com/sunspot"&gt;Sunspot&lt;/a&gt; est une solution permettant d&amp;#x27;ajouter une recherche full-text aux applications Ruby. Elle utilise &lt;a href="http://lucene.apache.org/solr/"&gt;Solr&lt;/a&gt; en arri&amp;egrave;re-plan et a de nombreuses fonctionnalit&amp;eacute;s sympathiques. Dans cet &amp;eacute;pisode, nous allons l&amp;#x27;utiliser pour ajouter une recherche full-text &amp;agrave; une application Rails. Nous utiliserons une application de blog qui nous a d&amp;eacute;j&amp;agrave; servi dans de pr&amp;eacute;c&amp;eacute;dents &amp;eacute;pisodes.&lt;/p&gt;

&lt;div class="imageWrapper"&gt;
  &lt;img src="/system/photos/718/original/E278I01.png" width="800" height="432" alt="Notre application blogging."/&gt;
&lt;/div&gt;

&lt;p&gt;Cette application contient une page qui affiche un certain nombre d&amp;#x27;articles et nous voulons faire en sorte de pouvoir chercher parmi ceux-ci. En utilisant SQL, cela devient rapidement difficile et ce n&amp;#x27;est pas, en g&amp;eacute;n&amp;eacute;ral, la meilleure approche. Une solution d&amp;eacute;di&amp;eacute;e &amp;agrave; la recherche full-text, comme Sunspot, s&amp;#x27;av&amp;egrave;re plus pertinente pour impl&amp;eacute;menter cette fonctionnalit&amp;eacute;.&lt;/p&gt;

&lt;h3&gt;Installer Sunspot&lt;/h3&gt;

&lt;p&gt;Sunspot est distribu&amp;eacute;e sous forme de gem et s&amp;#x27;installe de la mani&amp;egrave;re habituelle, &lt;code&gt;Gemfile&lt;/code&gt; et &lt;code&gt;bundle&lt;/code&gt;.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/Gemfile&lt;/p&gt;
&lt;pre class="ruby"&gt;source &amp;#x27;http://rubygems.org&amp;#x27;

gem &amp;#x27;rails&amp;#x27;, &amp;#x27;3.0.9&amp;#x27;
gem &amp;#x27;sqlite3&amp;#x27;
gem &amp;#x27;nifty-generators&amp;#x27;
gem &amp;#x27;sunspot_rails&amp;#x27;&lt;/pre&gt;

&lt;p&gt;Une fois la gem et ses d&amp;eacute;pendances install&amp;eacute;es, nous devons g&amp;eacute;n&amp;eacute;rer le fichier de configuration de Sunspot en lan&amp;ccedil;ant&lt;/p&gt;

&lt;pre class="terminal"&gt;$ rails g sunspot_rails:install&lt;/pre&gt;

&lt;p&gt;Cette commande cr&amp;eacute;e un fichier YML dans &lt;code&gt;/config/sunspot.yml&lt;/code&gt;. Nous n&amp;#x27;avons besoin de faire aucun changement aux r&amp;eacute;glages par d&amp;eacute;faut.&lt;/p&gt;

&lt;p&gt;Sunspot encapsule Solr dans la gem, nul besoin, donc, de l&amp;#x27;installer s&amp;eacute;par&amp;eacute;ment. Cela signifie que tout fonctionne tout de suite, ce qui est bien pratique en d&amp;eacute;veloppement. Pour d&amp;eacute;marrer, nous lan&amp;ccedil;ons&lt;/p&gt;

&lt;pre class="terminal"&gt;$ rake sunspot:solr:start&lt;/pre&gt;

&lt;p&gt;Si vous &amp;ecirc;tes sous OS&amp;nbsp;X&amp;nbsp;Lion et que vous n&amp;#x27;avez pas install&amp;eacute; le runtime Java, il vous sera demand&amp;eacute; de le faire lorsque vous lancerez la commande. Vous verrez peut-&amp;ecirc;tre un warning de d&amp;eacute;pr&amp;eacute;ciation mais il peut &amp;ecirc;tre ignor&amp;eacute;. La commande va &amp;eacute;galement cr&amp;eacute;er quelques fichiers de configuration suppl&amp;eacute;mentaire pour un r&amp;eacute;glage plus avanc&amp;eacute;. Nous ne les verrons pas mais ils sont d&amp;eacute;taill&amp;eacute;s dans la &lt;a href="http://outoftime.github.com/sunspot/docs/index.html"&gt;documentation&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;Utiliser Sunspot&lt;/h3&gt;

&lt;p&gt;Maintenant que nous avons install&amp;eacute; Sunspot, nous pouvons l&amp;#x27;utiliser dans notre mod&amp;egrave;le &lt;code&gt;Article&lt;/code&gt;. Pour ajouter la recherche full-text, nous utilisons la m&amp;eacute;thode &lt;code&gt;searchable&lt;/code&gt;.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/models/article.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;class Article &amp;lt; ActiveRecord::Base
  attr_accessible :name, :content, :published_at
  has_many :comments
  
  searchable do
    text :name, :content
  end
end&lt;/pre&gt;

&lt;p&gt;Cette m&amp;eacute;thode prend un bloc et, dedans, nous d&amp;eacute;finissons les attributs sur lesquels nous voulons effectuer la recherche de mani&amp;egrave;re &amp;agrave; ce que Sunspot sache quoi indexer. Nous pouvons utiliser la m&amp;eacute;thode &lt;code&gt;text&lt;/code&gt; pour d&amp;eacute;finir les attributs sur lesquels une recherche full-text sera effectu&amp;eacute;e. Pour nos articles, nous le ferons pour les champs name et content.&lt;/p&gt;

&lt;p&gt;Sunspot indexe automatiquement toute nouvel article mais pas les existants. Nous pouvons dire &amp;agrave; Sunspot de re-indexer les entr&amp;eacute;es existantes en lan&amp;ccedil;ant&lt;/p&gt;

&lt;pre class="terminal"&gt;$ rake sunspot:reindex&lt;/pre&gt;

&lt;p&gt;Tous les articles sont maintenant dans la base de donn&amp;eacute;es de Solr et nous pouvons chercher parmi ceux-ci. Nous allons donc ajouter un champ de recherche en haut de la page d&amp;#x27;index.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/views/articles/index.html.erb&lt;/p&gt;
&lt;pre class="ruby"&gt;&amp;lt;% title &amp;quot;Articles&amp;quot; %&amp;gt;

&amp;lt;%= form_tag articles_path, :method =&amp;gt; :get do %&amp;gt;
  &amp;lt;p&amp;gt;
    &amp;lt;%= text_field_tag :search, params[:search] %&amp;gt;
    &amp;lt;%= submit_tag &amp;quot;Search&amp;quot;, :name =&amp;gt; nil %&amp;gt;
&amp;lt;% end %&amp;gt;
&amp;lt;!-- rest of view omitted --&amp;gt;&lt;/pre&gt;

&lt;p&gt;Ce formulaire envoie les information de recherche en GET &amp;agrave; l&amp;#x27;action &lt;code&gt;index&lt;/code&gt;. Tous les param&amp;egrave;tres de recherche seront donc ajout&amp;eacute;s &amp;agrave; la query string. Nous allons ensuite modifier le contr&amp;ocirc;leur de fa&amp;ccedil;on &amp;agrave; ce qu&amp;#x27;il r&amp;eacute;cup&amp;egrave;re les articles en utilisant ce param&amp;egrave;tre &lt;code&gt;search&lt;/code&gt;. Pour lancer une recherche avec Sunspot, nous appelons la m&amp;eacute;thode &lt;code&gt;search&lt;/code&gt; sur le mod&amp;egrave;le et lui passons un bloc. Dans ce bloc, nous pouvons faire appel &amp;agrave; diff&amp;eacute;rentes m&amp;eacute;thodes pour g&amp;eacute;rer les recherches complexes. Nous allons utiliser la m&amp;eacute;thode &lt;code&gt;fulltext&lt;/code&gt; et lui passer les param&amp;egrave;tres de recherche du formulaire. Enfin, nous allons assigner le r&amp;eacute;sultat &amp;agrave; &lt;code&gt;@search&lt;/code&gt;. Nous pouvons appeler &lt;code&gt;results&lt;/code&gt; dessus pour obtenir la liste des articles correspondants.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/controllers/articles_controller.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;def index
  @search = Article.search do
    fulltext params[:search]
  end
  @articles = @search.results
end&lt;/pre&gt;

&lt;p&gt;Nous pouvons tester cela en rechargeant la page des articles et en cherchant un mot cl&amp;eacute;. Nous voyons alors une liste des articles r&amp;eacute;pondant &amp;agrave; cette recherche.&lt;/p&gt;

&lt;div class="imageWrapper"&gt;
  &lt;img src="/system/photos/719/original/E278I02.png" width="800" height="565" alt="La liste des articles filtr&amp;eacute;e."/&gt;
&lt;/div&gt;

&lt;p&gt;La recherche retourne une liste des articles contenant le terme de recherche, que cela soit dans le champ &lt;code&gt;name&lt;/code&gt; ou &lt;code&gt;content&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Nous pouvons faire bien plus dans le bloc &lt;code&gt;searchable&lt;/code&gt; du mod&amp;egrave;le &lt;code&gt;Article&lt;/code&gt;. Par exemple, nous pouvons utiliser &lt;code&gt;boost&lt;/code&gt; pour modifier le poids des champs. Nous pouvons donc rendre le champ &lt;code&gt;name&lt;/code&gt; plus important que le champ &lt;code&gt;content&lt;/code&gt;.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/models/article.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;class Article &amp;lt; ActiveRecord::Base
  attr_accessible :name, :content, :published_at
  has_many :comments
  
  searchable do
    text :name, :boost =&amp;gt; 5
    text :content
  end
end&lt;/pre&gt;

&lt;p&gt;C&amp;#x27;est important lorsque nous voulons trier les r&amp;eacute;sultats par pertinence. Dans notre cas, les articles dont le nom contient le terme recherch&amp;eacute; appara&amp;icirc;tront avant ceux le comprenant seulement dans leur contenu.&lt;/p&gt;

&lt;p&gt;Les attributs list&amp;eacute;s dans le bloc &lt;code&gt;searchable&lt;/code&gt; ne doivent pas n&amp;eacute;cessairement &amp;ecirc;tre des champs en base de donn&amp;eacute;es, nous pouvons utiliser n&amp;#x27;importe quelle m&amp;eacute;thode d&amp;eacute;finie dans le mod&amp;egrave;le. Nous allons cr&amp;eacute;er une m&amp;eacute;thode &lt;code&gt;publish_month&lt;/code&gt; qui va retourner le nom du mois et l&amp;#x27;ann&amp;eacute;e de publication de l&amp;#x27;article et effectuer ensuite une recherche sur cette m&amp;eacute;thode comme s&amp;#x27;il s&amp;#x27;agissait d&amp;#x27;un champ en base.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/models/article.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;class Article &amp;lt; ActiveRecord::Base
  attr_accessible :name, :content, :published_at
  has_many :comments
  
  searchable do
    text :name, :boost =&amp;gt; 5
    text :content, :publish_month
  end
  
  def publish_month
    published_at.strftime(&amp;quot;%B %Y&amp;quot;)
  end
  
end&lt;/pre&gt;

&lt;p&gt;Nous devons indexer de nouveau les entr&amp;eacute;es en lan&amp;ccedil;ant &lt;code&gt;rake sunspot:reindex&lt;/code&gt; avant de pouvoir effectuer notre recherche sur le nom de mois.&lt;/p&gt;

&lt;div class="imageWrapper"&gt;
  &lt;img src="/system/photos/720/original/E278I03.png" width="800" height="420" alt="Les articles filtr&amp;eacute;s sur leur mois de publication."/&gt;
&lt;/div&gt;

&lt;p&gt;Au lieu de cr&amp;eacute;er une m&amp;eacute;thode, nous pouvons cr&amp;eacute;er un bloc et effectuer la recherche sur ce que retourne ce dernier. Un article a des commentaires, nous pouvons donc ajouter la possibilit&amp;eacute; d&amp;#x27;effectuer une recherche sur le contenu des commentaires en utilisant un bloc.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/models/article.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;class Article &amp;lt; ActiveRecord::Base
  attr_accessible :name, :content, :published_at
  has_many :comments
  
  searchable do
    text :name, :boost =&amp;gt; 5
    text :content, :publish_month
    text :comments do
      comments.map(&amp;amp;:content)
    end
  end
  
  def publish_month
    published_at.strftime(&amp;quot;%B %Y&amp;quot;)
  end
  
end&lt;/pre&gt;

&lt;p&gt;Dans le bloc, le contexte est celui d&amp;#x27;un &lt;code&gt;Article&lt;/code&gt;. Nous pouvons donc obtenir les commentaires et faire un mapping sur leur contenu. Bien que cela retourne un tableau, Sunspot saura s&amp;#x27;en charger et indexer tous les commentaires afin de pouvoir effectuer une recherche sur ces derniers.&lt;/p&gt;

&lt;h3&gt;Effectuer une recherche sur les attributs&lt;/h3&gt;

&lt;p&gt;Que devons-nous faire si nous souhaitons des capacit&amp;eacute;s de recherche plus puissantes qu&amp;#x27;une simple recherche full-text ? Une recherche sur un attribut particulier, par exemple. Nous devons simplement passer le type d&amp;#x27;attribut que nous voulons filtrer, que ce soit string, integer, float ou encore timestamp. Pour ajouter l&amp;#x27;attribut &lt;code&gt;published_at&lt;/code&gt; aux champs recherch&amp;eacute;s, nous pouvons utiliser la m&amp;eacute;thode &lt;code&gt;time&lt;/code&gt;.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/models/article.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;class Article &amp;lt; ActiveRecord::Base
  attr_accessible :name, :content, :published_at
  has_many :comments
  
  searchable do
    text :name, :boost =&amp;gt; 5
    text :content, :publish_month
    text :comments do
      comments.map(&amp;amp;:content)
    end
    time :published_at
  end
  
  def publish_month
    published_at.strftime(&amp;quot;%B %Y&amp;quot;)
  end
  
end&lt;/pre&gt;

&lt;p&gt;Nous pouvons en faire usage dans &lt;code&gt;ArticlesController&lt;/code&gt; pour restreindre les articles cherch&amp;eacute;s &amp;agrave; une date de publication ant&amp;eacute;rieure &amp;agrave; la date courante. Pour cela, nous utilisons la m&amp;eacute;thode &lt;code&gt;with&lt;/code&gt;.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/controllers/articles_controller.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;def index
  @search = Article.search do
    fulltext params[:search]
    with(:published_at).less_than(Time.zone.now)
  end
  @articles = @search.results
end&lt;/pre&gt;

&lt;p&gt;Cela fait, une recherche ne retournera pas les articles qui n&amp;#x27;ont pas encore &amp;eacute;t&amp;eacute; publi&amp;eacute;s. Vous pouvez trouver une tr&amp;egrave;s bonne documentation sur le sujet sur la &lt;a href="https://github.com/outoftime/sunspot/wiki/Scoping-by-attribute-fields"&gt;page de wiki de Sunspot&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;Recherche &amp;agrave; facettes&lt;/h3&gt;

&lt;p&gt;Une recherche &amp;agrave; facettes nous permet de filtrer les r&amp;eacute;sultats de recherche en se basant sur certains attributs comme le mois de publication d&amp;#x27;article. Disons que nous voulons ajouter une liste de liens montrant les dates auxquelles des articles ont &amp;eacute;t&amp;eacute; publi&amp;eacute;s. Lorsque nous cliquons sur l&amp;#x27;un de ces liens, la liste des articles est alors filtr&amp;eacute;e pour afficher uniquement ceux publi&amp;eacute;s pour le mois choisi.&lt;/p&gt;

&lt;p&gt;Pour ce faire, nous allons d&amp;#x27;abord ajouter un attribut &lt;code&gt;string&lt;/code&gt; au bloc &lt;code&gt;searchable&lt;/code&gt; pour notre m&amp;eacute;thode &lt;code&gt;publish_month&lt;/code&gt;.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/models/article.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;class Article &amp;lt; ActiveRecord::Base
  attr_accessible :name, :content, :published_at
  has_many :comments
  
  searchable do
    text :name, :boost =&amp;gt; 5
    text :content, :publish_month
    text :comments do
      comments.map(&amp;amp;:content)
    end
    time :published_at
    string :publish_month
  end
  
  def publish_month
    published_at.strftime(&amp;quot;%B %Y&amp;quot;)
  end
  
end&lt;/pre&gt;

&lt;p&gt;Nous pouvons en faire une recherche &amp;agrave; facettes en appelant &lt;code&gt;facet&lt;/code&gt; dans le bloc &lt;code&gt;search&lt;/code&gt; du contr&amp;ocirc;leur &lt;code&gt;ArticlesController&lt;/code&gt;.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/controllers/articles_controller.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;def index
  @search = Article.search do
    fulltext params[:search]
    with(:published_at).less_than(Time.zone.now)
    facet(:publish_month)
  end
  @articles = @search.results
end&lt;/pre&gt;

&lt;p&gt;Nous pouvons maintenant lister ces facettes sur la page &lt;code&gt;index&lt;/code&gt; en ajoutant le code suivant entre le champ de recherche et la liste des articles.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/views/articles/index.html.erb&lt;/p&gt;
&lt;pre class="ruby"&gt;&amp;lt;div id=&amp;quot;facets&amp;quot;&amp;gt;
  &amp;lt;h3&amp;gt;Published&amp;lt;/h3&amp;gt;
  &amp;lt;ul&amp;gt;
    &amp;lt;% for row in @search.facet(:publish_month).rows %&amp;gt;
      &amp;lt;li&amp;gt;
        &amp;lt;% if params[:month].blank? %&amp;gt;
          &amp;lt;%= link_to row.value, :month =&amp;gt; row.value %&amp;gt; (&amp;lt;%= row.count %&amp;gt;)
        &amp;lt;% else %&amp;gt;
          &amp;lt;strong&amp;gt;&amp;lt;%= row.value %&amp;gt;&amp;lt;/strong&amp;gt; (&amp;lt;%= link_to &amp;quot;remove&amp;quot;, :month =&amp;gt; nil %&amp;gt;)
        &amp;lt;% end %&amp;gt;
      &amp;lt;/li&amp;gt;
    &amp;lt;% end %&amp;gt;
  &amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;&lt;/pre&gt;

&lt;p&gt;Dans ce code, nous bouclons sur chacune des facettes &lt;code&gt;publish_month&lt;/code&gt; et les affichons. Si nous appelons &lt;code&gt;.facet&lt;/code&gt; sur notre objet &lt;code&gt;@search&lt;/code&gt; et passons l&amp;#x27;attribut que nous voulons lister, dans notre cas &lt;code&gt;:publish_month&lt;/code&gt;, nous pouvons ensuite appeler &lt;code&gt;.rows&lt;/code&gt; dessus pour obtenir chaque option de facette pour cet attribut.&lt;/p&gt;

&lt;p&gt;Lorsque nous appelons &lt;code&gt;row.value&lt;/code&gt;, la valeur de l&amp;#x27;attribut est retourn&amp;eacute;e (ex: &amp;ldquo;January 2011&amp;rdquo;). Nous pouvons &amp;eacute;galement faire appel &amp;agrave; &lt;code&gt;row.count&lt;/code&gt; pour obtenir le nombre d&amp;#x27;articles correspondant &amp;agrave; cette valeur. S&amp;#x27;il y a un param&amp;egrave;tre &lt;code&gt;month&lt;/code&gt; dans la query string, nous allons afficher sa valeur suivie d&amp;#x27;un lien &amp;ldquo;remove&amp;rdquo; qui permet de supprimer le param&amp;egrave;tre. Cela nous permet de s&amp;eacute;lectionner une facette donn&amp;eacute;e et de la passer sous forme d&amp;#x27;un param&amp;egrave;tre &lt;code&gt;month&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Lorsque nous rechargeons la page, et que nous avons reindex&amp;eacute; les entr&amp;eacute;es, nous allons voir la liste des facettes dans un panneau, chacune montrant un mois et le nombre d&amp;#x27;articles publi&amp;eacute;s durant ce mois. Si nous s&amp;eacute;lectionnons un mois, nous allons le recevoir en param&amp;egrave;tre dans la query string mais les articles ne seront pas filtr&amp;eacute;s. Pour corriger cela, nous devons ajouter un autre param&amp;egrave;tre &lt;code&gt;with&lt;/code&gt; au bloc &lt;code&gt;search&lt;/code&gt; dans le contr&amp;ocirc;leur afin qu&amp;#x27;il filtre les articles d&amp;#x27;apr&amp;egrave;s le param&amp;egrave;tre &lt;code&gt;month&lt;/code&gt; s&amp;#x27;il est pr&amp;eacute;sent.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/controllers/articles_controller.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;def index
  @search = Article.search do
    fulltext params[:search]
    with(:published_at).less_than(Time.zone.now)
    facet(:publish_month)
    with(:publish_month, params[:month]) &amp;crarr; 
      if params[:month].present?
  end
  @articles = @search.results
end&lt;/pre&gt;

&lt;p&gt;Maintenant, lorsque nous s&amp;eacute;lectionnons un mois, nous verrons la liste correctement filtr&amp;eacute;e.&lt;/p&gt;

&lt;div class="imageWrapper"&gt;
  &lt;img src="/system/photos/721/original/E278I04.png" width="800" height="439" alt="Les articles filtr&amp;eacute;s par mois en utilisant une facette."/&gt;
&lt;/div&gt;

&lt;p&gt;Lorsque nous cliquons sur le lien &amp;ldquo;remove&amp;rdquo;, nous revenons &amp;agrave; la liste compl&amp;egrave;te. Cela fonctionne avec les r&amp;eacute;sultats de recherches. Si nous cherchons un terme, la liste affichera les mois contenant des articles correspondants.&lt;/p&gt;

&lt;div class="imageWrapper"&gt;
  &lt;img src="/system/photos/722/original/E278I05.png" width="800" height="581" alt="Les mois correspondant aux articles filtr&#233;s sont affich&#233;s dans la sidebar."/&gt;
&lt;/div&gt;

&lt;p&gt;Les facettes sont une fonctionnalit&amp;eacute; fort sympathique en parall&amp;egrave;le de la recherche.&lt;/p&gt;

&lt;p&gt;C&amp;#x27;est tout pour cet &amp;eacute;pisode. Sunspot est un tr&amp;egrave;s bon moyen d&amp;#x27;ajouter une recherche full-text aux applications Rails et fournit de nombreuses fonctionnalit&amp;eacute;s suppl&amp;eacute;mentaires non abord&amp;eacute;es ici. Pensez &amp;agrave; jeter un oeil sur le &lt;a href="https://github.com/outoftime/sunspot/wiki/"&gt;wiki&lt;/a&gt; pour plus d&amp;#x27;informations.&lt;/p&gt;
</description>
      <pubDate>Wed, 28 Sep 2011 18:32:07 +0000</pubDate>
      <guid>http://fr.asciicasts.com/episodes/278-recherche-avec-sunspot</guid>
      <link>http://fr.asciicasts.com/episodes/278-recherche-avec-sunspot</link>
    </item>
    <item>
      <title>Mountable Engines</title>
      <description>&lt;p&gt;Le Rails&amp;nbsp;3.1 HackFest a eu lieu le week-end dernier et, gr&amp;acirc;ce au dur travail des participants, la cinqui&amp;egrave;me release candidate de Rails&amp;nbsp;3.1 est maintenant disponible. Cette release contient d&amp;#x27;importantes corrections pour les mountable engines. Les mountable engines nous permettent de monter une application Rails &amp;agrave; l&amp;#x27;int&amp;eacute;rieur d&amp;#x27;une autre. Nous allons voir cela dans cet &amp;eacute;pisode.&lt;/p&gt;

&lt;p&gt;Vous vous souvenez peut &amp;ecirc;tre du plugin Notification Exception, couvert dans l&amp;#x27;&amp;eacute;pisode 104 [ &lt;a href="http://railscasts.com/episodes/104-exception-notifications"&gt;regarder&lt;/a&gt; ]. Il peut &amp;ecirc;tre ajout&amp;eacute; &amp;agrave; une application et stocke en base chaque exception lev&amp;eacute;e par l&amp;#x27;application. Il fournit &amp;eacute;galement une interface utilisateur permettant de consulter les exceptions. Dans cet &amp;eacute;pisode, nous allons recr&amp;eacute;er ce plugin sous forme de mountable engine.&lt;/p&gt;

&lt;h3&gt;Mise en route&lt;/h3&gt;

&lt;p&gt;Avant de commencer &amp;agrave; &amp;eacute;crire notre engine, nous devons nous assurez que nous utilisons Rails&amp;nbsp;3.1 Release&amp;nbsp;Candidate&amp;nbsp;5 ou une version plus r&amp;eacute;cente. Nous pouvons installer la derni&amp;egrave;re version en date gr&amp;acirc;ce &amp;agrave;&lt;/p&gt;

&lt;pre class="terminal"&gt;$ gem install rails --pre&lt;/pre&gt;

&lt;p&gt;Une fois cela fait, nous pouvons commencer &amp;agrave; g&amp;eacute;n&amp;eacute;rer notre mountable engine. Nous n&amp;#x27;avons pas besoin de le cr&amp;eacute;er dans une application existante, cr&amp;eacute;er un engine revient &amp;agrave; cr&amp;eacute;er un nouvelle application Rails avec la commande &lt;code&gt;rails new&lt;/code&gt;. La seule diff&amp;eacute;rence est que nous lan&amp;ccedil;ons &lt;code&gt;rails plugin new&lt;/code&gt; &amp;agrave; la place. Comme notre application s&amp;#x27;occupe d&amp;#x27;exceptions, nous l&amp;#x27;appellerons &lt;code&gt;uhoh&lt;/code&gt;. Nous devons passer l&amp;#x27;option &lt;code&gt;--mountable&lt;/code&gt; pour en faire un mountable engine.&lt;/p&gt;

&lt;pre class="terminal"&gt;$ rails plugin new uhoh --mountable&lt;/pre&gt;

&lt;p&gt;La structure du dossier de notre engine ressemble beaucoup &amp;agrave; celle d&amp;#x27;une application Rails classique et c&amp;#x27;en est pratiquement une. Elle est simplement con&amp;ccedil;ue pour &amp;ecirc;tre mont&amp;eacute;e &amp;agrave; l&amp;#x27;int&amp;eacute;rieur d&amp;#x27;une autre. Il existe cependant quelques diff&amp;eacute;rences. Il existe un certain nombre de dossier sous namespace dans l&amp;#x27;application&amp;nbsp;; par exemple, le fichier &lt;code&gt;application_controller&lt;/code&gt; est dans le dossier &lt;code&gt;/app/controllers/uhoh&lt;/code&gt;. Le principe est le m&amp;ecirc;me pour les fichiers des dossiers &lt;code&gt;assets&lt;/code&gt;, &lt;code&gt;helpers&lt;/code&gt; et &lt;code&gt;views&lt;/code&gt;. Cela permet de garder le code de l&amp;#x27;engine s&amp;eacute;par&amp;eacute; de celui de l&amp;#x27;application dans laquelle il sera mont&amp;eacute;. La pr&amp;eacute;sence du dossier &lt;code&gt;assets&lt;/code&gt; signifie qu&amp;#x27;il n&amp;#x27;est plus besoin de copier les ressources media dans le dossier &lt;code&gt;public&lt;/code&gt; de l&amp;#x27;application lorsque l&amp;#x27;engine est mont&amp;eacute;. Gr&amp;acirc;ce &amp;agrave; l&amp;#x27;asset pipeline, tout est g&amp;eacute;r&amp;eacute; pour nous.&lt;/p&gt;

&lt;div class="imageWrapper"&gt;
  &lt;img src="/system/photos/712/original/E277I01.png" width="800" height="502" alt="La structure de dossiers de notre engine."/&gt;
&lt;/div&gt;

&lt;p&gt;Les assets (ressources media) sont &amp;eacute;galement encapsul&amp;eacute;s dans un namespace, nous devons donc passer par ce dossier lorsque nous cr&amp;eacute;ons un lien vers ceux-ci. Nous pouvons &amp;eacute;galement voir cela dans le dossier &lt;code&gt;layouts&lt;/code&gt;. Il semble y avoir un bug en RC5, nous voyons deux fichiers &lt;code&gt;application.html.erb&lt;/code&gt;&amp;nbsp;. Nous pouvons supprimer celui situ&amp;eacute; en dehors du dossier &lt;code&gt;uhoh&lt;/code&gt;. Si nous regardons l&amp;#x27;autre, nous allons voir que les r&amp;eacute;f&amp;eacute;rences aux assets que l&amp;#x27;on y trouve contiennent le dossier &lt;code&gt;uhoh&lt;/code&gt;. Chaque fois que nous cr&amp;eacute;ons un liens vers ces assets, nous devons inclure ce namespace.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/views/layouts/uhoh/application.html.erb&lt;/p&gt;
&lt;pre class="ruby"&gt;&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html&amp;gt;
&amp;lt;head&amp;gt;
  &amp;lt;title&amp;gt;Uhoh&amp;lt;/title&amp;gt;
  &amp;lt;%= stylesheet_link_tag    &amp;quot;uhoh/application&amp;quot; %&amp;gt;
  &amp;lt;%= javascript_include_tag &amp;quot;uhoh/application&amp;quot; %&amp;gt;
  &amp;lt;%= csrf_meta_tags %&amp;gt;
&amp;lt;/head&amp;gt;
&amp;lt;body&amp;gt;

&amp;lt;%= yield %&amp;gt;

&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;&lt;/pre&gt;

&lt;p&gt;Nous allons ensuite regarder l&amp;#x27;un des fichiers cl&amp;eacute;s d&amp;#x27;un engine, &lt;code&gt;engine.rb&lt;/code&gt; dans le dossier &lt;code&gt;/lib/uhoh&lt;/code&gt;.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/lib/uhoh/engine.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;module Uhoh
  class Engine &amp;lt; Rails::Engine
    isolate_namespace Uhoh
  end
end&lt;/pre&gt;

&lt;p&gt;C&amp;#x27;est une classe h&amp;eacute;ritant de &lt;code&gt;Rails::Engine&lt;/code&gt; et c&amp;#x27;est l&amp;#x27;endroit o&amp;ugrave; la configuration est centralis&amp;eacute;e. Il existe d&amp;eacute;j&amp;agrave; un appel &amp;agrave; &lt;code&gt;isolate_namespace&lt;/code&gt; dans la classe et cela signifie que l&amp;#x27;engine sera trait&amp;eacute; comme une unit&amp;eacute; isol&amp;eacute;e et nous n&amp;#x27;avons donc pas &amp;agrave; nous inqui&amp;eacute;ter pour l&amp;#x27;application dans laquelle il sera mont&amp;eacute;.&lt;/p&gt;

&lt;p&gt;La derni&amp;egrave;re partie de l&amp;#x27;engine que nous allons voir est situ&amp;eacute;e dans le dossier &lt;code&gt;/test/dummy&lt;/code&gt;. On y trouve une application Rails permettant de montrer comment marche notre engine lorsqu&amp;#x27;il est mont&amp;eacute;. Le dossier &lt;code&gt;config&lt;/code&gt; de l&amp;#x27;application contient un fichier &lt;code&gt;routes.rb&lt;/code&gt;. Ce dernier contient un appel &amp;agrave; &lt;code&gt;mount&lt;/code&gt; auquel est pass&amp;eacute;e la classe principale de l&amp;#x27;engine qui sera attach&amp;eacute; &amp;agrave; l&amp;#x27;URL.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/test/dummy/config/routes.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;Rails.application.routes.draw do
  mount Uhoh::Engine =&amp;gt; &amp;quot;/uhoh&amp;quot;
end&lt;/pre&gt;

&lt;p&gt;C&amp;#x27;est ce qu&amp;#x27;un utilisateur devra faire lorsqu&amp;#x27;il installera votre engine dans une application, le monter sur une URL de leur choix. C&amp;#x27;est une application Rack et, par cons&amp;eacute;quent, si une requ&amp;ecirc;te arrive sur /uhoh elle sera pass&amp;eacute;e &amp;agrave; notre class &lt;code&gt;Engine&lt;/code&gt;. Une bonne pratique est d&amp;#x27;ajouter cette ligne aux instructions d&amp;#x27;installation dans le fichier README de l&amp;#x27;engine. Cela permettra aux utilisateurs de savoir comment le monter dans le fichier routes de leur application.&lt;/p&gt;

&lt;p&gt;Bien que cette application d&amp;#x27;exemple soit situ&amp;eacute;e dans le dossier &lt;code&gt;/test&lt;/code&gt;, elle est &amp;eacute;galement utile pour tester &amp;agrave; la main. Si nous lan&amp;ccedil;ons &lt;code&gt;rails s&lt;/code&gt; depuis le dossier de notre engine, l&amp;#x27;application d&amp;#x27;exemple va se lancer. Si nous visitons &lt;a href="http://localhost:3000/uhoh/"&gt;&lt;code&gt;http://localhost:3000/uhoh/&lt;/code&gt;&lt;/a&gt;, nous serons men&amp;eacute;s &amp;agrave; notre engine puisque c&amp;#x27;est l&amp;#x27;URL &amp;agrave; laquelle il est mont&amp;eacute;. Nous allons voir une erreur lors de la visite de cette page. C&amp;#x27;est tout &amp;agrave; fait normal puisque nous n&amp;#x27;avons pas encore &amp;eacute;crit le contr&amp;ocirc;leur correspondant.&lt;/p&gt;

&lt;p&gt;Nous allons donc cr&amp;eacute;er un contr&amp;ocirc;leur &lt;code&gt;failures&lt;/code&gt; dans l&amp;#x27;engine. Nous pouvons utiliser les g&amp;eacute;n&amp;eacute;rateurs de Rails pour le faire, tout comme nous le ferions dans une application Rails classique. Bien que nous soyons dans un engine, nous n&amp;#x27;avons pas besoin de sp&amp;eacute;cifier le namespace, tout cela est fait pour nous.&lt;/p&gt;

&lt;pre class="terminal"&gt;$ rails g controller failures index&lt;/pre&gt;

&lt;p&gt;Cela g&amp;eacute;n&amp;egrave;re les m&amp;ecirc;mes fichiers que pour un contr&amp;ocirc;leur classique, &amp;agrave; la diff&amp;eacute;rence que tout est dans le bon dossier de namespace. Nous allons ensuite modifier les routes de l&amp;#x27;engine pour fournir une route &lt;code&gt;root&lt;/code&gt; pointant vers l&amp;#x27;action index de notre contr&amp;ocirc;leur. Cela se fait dans le fichier &lt;code&gt;/config/routes.rb&lt;/code&gt; de l&amp;#x27;engine.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/config/routes.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;Uhoh::Engine.routes.draw do
  root :to =&amp;gt; &amp;quot;failures#index&amp;quot;
end&lt;/pre&gt;

&lt;p&gt;Lorsque nous visitons la page &lt;a href="http://localhost:3000/uhoh/"&gt;&lt;code&gt;http://localhost:3000/uhoh/&lt;/code&gt;&lt;/a&gt;, nous allons maintenant voir la vue de l&amp;#x27;action.&lt;/p&gt;

&lt;div class="imageWrapper"&gt;
  &lt;img src="/system/photos/713/original/E277I02.png" width="801" height="280" alt="Le text par d&amp;eacute;faut dans la vue index."/&gt;
&lt;/div&gt;

&lt;p&gt;Sur cette page, nous voulons afficher une liste des exceptions lev&amp;eacute;es. Nous allons avoir besoin d&amp;#x27;un mod&amp;egrave;le pour stocker cette information et nous allons donc cr&amp;eacute;er un simple mod&amp;egrave;le &lt;code&gt;Failure&lt;/code&gt; avec un champ message.&lt;/p&gt;

&lt;pre class="terminal"&gt;$ rails g model failure message:text&lt;/pre&gt;

&lt;p&gt;Maintenant que nous avons cr&amp;eacute;&amp;eacute; le mod&amp;egrave;le, comment lan&amp;ccedil;ons nous la migration ? Dans l&amp;#x27;engine lui-m&amp;ecirc;me, nous pouvons lancer &lt;code&gt;rake db:migrate&lt;/code&gt; comme d&amp;#x27;habitude et tout fonctionnera comme pr&amp;eacute;vu. Cela ne marchera pas lorsque quelqu&amp;#x27;un tentera de monter l&amp;#x27;engine dans une application car &lt;code&gt;rake&lt;/code&gt; ne prendra pas les migrations de celui-ci. Nous devons dire aux utilisateurs d&amp;#x27;utiliser &lt;code&gt;rake uhoh:install:migrations&lt;/code&gt;. Cela va copier les migrations de l&amp;#x27;engine dans l&amp;#x27;application afin qu&amp;#x27;ils puissent faire appel &amp;agrave; &lt;code&gt;rake db:migrate&lt;/code&gt; normalement. Inclure cette information dans les instructions d&amp;#x27;installation de l&amp;#x27;engine semble une bonne id&amp;eacute;e.&lt;/p&gt;

&lt;p&gt;La console Rails fonctionne &amp;eacute;galement comme attendu et nous allons maintenant l&amp;#x27;utiliser pour cr&amp;eacute;er une &lt;code&gt;Failure&lt;/code&gt; d&amp;#x27;exemple.&lt;/p&gt;

&lt;pre class="ruby"&gt;Uhoh::Failure.create!(:message =&amp;gt; &amp;quot;hello world!&amp;quot;)&lt;/pre&gt;

&lt;p&gt;Notez que nous devons inclure le namespace chaque fois que nous r&amp;eacute;f&amp;eacute;ren&amp;ccedil;ons une classe. Maintenant que nous avons une entr&amp;eacute;e &lt;code&gt;Failure&lt;/code&gt;, nous allons l&amp;#x27;afficher dans l&amp;#x27;action index de &lt;code&gt;FailuresController&lt;/code&gt;.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/controllers/uhoh/failures_controller.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;module Uhoh
  class FailuresController &amp;lt; ApplicationController
    def index
      @failures = Failure.all
    end
  end
end&lt;/pre&gt;

&lt;p&gt;Dans la console, au contraire, nous n&amp;#x27;avons pas besoin de sp&amp;eacute;cifier le namespace car nous somme d&amp;eacute;j&amp;agrave; dans le module &lt;code&gt;Uhoh&lt;/code&gt;. Dans la vue, nous allons &amp;eacute;crire un peu de code pour parcourir les exceptions et les afficher sous forme de liste.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/views/uhoh/failures/index.html.erb&lt;/p&gt;
&lt;pre class="ruby"&gt;&amp;lt;h1&amp;gt;Failures&amp;lt;/h1&amp;gt;
&amp;lt;ul&amp;gt;
  &amp;lt;% for failure in @failures %&amp;gt;
  &amp;lt;li&amp;gt;&amp;lt;%= failure.message %&amp;gt;&amp;lt;/li&amp;gt;
  &amp;lt;% end %&amp;gt;
&amp;lt;/ul&amp;gt;&lt;/pre&gt;

&lt;p&gt;Lorsque nous rechargeons la page, nous allons voir la &lt;code&gt;Failure&lt;/code&gt; que nous avons ajout&amp;eacute;e.&lt;/p&gt;

&lt;div class="imageWrapper"&gt;
  &lt;img src="/system/photos/714/original/E277I03.png" width="801" height="280" alt="Our failure shown in the list."/&gt;
&lt;/div&gt;

&lt;h3&gt;Noter les exceptions&lt;/h3&gt;

&lt;p&gt;Maintenant que nous avons une m&amp;eacute;thode pour enregistrer une &lt;code&gt;Failure&lt;/code&gt;, nous allons devoir en g&amp;eacute;n&amp;eacute;rer une chaque fois que l&amp;#x27;application dans laquelle est mont&amp;eacute; l&amp;#x27;engine l&amp;egrave;ve une exception. Pour tester cela, nous devons simuler une exception dans l&amp;#x27;application de d&amp;eacute;monstration. Nous allons donc nous placer dans le dossier de cette derni&amp;egrave;re et g&amp;eacute;n&amp;eacute;rer un contr&amp;ocirc;leur nomm&amp;eacute; &lt;code&gt;simulate&lt;/code&gt; avec une action &lt;code&gt;failure&lt;/code&gt;.&lt;/p&gt;

&lt;pre class="terminal"&gt;$ rails g controller simulate failure&lt;/pre&gt;

&lt;p&gt;Dans l&amp;#x27;action, nous allons lever une exception.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/test/dummy/app/controllers/simulate_controller.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;class SimulateController &amp;lt; ApplicationController
  def failure
    raise &amp;quot;Simulating an exception&amp;quot;
  end
end&lt;/pre&gt;

&lt;p&gt;Si nous visitons cette action dans le navigateur, nous allons voir l&amp;#x27;exception, comme attendu.&lt;/p&gt;

&lt;div class="imageWrapper"&gt;
  &lt;img src="/system/photos/715/original/E277I04.png" width="800" height="420" alt="L'exception montr&amp;eacute;e dans le navigateur."/&gt;
&lt;/div&gt;

&lt;p&gt;Nous allons devoir changer notre engine de fa&amp;ccedil;on &amp;agrave; ce qu&amp;#x27;il note les exceptions et cr&amp;eacute;e une nouvelle &lt;code&gt;Failure&lt;/code&gt; lorsqu&amp;#x27;elles sont lev&amp;eacute;es. La solution que nous allons utiliser n&amp;#x27;est pas la plus efficace mais elle est simple et fonctionnera dans notre cas. Nous allons commencer par cr&amp;eacute;er un initializer dans notre engine. Il n&amp;#x27;y a pas de dossier &lt;code&gt;initializers&lt;/code&gt; dans le dossier config de l&amp;#x27;engine mais nous pouvons en cr&amp;eacute;er un et les initializers plac&amp;eacute;s dedans fonctionneront. Dans ce dossier, nous allons cr&amp;eacute;er un fichier nomm&amp;eacute; &lt;code&gt;exception_handler.rb&lt;/code&gt;.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/config/initializers/exception_handler.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;ActiveSupport::Notifications.subscribe &amp;crarr;
  &amp;quot;process_action.action_controller&amp;quot; do &amp;crarr;
  |name, start, finish, id, payload|
  if payload[:exception]
    name, message = *payload[:exception]
    Uhoh::Failure.create!(:message =&amp;gt; message)
  end
end&lt;/pre&gt;

&lt;p&gt;Dans ce fichier, nous souscrivons &amp;agrave; une notification (les notifications sont vues dans l&amp;#x27;&amp;eacute;pisode 249 [&lt;a href="http://railscasts.com/episodes/249-notifications-in-rails-3"&gt;regarder&lt;/a&gt;, &lt;a href="http://fr.asciicasts.com/episodes/249-notifications-in-rails-3"&gt;lire&lt;/a&gt;]) qui nous indique lorsqu&amp;#x27;une action est trait&amp;eacute;e. Lorsque c&amp;#x27;est le cas, nous pouvons v&amp;eacute;rifier si le &lt;code&gt;payload&lt;/code&gt; contient une exception. Si oui, nous savons donc qu&amp;#x27;un exception a &amp;eacute;t&amp;eacute; lev&amp;eacute;e et nous pouvons stocker son message dans une nouvelle &lt;code&gt;Failure&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Nous devons red&amp;eacute;marrer le serveur avant de tester. Nous pouvons ensuite visiter &lt;a href="http://localhost:3000/simulate/failure"&gt;&lt;code&gt;http://localhost:3000/simulate/failure&lt;/code&gt;&lt;/a&gt; de nouveau pour lever une exception. Une fois l&amp;#x27;exception vue, nous pouvons ensuite v&amp;eacute;rifier qu&amp;#x27;elle est list&amp;eacute;e en allant sur &lt;a href="http://localhost:3000/uhoh"&gt;&lt;code&gt;http://localhost:3000/uhoh&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;div class="imageWrapper"&gt;
  &lt;img src="/system/photos/716/original/E277I05.png" width="800" height="420" alt="Notre nouvelle exception affich&amp;eacute;e dans la liste."/&gt;
&lt;/div&gt;

&lt;h3&gt;G&amp;eacute;rer les URLs dans l&amp;#x27;engine&lt;/h3&gt;

&lt;p&gt;Tout helper d&amp;#x27;URL que nous utilisons dans l&amp;#x27;engine va g&amp;eacute;n&amp;eacute;rer des URLs pour cet engine. Par exemple, si nous ajoutons un lien vers l&amp;#x27;URL root depuis page &lt;code&gt;index&lt;/code&gt; des &lt;code&gt;failures&lt;/code&gt;, ce lien pointera vers l&amp;#x27;URL root de cet engine et non vers celle de l&amp;#x27;application dans laquelle il est mont&amp;eacute;.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/views/uhoh/failures/index.html.erb&lt;/p&gt;
&lt;pre class="ruby"&gt;&amp;lt;p&amp;gt;&amp;lt;%= link_to &amp;quot;Failures&amp;quot;, root_url %&amp;gt;&amp;lt;/p&amp;gt;&lt;/pre&gt;

&lt;p&gt;Ce lien pointe vers &lt;a href="http://localhost:3000/uhoh"&gt;&lt;code&gt;http://localhost:3000/uhoh&lt;/code&gt;&lt;/a&gt; qui est l&amp;#x27;URL root de l&amp;#x27;engine. C&amp;#x27;est la m&amp;ecirc;me page que celle contenant le lien car l&amp;#x27;URL root est d&amp;eacute;finie dans les routes pour pointer sur l&amp;#x27;action &lt;code&gt;index&lt;/code&gt; de &lt;code&gt;FailuresController&lt;/code&gt;. Nous pouvons cr&amp;eacute;er des liens vers l&amp;#x27;application elle-m&amp;ecirc;me en appelant le helper d&amp;#x27;URL sur &lt;code&gt;main_app&lt;/code&gt; comme ceci&amp;nbsp;:&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/views/uhoh/failures/index.html.erb&lt;/p&gt;
&lt;pre class="ruby"&gt;&amp;lt;p&amp;gt;&amp;lt;%= link_to &amp;quot;Failures&amp;quot;, root_url %&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;%= link_to &amp;quot;Simulate Failure&amp;quot;, main_app.simulate_failure_path %&amp;gt;&amp;lt;/p&amp;gt;&lt;/pre&gt;

&lt;p&gt;Cela nous donne un lien vers la page de simulation d&amp;#x27;exception de l&amp;#x27;application, &lt;a href="http://localhost:3000/simulate/failure"&gt;&lt;code&gt;http://localhost:3000/simulate/failure&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Que se passe-t-il si nous voulons faire cela dans l&amp;#x27;autre sens et avoir un lien vers l&amp;#x27;engine dans l&amp;#x27;application&amp;nbsp;? La premi&amp;egrave;re chose &amp;agrave; faire est de changer la ligne dans le fichier de routes de l&amp;#x27;application pour donner un nom &amp;agrave; la route qui monte l&amp;#x27;engine. Cela se fait avec l&amp;#x27;option &lt;code&gt;:as&lt;/code&gt;.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/test/dummy/config/routes.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;Rails.application.routes.draw do

  get &amp;quot;simulate/failure&amp;quot;

  mount Uhoh::Engine =&amp;gt; &amp;quot;/uhoh&amp;quot;, :as =&amp;gt; &amp;quot;uhoh_engine&amp;quot;
end&lt;/pre&gt;

&lt;p&gt;Nous pouvons ensuite acc&amp;eacute;der aux helpers d&amp;#x27;URLs de l&amp;#x27;engine en les appelant comme des m&amp;eacute;thodes de &lt;code&gt;uhoh_engine&lt;/code&gt;. Pour d&amp;eacute;montrer ceci, nous allons changer temporairement notre action &lt;code&gt;failure&lt;/code&gt; de fa&amp;ccedil;on &amp;agrave; ce que, au lieu de lever une exception, elle redirige vers l&amp;#x27;URL root de l&amp;#x27;engine.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/test/dummy/app/controllers/simulate_controller.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;class SimulateController &amp;lt; ApplicationController
  def failure
    redirect_to uhoh_engine.root_url
  end
end&lt;/pre&gt;

&lt;p&gt;Si nous visitons &lt;a href="http://localhost:3000/simulate/failure"&gt;&lt;code&gt;http://localhost:3000/simulate/failure&lt;/code&gt;&lt;/a&gt;, nous allons &amp;ecirc;tre redirig&amp;eacute;s vers &lt;a href="http://localhost:3000/uhoh"&gt;&lt;code&gt;http://localhost:3000/uhoh&lt;/code&gt;&lt;/a&gt; puisque nous utilisons le helper de l&amp;#x27;engine pour rediriger vers l&amp;#x27;une des ses URLs. C&amp;#x27;est une autre fonctionnalit&amp;eacute; qu&amp;#x27;il peut &amp;ecirc;tre bon de mentionner dans le README de votre engine.&lt;/p&gt;

&lt;p&gt;La fonctionnalit&amp;eacute; de notre engine est presque compl&amp;egrave;te mais la page listant les &lt;code&gt;failures&lt;/code&gt; est plut&amp;ocirc;t terne. Nous allons donc l&amp;#x27;&amp;eacute;gayer un peu en ajoutant quelques assets. Tout d&amp;#x27;abord, nous allons ajouter une image. Nous en avons d&amp;eacute;j&amp;agrave; trouv&amp;eacute; une et l&amp;#x27;avons plac&amp;eacute;e dans le dossier &lt;code&gt;/app/assets/images/uhoh&lt;/code&gt;. Pour l&amp;#x27;inclure dans la page, nous pouvons utiliser &lt;code&gt;image_tag&lt;/code&gt; comme pour n&amp;#x27;importe quelle autre image.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/views/uhoh/failures/index.html.erb&lt;/p&gt;
&lt;pre class="ruby"&gt;&amp;lt;%= image_tag &amp;quot;uhoh/alert.png&amp;quot; %&amp;gt;
&amp;lt;h1&amp;gt;Failures&amp;lt;/h1&amp;gt;
&amp;lt;ul&amp;gt;
  &amp;lt;% for failure in @failures %&amp;gt;
  &amp;lt;li&amp;gt;&amp;lt;%= failure.message %&amp;gt;&amp;lt;/li&amp;gt;
  &amp;lt;% end %&amp;gt;
&amp;lt;/ul&amp;gt;

&amp;lt;p&amp;gt;&amp;lt;%= link_to &amp;quot;Failures&amp;quot;, root_url %&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;%= link_to &amp;quot;Simulate Failure&amp;quot;, &amp;crarr;
  main_app.simulate_failure_path %&amp;gt;&amp;lt;/p&amp;gt;&lt;/pre&gt;

&lt;p&gt;Nous allons &amp;eacute;galement inclure un peu de CSS. SASS et CoffeeScript ne sont pas disponibles par d&amp;eacute;faut dans les engines, bien qu&amp;#x27;ils puissent &amp;ecirc;tre ajout&amp;eacute;s comme d&amp;eacute;pendances. Si nous ajoutons quelques CSS au fichier &lt;code&gt;failures.css&lt;/code&gt;, il sera inclus automatiquement.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/assets/stylesheets/uhoh/failures.css&lt;/p&gt;
&lt;pre class="css"&gt;html, body {
  background-color: #DDD;
  font-family: Verdana;
}

body {
  padding: 20px 200px;
}

img {
  display: block;
  margin: 0 auto;
}

a {
  color: #000;
}

ul {
  list-style: none;
  margin: 0;
  padding: 0;
}

li {
  background-color: #FFF;
  margin-bottom: 10px;
  padding: 5px 10px;
}&lt;/pre&gt;

&lt;p&gt;Ceci est &amp;eacute;galement valable pour JavaScript. Tout code plac&amp;eacute; dans le fichier &lt;code&gt;failures.js&lt;/code&gt; sera automatiquement inclus.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/assets/javascripts/uhoh/failures.js&lt;/p&gt;
&lt;pre class="javascript"&gt;$(function() {
  $(&amp;quot;li&amp;quot;).click(function() {
    $(this).slideUp();
  });
});&lt;/pre&gt;

&lt;p&gt;Lorsque nous rechargeons la page, elle sera bien mieux et nous pourrons masquer les exceptions en cliquant dessus. Cela nous montre que le JavaScript a &amp;eacute;t&amp;eacute; inclus.&lt;/p&gt;

&lt;div class="imageWrapper"&gt;
  &lt;img src="/system/photos/717/original/E277I06.png" width="799" height="436" alt="Notre page failures avec les CSS et le JavaScript inclus."/&gt;
&lt;/div&gt;

&lt;p&gt;C&amp;#x27;est tout pour cet &amp;eacute;pisode. Les mountable engines sont une tr&amp;egrave;s bonne fonctionnalit&amp;eacute; de Rails&amp;nbsp;3.1 et valent vraiment la peine d&amp;#x27;y jeter un &amp;oelig;il.&lt;/p&gt;
</description>
      <pubDate>Thu, 08 Sep 2011 21:26:06 +0000</pubDate>
      <guid>http://fr.asciicasts.com/episodes/277-mountable-engines</guid>
      <link>http://fr.asciicasts.com/episodes/277-mountable-engines</link>
    </item>
    <item>
      <title>Tester le temps et les requ&#234;tes externes</title>
      <description>&lt;p&gt;Dans l&amp;#x27;&amp;eacute;pisode pr&amp;eacute;c&amp;eacute;dent, nous avons montr&amp;eacute; un workflow de d&amp;eacute;veloppement dirig&amp;eacute; par les tests. En majeure partie, le mod&amp;egrave;le utilis&amp;eacute; fonctionne bien mais il peut arriver que certaines fonctionnalit&amp;eacute;s de notre application soient difficiles &amp;agrave; tester. Nous allons voir deux sc&amp;eacute;narios de ce type dans cet &amp;eacute;pisode.&lt;/p&gt;

&lt;h3&gt;Tester le temps actuel&lt;/h3&gt;

&lt;p&gt;La derni&amp;egrave;re fois, nous avons cr&amp;eacute;&amp;eacute; un certain nombre de specs pour tester le mod&amp;egrave;le &lt;code&gt;User&lt;/code&gt;. Nous les avons &amp;eacute;crites assez rapidement et nous allons maintenant revenir sur l&amp;#x27;une d&amp;#x27;elles et nous attarder quelque peu dessus.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/spec/models/user.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;it &amp;quot;saves the time the password reset was sent&amp;quot; do
  user.send_password_reset
  user.reload.password_reset_sent_at.should be_present
end&lt;/pre&gt;

&lt;p&gt;Cette spec v&amp;eacute;rifie que, lorsqu&amp;#x27;une demande de r&amp;eacute;initialisation de mot de passe est envoy&amp;eacute;e, le moment de l&amp;#x27;envoi est stock&amp;eacute; dans le champ &lt;code&gt;password_reset_sent_at&lt;/code&gt;. Ceci est test&amp;eacute; gr&amp;acirc;ce au matcher &lt;code&gt;be_present&lt;/code&gt; de RSpec. Ce matcher appelle une m&amp;eacute;thode, fournie par Rails, nomm&amp;eacute;e &lt;code&gt;present?&lt;/code&gt; qui v&amp;eacute;rifie l&amp;#x27;existence d&amp;#x27;un objet.&lt;/p&gt;

&lt;p&gt;Cette spec est incompl&amp;egrave;te&amp;nbsp;: elle v&amp;eacute;rifie qu&amp;#x27;une valeur existe pour &lt;code&gt;password_reset_sent_at&lt;/code&gt; mais ne s&amp;#x27;assure pas que cette valeur est le temps actuel. Nous renseignons bien &lt;code&gt;password_reset_sent_at&lt;/code&gt; &amp;agrave; &lt;code&gt;Time.zone.now&lt;/code&gt;, dans la m&amp;eacute;thode &lt;code&gt;send_password_reset&lt;/code&gt; du mod&amp;egrave;le &lt;code&gt;User&lt;/code&gt;, mais la spec passerait, peu importe la valeur renseign&amp;eacute;e. Id&amp;eacute;alement, nous devrions tester que la valeur est la date actuelle en &amp;eacute;crivant quelque chose comme ceci&amp;nbsp;:&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/spec/models/user.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;it &amp;quot;saves the time the password reset was sent&amp;quot; do
  user.send_password_reset
  user.reload.password_reset_sent_at.should eq(Time.zone.now)
end&lt;/pre&gt;

&lt;p&gt;Malheureusement cela ne peut pas fonctionner. Le temps actuel, au moment du test, sera l&amp;eacute;g&amp;egrave;rement apr&amp;egrave;s le moment ou le code test&amp;eacute; est ex&amp;eacute;cut&amp;eacute;. Lorsque l&amp;#x27;on est face &amp;agrave; un probl&amp;egrave;me comme celui-ci, cela vaut la peine de se poser la question de l&amp;#x27;utilit&amp;eacute; d&amp;#x27;ajouter une certaine complexit&amp;eacute; aux tests afin qu&amp;#x27;ils soient complets. Dans de nombreux cas, comme celui-ci, il est suffisant de tester que la valeur du timestamp existe. Il y a peu de chances qu&amp;#x27;un bug ait lieu dans une ligne de code qui renseigne le temps mais il peut arriver que nous ayons besoin de tester le temps actuel. Regardons donc comment nous pourrions le faire dans les specs.&lt;/p&gt;

&lt;p&gt;Guard tourne et nous pouvons voir que notre spec &amp;eacute;choue. Bien que le timestamp soient tr&amp;egrave;s proches en terme de secondes, ils ne sont pas identiques et cela suffit &amp;agrave; causer l&amp;#x27;&amp;eacute;chec de la spec.&lt;/p&gt;

&lt;pre class="terminal"&gt;Failures:

  1) User#send_password_reset saves the time the password reset was sent
     Failure/Error: user.reload.password_reset_sent_at.should eq(Time.zone.now)

       expected Mon, 25 Jul 2011 20:34:46 UTC +00:00
            got Mon, 25 Jul 2011 20:34:46 UTC +00:00

       (compared using ==)

       Diff:
     # ./spec/models/user_spec.rb:16:in `block (3 levels) in &amp;lt;top (required)&amp;gt;&amp;#x27;

Finished in 1.95 seconds
9 examples, 1 failure&lt;/pre&gt;

&lt;p&gt;Nous pouvons g&amp;eacute;rer ce genre de probl&amp;egrave;mes en utilisant une gem nomm&amp;eacute;e &lt;a href="https://github.com/jtrupiano/timecop/"&gt;Timecop&lt;/a&gt;. Nous pouvons l&amp;#x27;utiliser pour manipuler le temps actuel de plusieurs fa&amp;ccedil;ons, y compris en le gelant. Cela signifie que nous pouvons geler le temps actuel durant le fonctionnement de la spec afin que le moment auquel le timestamp est renseign&amp;eacute; soit exactement le m&amp;ecirc;me que lors du test.&lt;/p&gt;

&lt;p&gt;Nous pouvons ajouter Timecop &amp;agrave; notre application en l&amp;#x27;ajoutant dans le &lt;code&gt;Gemfile&lt;/code&gt; et en lan&amp;ccedil;ant &lt;code&gt;bundle&lt;/code&gt;. Puisque nous en avons seulement besoin pour nos tests, nous le pla&amp;ccedil;ons dans le groupe &lt;code&gt;test&lt;/code&gt;.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/Gemfile&lt;/p&gt;
&lt;pre class="ruby"&gt;source &amp;#x27;http://rubygems.org&amp;#x27;

gem &amp;#x27;rails&amp;#x27;, &amp;#x27;3.1.0.rc4&amp;#x27;

gem &amp;#x27;sqlite3&amp;#x27;

# Asset template engines
gem &amp;#x27;sass-rails&amp;#x27;, &amp;quot;~&amp;gt; 3.1.0.rc&amp;quot;
gem &amp;#x27;coffee-script&amp;#x27;
gem &amp;#x27;uglifier&amp;#x27;

gem &amp;#x27;jquery-rails&amp;#x27;

gem &amp;quot;rspec-rails&amp;quot;, :group =&amp;gt; [:test, :development]
group :test do
  gem &amp;quot;factory_girl_rails&amp;quot;
  gem &amp;quot;capybara&amp;quot;
  gem &amp;quot;guard-rspec&amp;quot;
  gem &amp;quot;timecop&amp;quot;
end&lt;/pre&gt;

&lt;p&gt;Il est maintenant temps d&amp;#x27;aller dans le fichier &lt;code&gt;spec_helper.rb&lt;/code&gt; et d&amp;#x27;ajouter un appel &amp;agrave; &lt;code&gt;Timecop.return&lt;/code&gt; dans le bloc &lt;code&gt;config.before(:each)&lt;/code&gt;. Cela assure le fait que tout changement effectu&amp;eacute; avec Timecop est annul&amp;eacute; avant le lancement de chaque spec.&lt;/p&gt;

&lt;p&gt;Nous pouvons appeler &lt;code&gt;Timecop.freeze&lt;/code&gt; dans n&amp;#x27;importe quelle spec et geler le temps durant l&amp;#x27;ex&amp;eacute;cution de cette derni&amp;egrave;re. Cela signifie que nous pouvons comparer les deux timestamps.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/spec/models/user.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;it &amp;quot;saves the time the password reset was sent&amp;quot; do
  Timecop.freeze
  user.send_password_reset
  user.reload.password_reset_sent_at.should eq(Time.zone.now)
end&lt;/pre&gt;

&lt;p&gt;&amp;Agrave; pr&amp;eacute;sent, lorsque Guard lance les specs, elles passent toutes.&lt;/p&gt;

&lt;p&gt;Il y a un autre sc&amp;eacute;nario inattendu qui peut causer l&amp;#x27;&amp;eacute;chec des tests. Si vous assistez &amp;agrave; une conf&amp;eacute;rence sur Ruby dans un autre fuseau horaire, vous pouvez vous retrouver avec un &amp;eacute;chec de vos tests relatifs au temps. Au lieu de parcourir la moiti&amp;eacute; du monde, il est bien moins co&amp;ucirc;teux de r&amp;eacute;gler le fuseau horaire dans les specs. Cela se fait en r&amp;eacute;glant &lt;code&gt;Time.zone&lt;/code&gt;&amp;nbsp;:&lt;/p&gt;

&lt;pre class="terminal"&gt;Time.zone = &amp;quot;Paris&amp;quot;&lt;/pre&gt;

&lt;p&gt;Pour r&amp;eacute;gler temporairement le fuseau, pour une seule spec, nous pouvons appeler &lt;code&gt;Time.use_zone&lt;/code&gt;.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/spec/model/user_spec.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;it &amp;quot;saves the time the password reset was sent&amp;quot; do
  Timecop.freeze
  user.send_password_reset
  Time.use_zone(&amp;quot;Paris&amp;quot;) do
    user.reload.password_reset_sent_at.should eq(Time.zone.now)
  end
end&lt;/pre&gt;

&lt;p&gt;Le code &amp;agrave; l&amp;#x27;int&amp;eacute;rieur du bloc sera lanc&amp;eacute; comme si nous &amp;eacute;tions &amp;agrave; Paris. Nous pouvons utiliser cela pour tester que nos specs passent toujours, m&amp;ecirc;me si nous somme dans un autre fuseau horaire.&lt;/p&gt;

&lt;p&gt;Chaque fois que nous testons de temps actuel, nous devrions utiliser quelque chose comme Timecop de fa&amp;ccedil;on &amp;agrave; ce que le temps puisse &amp;ecirc;tre mani&amp;eacute; de mani&amp;egrave;re consistante et ne change pas lors d&amp;#x27;un changement de fuseau horaire ou d&amp;#x27;un passage &amp;agrave; l&amp;#x27;heure d&amp;#x27;&amp;eacute;t&amp;eacute;. Nous devrions &amp;eacute;galement l&amp;#x27;utiliser pour tester notre code dans diff&amp;eacute;rents fuseaux horaire afin de v&amp;eacute;rifier que notre application fonctionne mondialement.&lt;/p&gt;

&lt;h3&gt;Tester les requ&amp;ecirc;tes web externes&lt;/h3&gt;

&lt;p&gt;Nous allons jeter un oeil au test des requ&amp;ecirc;tes web externes. Cette section est bas&amp;eacute;e sur un probl&amp;egrave;me que Ryan Bates a rencontr&amp;eacute; lors de la r&amp;eacute;&amp;eacute;criture du site de Railscasts, en particulier la fonctionnalit&amp;eacute; qui affiche la taille des fichiers pour chaque format vid&amp;eacute;o lorsque vous passez sur le lien t&amp;eacute;l&amp;eacute;charger.&lt;/p&gt;

&lt;div class="imageWrapper"&gt;
  &lt;img src="/system/photos/708/original/E276I01.png" width="798" height="411" alt="La taille du fichier est affich&amp;eacute;e pour chaque format vid&amp;eacute;o."/&gt;
&lt;/div&gt;

&lt;p&gt;La taille du fichier est r&amp;eacute;cup&amp;eacute;r&amp;eacute;e depuis un serveur web externe puisque les fichiers m&amp;eacute;dia sont stock&amp;eacute;s sur un serveur &amp;agrave; part. Cela signifie qu&amp;#x27;une requ&amp;ecirc;te web externe est effectu&amp;eacute;e et nous allons maintenant montrer comment cela a &amp;eacute;t&amp;eacute; test&amp;eacute;. Nous allons le faire gr&amp;acirc;ce &amp;agrave; une petite application d&amp;#x27;exemple. Elle a une ressource WebRequest et un formulaire contenant un champ texte qui attend une URL.&lt;/p&gt;

&lt;div class="imageWrapper"&gt;
  &lt;img src="/system/photos/709/original/E276I02.png" width="800" height="322" alt="Notre application de requ&amp;ecirc;te web."/&gt;
&lt;/div&gt;

&lt;p&gt;Lorsque nous saisissons l&amp;#x27;URL d&amp;#x27;une vid&amp;eacute;o dans le champs texte et soumettons le formulaire, l&amp;#x27;URL est affich&amp;eacute;e ainsi que la taille du fichier indiquant z&amp;eacute;ro octet.&lt;/p&gt;

&lt;div class="imageWrapper"&gt;
  &lt;img src="/system/photos/710/original/E276I03.png" width="800" height="322" alt="La taille du fichier indique toujours z&amp;eacute;ro octet."/&gt;
&lt;/div&gt;

&lt;p&gt;La taille du fichier est z&amp;eacute;ro puisque nous n&amp;#x27;avons pas encore impl&amp;eacute;ment&amp;eacute; cette fonctionnalit&amp;eacute;. Nous avons, dans notre mod&amp;egrave;le &lt;code&gt;WebRequest&lt;/code&gt;, une m&amp;eacute;thode &lt;code&gt;content_length&lt;/code&gt; mais cette m&amp;eacute;thode est cod&amp;eacute;e en dur pour retourner &lt;code&gt;0&lt;/code&gt;. Nous allons maintenant l&amp;#x27;impl&amp;eacute;menter en utilisant le TDD (d&amp;eacute;veloppement dirig&amp;eacute; par les tests).&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/models/web_request.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;class WebRequest &amp;lt; ActiveRecord::Base
  def content_length
    0
  end
end&lt;/pre&gt;

&lt;p&gt;Il existe un certain nombre de gems aidant au test des requ&amp;ecirc;tes web externes mais nous allons utiliser &lt;a href="https://github.com/chrisk/fakeweb"&gt;Fakeweb&lt;/a&gt;. Cette gem peut &amp;ecirc;tre utilis&amp;eacute;e pour enregistrer une URI et d&amp;eacute;finir ce que sa r&amp;eacute;ponse doit &amp;ecirc;tre. Lorsque nous utilisons &lt;code&gt;Net::HTTP&lt;/code&gt; pour r&amp;eacute;cup&amp;eacute;rer cette URI, elle va, &amp;agrave; la place, retourner cette r&amp;eacute;ponse plut&amp;ocirc;t que faire une requ&amp;ecirc;te externe.&lt;/p&gt;

&lt;p&gt;Fakeweb est install&amp;eacute;, comme d&amp;#x27;habitude, en l&amp;#x27;ajoutant dans le &lt;code&gt;Gemfile&lt;/code&gt; et en appelant &lt;code&gt;bundle&lt;/code&gt;. Nous allons ensuite ajouter une configuration pour Fakeweb en effectuant deux modifications dans le fichier &lt;code&gt;spec_helper.rb&lt;/code&gt;.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/spec/spec_helper.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;ENV[&amp;quot;RAILS_ENV&amp;quot;] ||= &amp;#x27;test&amp;#x27;
require File.expand_path(&amp;quot;../../config/environment&amp;quot;, __FILE__)
require &amp;#x27;rspec/rails&amp;#x27;
require &amp;#x27;capybara/rspec&amp;#x27;

Dir[Rails.root.join(&amp;quot;spec/support/**/*.rb&amp;quot;)].each {|f| require f}

FakeWeb.allow_net_connect = false

RSpec.configure do |config|
  config.mock_with :rspec
  config.use_transactional_fixtures = true
  config.include(MailerMacros)
  config.before(:each) do
    Timecop.return
    reset_email
    FakeWeb.clean_registry
  end
end&lt;/pre&gt;

&lt;p&gt;Pr&amp;egrave;s du d&amp;eacute;but du fichier, nous renseignons &lt;code&gt;Fakeweb.allow_net_connect&lt;/code&gt; &amp;agrave; &lt;code&gt;false&lt;/code&gt; ce qui va emp&amp;ecirc;cher les specs d&amp;#x27;effectuer des connexion HTTP externes. Cela permet de faire en sorte que, si nous avons oubli&amp;eacute; des requ&amp;ecirc;tes externes dans nos specs, elles ne ralentiront pas la totalit&amp;eacute; de la suite de tests et Fakeweb nous fera savoir que les specs tentent de se connecter au web. Dans &lt;code&gt;before(:each)&lt;/code&gt;, nous appelons &lt;code&gt;Fakeweb.clean_registry&lt;/code&gt; afin que chaque spec d&amp;eacute;marre dans le m&amp;ecirc;me &amp;eacute;tat.&lt;/p&gt;

&lt;p&gt;Dans les specs pour &lt;code&gt;WebRequest&lt;/code&gt;, nous allons &amp;eacute;crire une spec qui va v&amp;eacute;rifier que le contenu est r&amp;eacute;cup&amp;eacute;r&amp;eacute;.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/spec/models/web_request_spec.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;require &amp;#x27;spec_helper&amp;#x27;

describe WebRequest do
  it &amp;quot;fetches the content length&amp;quot; do
    FakeWeb.register_uri(:head, &amp;quot;http://example.com&amp;quot;, :content_length =&amp;gt; 123)
    WebRequest.new(:url =&amp;gt; &amp;quot;http://example.com&amp;quot;).content_length.should eq(123)
  end
end&lt;/pre&gt;

&lt;p&gt;Nous appelons &lt;code&gt;FakeWeb.register_uri&lt;/code&gt; pour enregistrer une fausse URL. Le premier argument de cette m&amp;eacute;thode est le type de requ&amp;ecirc;te que nous voulons faire, nous pouvons obtenir la taille du fichier depuis les informations d&amp;#x27;en-t&amp;ecirc;te, nous utilisons donc &lt;code&gt;:head&lt;/code&gt;. Les autres arguments sont l&amp;#x27;URL et les en-t&amp;ecirc;tes de notre choix. Dans notre cas, la longueur du contenu (Content Length). Nous cr&amp;eacute;ons ensuite un nouvel objet &lt;code&gt;WebRequest&lt;/code&gt; qui appelle cette URL et v&amp;eacute;rifions que la valeur retourn&amp;eacute;e par la m&amp;eacute;thode &lt;code&gt;content_length&lt;/code&gt; est &amp;eacute;gale &amp;agrave; la valeur saisie dans l&amp;#x27;en-t&amp;ecirc;te.&lt;/p&gt;

&lt;p&gt;Bien s&amp;ucirc;r, lorsque nous lan&amp;ccedil;ons la spec, elle &amp;eacute;choue puisque notre m&amp;eacute;thode &lt;code&gt;content_length&lt;/code&gt; retourne toujours &lt;code&gt;0&lt;/code&gt;. Pour faire passer la spec, nous devons modifier cette m&amp;eacute;thode afin qu&amp;#x27;elle retourne la vraie valeur du content length pour le fichier demand&amp;eacute;.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/models/web_request.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;class WebRequest &amp;lt; ActiveRecord::Base
  def content_length
    uri = URI.parse(url)
    response = Net::HTTP.start(uri.host, uri.port) { |http| http.request_head(uri.path) }
    response[&amp;quot;content-length&amp;quot;].to_i
  end
end&lt;/pre&gt;

&lt;p&gt;La m&amp;eacute;thode appelle maintenant &lt;code&gt;Net::HTTP.start&lt;/code&gt; en utilisant l&amp;#x27;URL pass&amp;eacute;e au mod&amp;egrave;le. Le bloc pass&amp;eacute; appelle &lt;code&gt;request_head&lt;/code&gt; pou r&amp;eacute;cup&amp;eacute;rer l&amp;#x27;en-t&amp;ecirc;te de la r&amp;eacute;ponse. Enfin, elle retourne la valeur de l&amp;#x27;en-t&amp;ecirc;te &lt;code&gt;content-length&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Rails n&amp;#x27;inclue pas &lt;code&gt;Net::HTTP&lt;/code&gt; par d&amp;eacute;faut, nous devons donc ajouter un &lt;code&gt;require&lt;/code&gt; dans notre application. Nous allons de le faire dans le fichier &lt;code&gt;application.rb&lt;/code&gt;.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/config/auth.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;require File.expand_path(&amp;#x27;../boot&amp;#x27;, __FILE__)

require &amp;#x27;net/http&amp;#x27;
require &amp;#x27;rails/all&amp;#x27;
# rest of file&lt;/pre&gt;

&lt;p&gt;Toutes nos specs passent &amp;agrave; pr&amp;eacute;sent et, lorsque nous rechargeons la page de notre requ&amp;ecirc;te, la bonne taille de fichier est affich&amp;eacute;e.&lt;/p&gt;

&lt;div class="imageWrapper"&gt;
  &lt;img src="/system/photos/711/original/E276I04.png" width="800" height="322" alt="La bonne taille de fichier est affich&amp;eacute;e."/&gt;
&lt;/div&gt;

&lt;p&gt;Si jamais vous avez besoin de g&amp;eacute;rer des requ&amp;ecirc;tes web externes dans vos tests, Fakeweb est une tr&amp;egrave;s bonne solution.&lt;/p&gt;</description>
      <pubDate>Sun, 21 Aug 2011 22:07:47 +0000</pubDate>
      <guid>http://fr.asciicasts.com/episodes/276-tester-le-temps-et-les-requetes-externes</guid>
      <link>http://fr.asciicasts.com/episodes/276-tester-le-temps-et-les-requetes-externes</link>
    </item>
    <item>
      <title>Comment nous testons</title>
      <description>&lt;p&gt;&amp;Agrave; partir de cet &amp;eacute;pisode, nous verrons plus souvent le sujet des tests. Cette fois-ci, nous allons montrer comment nous aurions &amp;eacute;crit les tests pour l&amp;#x27;&amp;eacute;pisode pr&amp;eacute;c&amp;eacute;dent [&lt;a href="http : //railscasts.com/episodes/274-remember-me-reset-password"&gt;regarder&lt;/a&gt;, &lt;a href="http://fr.asciicasts.com/episodes/274-remember-me-reset-password"&gt;lire&lt;/a&gt;], plus sp&amp;eacute;cifiquement, le lien &amp;ldquo;forgotten password&amp;rdquo; (mot de passe oubli&amp;eacute;) que nous avons ajout&amp;eacute; au formulaire de connexion.&lt;/p&gt;

&lt;p&gt;Lorsque nous avons commenc&amp;eacute; le dernier &amp;eacute;pisode, nous avions une application avec un formulaire de connexion. L&amp;#x27;application avait un syst&amp;egrave;me d&amp;#x27;authentification assez simple et un formulaire de connexion mais pas de checkbox &amp;ldquo;remember me&amp;rdquo; (se souvenir de moi) ou de lien &amp;ldquo;forgotten password&amp;rdquo; (mot de passe oubli&amp;eacute;). Nous les avons donc ajout&amp;eacute;s. Nous allons de nouveau ajouter le lien mais cette fois, nous allons le faire gr&amp;acirc;ce au Test Driven Development (TDD, D&amp;eacute;veloppement Dirig&amp;eacute; par les Tests).&lt;/p&gt;

&lt;div class="imageWrapper"&gt;
  &lt;img src="/system/photos/707/original/E275I01.png" width="800" height="369" alt="La page de connexion."/&gt;
&lt;/div&gt;

&lt;p&gt;La derni&amp;egrave;re fois, nous avons test&amp;eacute; l&amp;#x27;application dans le navigateur. Cette fois, nous garderons le navigateur ferm&amp;eacute; et &amp;eacute;crirons du code pour tester la fonctionnalit&amp;eacute;. Nous l&amp;#x27;ouvrirons seulement lorsque nous aurons besoin de nous concentrer sur l&amp;#x27;exp&amp;eacute;rience utilisateur.&lt;/p&gt;

&lt;p&gt;Pour nous aider &amp;agrave; &amp;eacute;crire nos tests, nous devons ajouter quelques gems relatives aux tests dans le &lt;code&gt;Gemfile&lt;/code&gt; de notre application. Nous utilisons Rails&amp;nbsp;3.1 mais tout ce que nous allons faire fonctionnera sous Rails&amp;nbsp;3.0.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/Gemfile&lt;/p&gt;
&lt;pre class="ruby"&gt;source &amp;#x27;http://rubygems.org&amp;#x27;

gem &amp;#x27;rails&amp;#x27;, &amp;#x27;3.1.0.rc4&amp;#x27;

gem &amp;#x27;sqlite3&amp;#x27;

# Asset template engines
gem &amp;#x27;sass-rails&amp;#x27;, &amp;quot;~&amp;gt; 3.1.0.rc&amp;quot;
gem &amp;#x27;coffee-script&amp;#x27;
gem &amp;#x27;uglifier&amp;#x27;

gem &amp;#x27;jquery-rails&amp;#x27;

gem &amp;quot;rspec-rails&amp;quot;, :group =&amp;gt; [:test, :development]
group :test do
  gem &amp;quot;factory_girl_rails&amp;quot;
  gem &amp;quot;capybara&amp;quot;
  gem &amp;quot;guard-rspec&amp;quot;
end&lt;/pre&gt;

&lt;p&gt;Nous utilisons &lt;a href="http://relishapp.com/rspec"&gt;RSpec&lt;/a&gt; mais n&amp;#x27;importe quel framework de test ferait l&amp;#x27;affaire. Notez que, contrairement aux autres gems de test, RSpec est &amp;eacute;galement dans le groupe &lt;code&gt;development&lt;/code&gt; de fa&amp;ccedil;on &amp;agrave; ce que ses t&amp;acirc;ches Rake fonctionnent correctement. Nous avons aussi choisi d&amp;#x27;utiliser &lt;a href="https://github.com/thoughtbot/factory_girl"&gt;Factory Girl&lt;/a&gt; plut&amp;ocirc;t que les fixtures, &lt;a href="https://github.com/jnicklas/capybara"&gt;Capybara&lt;/a&gt; pour simuler les interactions du navigateur et &lt;a href="https://github.com/guard/guard"&gt;Guard&lt;/a&gt; pour lancer les tests automatiquement. Chacune de ces gems a &amp;eacute;t&amp;eacute; vue dans un &amp;eacute;pisode pr&amp;eacute;c&amp;eacute;dent&amp;nbsp;: Factory Girl &amp;eacute;tait abord&amp;eacute;e dans l&amp;#x27;&amp;eacute;pisode 158 [&lt;a href="http://railscasts.com/episodes/158-factories-not-fixtures"&gt;regarder&lt;/a&gt;, &lt;a href="http://fr.asciicasts.com/episodes/158-factories-not-fixtures"&gt;lire&lt;/a&gt;], Capybara dans l&amp;#x27;&amp;eacute;pisode 257 [&lt;a href="http://railscasts.com/episodes/257-request-specs-and-capybara"&gt;regarder&lt;/a&gt;, &lt;a href="http://fr.asciicasts.com/episodes/257-request-specs-and-capybara"&gt;lire&lt;/a&gt;] et Guard dans l&amp;#x27;&amp;eacute;pisode 264 [&lt;a href="http://railscasts.com/episodes/264-guard"&gt;regarder&lt;/a&gt;, &lt;a href="http://fr.asciicasts.com/episodes/264-guard"&gt;lire&lt;/a&gt;].&lt;/p&gt;

&lt;p&gt;Nous pouvons installer les gems gr&amp;acirc;ce &amp;agrave; la commande &lt;code&gt;bundle&lt;/code&gt;. Une fois cela fait, nous allons configurer RSpec en lan&amp;ccedil;ant&lt;/p&gt;

&lt;pre class="terminal"&gt;$ rails g rspec:install&lt;/pre&gt;

&lt;p&gt;Nous allons cr&amp;eacute;er quelques dossiers dans celui nomm&amp;eacute; &lt;code&gt;/rspec&lt;/code&gt;&amp;nbsp;: un dossier &lt;code&gt;support&lt;/code&gt; pour les fichiers de support ainsi qu&amp;#x27;un dossier &lt;code&gt;models&lt;/code&gt; et un dossier &lt;code&gt;routing&lt;/code&gt; qui sont requis par Guard.&lt;/p&gt;

&lt;pre class="terminal"&gt;$ mkdir spec/support spec/models spec/routing&lt;/pre&gt;

&lt;p&gt;Il est &amp;eacute;galement temps de lancer l&amp;#x27;initialiseur de Guard.&lt;/p&gt;

&lt;pre class="terminal"&gt;$ guard init rspec&lt;/pre&gt;

&lt;p&gt;Puisque nous d&amp;eacute;veloppons sous OS&amp;nbsp;X, nous devons installer la gem &lt;a href="https://rubygems.org/gems/rb-fsevent"&gt;&lt;code&gt;rb-fsevent&lt;/code&gt;&lt;/a&gt; de fa&amp;ccedil;on &amp;agrave; ce que Guard puisse d&amp;eacute;tecter les changements de fichiers. Une fois cela fait, nous allons lancer Guard dans un nouvel onglet de Terminal et le garder actif en arri&amp;egrave;re-plan.&lt;/p&gt;

&lt;pre class="terminal"&gt;$ guard
Please install growl gem for Mac OS X notification support and add it to your Gemfile

Guard is now watching at &amp;#x27;/Users/eifion/auth&amp;#x27;
Guard::RSpec is running, with RSpec 2!
Running all specs
No examples found.&lt;/pre&gt;

&lt;p&gt;Lorsque nous avons lanc&amp;eacute; le g&amp;eacute;n&amp;eacute;rateur RSpec, il a cr&amp;eacute;&amp;eacute; un fichier &lt;code&gt;/spec/spec_helper.rb&lt;/code&gt;. Nous devons activer Capybara dans ce fichier. Pour ce faire, nous allons ajouter une ligne &lt;code&gt;require &amp;#x27;capybara/spec&amp;#x27;&lt;/code&gt;.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/spec/spec_helper.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;# This file is copied to spec/ when you run &amp;#x27;rails generate rspec:install&amp;#x27;
ENV[&amp;quot;RAILS_ENV&amp;quot;] ||= &amp;#x27;test&amp;#x27;
require File.expand_path(&amp;quot;../../config/environment&amp;quot;, __FILE__)
require &amp;#x27;rspec/rails&amp;#x27;
require &amp;#x27;capybara/rspec&amp;#x27;
# rest of file...&lt;/pre&gt;

&lt;p&gt;Nous allons &amp;eacute;galement suivre le conseil donn&amp;eacute; dans les commentaires du fichier et retirer la ligne contenant le chemin vers les fixtures puisque nous n&amp;#x27;allons pas les utiliser.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/spec/spec_helper.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;# Remove this line if you&amp;#x27;re not using ActiveRecord or &amp;crarr;
  ActiveRecord fixtures
config.fixture_path = &amp;quot;#{::Rails.root}/spec/fixtures&amp;quot;&lt;/pre&gt;

&lt;h3&gt;Notre premier test&lt;/h3&gt;

&lt;p&gt;Nous sommes maintenant par&amp;eacute;s pour commencer nos tests et nous allons d&amp;eacute;marrer avec un test d&amp;#x27;int&amp;eacute;gration que nous allons appeler &lt;code&gt;password_reset&lt;/code&gt;.&lt;/p&gt;

&lt;pre class="terminal"&gt;$ rails g integration_test password_reset&lt;/pre&gt;

&lt;p&gt;Le g&amp;eacute;n&amp;eacute;rateur RSpec va prendre la main et cr&amp;eacute;er ce que l&amp;#x27;on appelle une request spec (sp&amp;eacute;cification de requ&amp;ecirc;te). Le code par d&amp;eacute;faut dans la spec ressemble &amp;agrave; ceci&amp;nbsp;:&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/spec/requests/password_resets_spec.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;require &amp;#x27;spec_helper&amp;#x27;

describe &amp;quot;PasswordResets&amp;quot; do
  describe &amp;quot;GET /password_resets&amp;quot; do
    it &amp;quot;works! (now write some real specs)&amp;quot; do
      # Run the generator again with the --webrat flag if you want to use webrat methods/matchers
      get password_resets_path
      response.status.should be(200)
    end
  end
end&lt;/pre&gt;

&lt;p&gt;Nous allons retirer la spec par d&amp;eacute;faut et la remplacer par la n&amp;ocirc;tre et tester qu&amp;#x27;un e-mail est envoy&amp;eacute; &amp;agrave; un utilisateur lorsqu&amp;#x27;il demande une r&amp;eacute;initialisation de son mot de passe. Nous aurons besoin d&amp;#x27;un enregistrement &lt;code&gt;User&lt;/code&gt; avec lequel travailler. Nous pourrions passer par la page d&amp;#x27;inscription et enregistrer notre utilisateur mais il est pr&amp;eacute;f&amp;eacute;rable de se concentrer uniquement sur ce que nous voulons tester. Nous allons donc utiliser une factory (fabrique). Avant de commencer nos tests, nous allons cr&amp;eacute;er, dans le fichier &lt;code&gt;factories.rb&lt;/code&gt; du dossier &lt;code&gt;/spec&lt;/code&gt;, une factory pour le mod&amp;egrave;le &lt;code&gt;User&lt;/code&gt;. Ce nom et cet emplacement signifient que toutes les factories que nous allons d&amp;eacute;finir dedans seront automatiquement charg&amp;eacute;es par Factory Girl.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/spec/factories.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;Factory.define :user do |f|
  f.sequence(:email) { |n| &amp;quot;foo#{n}@example.com&amp;quot; }
  f.password &amp;quot;secret&amp;quot;
end&lt;/pre&gt;

&lt;p&gt;Cette factory est simple et va g&amp;eacute;n&amp;eacute;rer un utilisateur avec une adresse e-mail et un mot de passe uniques. Nous allons maintenant l&amp;#x27;utiliser pour nos tests.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/spec/requests/password_resets_spec.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;require &amp;#x27;spec_helper&amp;#x27;

describe &amp;quot;PasswordResets&amp;quot; do
  it &amp;quot;emails user when requesting password reset&amp;quot;
    user = Factory(:user)
    visit login_path
    click_link &amp;quot;password&amp;quot;
    fill_in &amp;quot;Email&amp;quot;, :with =&amp;gt; user.email
    click_button &amp;quot;Reset Password&amp;quot;
  end
end&lt;/pre&gt;

&lt;p&gt;Ce test utilise notre factory pour cr&amp;eacute;er un utilisateur et simule ensuite, gr&amp;acirc;ce &amp;agrave; quelques commandes Capybara, les &amp;eacute;tapes par lesquelles un utilisateur passerait pour r&amp;eacute;initialiser son mot de passe. Nous visitons la page de connexion et cliquons sur le lien contenant &amp;#x27;mot de passe&amp;#x27;. En ne d&amp;eacute;finissant pas pr&amp;eacute;cis&amp;eacute;ment le texte du lien, nos tests sont moins fig&amp;eacute;s, si le texte du lien passe, par exemple, de &amp;#x27;Mot de passe oubli&amp;eacute; ?&amp;#x27; &amp;agrave; &amp;#x27;Vous avez oubli&amp;eacute; votre mot de passe ?&amp;#x27;, ils fonctionneront toujours. Sur la page &amp;agrave; laquelle nous m&amp;egrave;ne le lien, nous trouvons un champ texte associ&amp;eacute; &amp;agrave; un label dont le texte contient &amp;#x27;Email&amp;#x27; et saisissons comme valeur l&amp;#x27;e-mail de l&amp;#x27;utilisateur. Enfin, nous cliquons sur le bouton &amp;#x27;R&amp;eacute;initialiser mot de passe&amp;#x27;.&lt;/p&gt;

&lt;p&gt;Notre spec n&amp;#x27;est pas encore termin&amp;eacute;e mais lorsque nous la sauvegardons, Guard va la lancer et nous allons voir notre premier &amp;eacute;chec.&lt;/p&gt;

&lt;pre class="terminal"&gt;  1) PasswordResets emails user when requesting password reset
     Failure/Error: click_link &amp;quot;password&amp;quot;
     Capybara::ElementNotFound:
       no link with title, id or text &amp;#x27;password&amp;#x27; found
     # (eval):2:in `click_link&amp;#x27;
     # ./spec/requests/password_resets_spec.rb:7:in `block (2 levels) in &amp;lt;top (required)&amp;gt;&amp;#x27;&lt;/pre&gt;

&lt;p&gt;La spec &amp;eacute;choue car Capybara ne trouve pas le lien &amp;#x27;mot de passe&amp;#x27;. Nous allons corriger ceci avant de continuer. Tout ce que nous devons faire, c&amp;#x27;est ajouter le lien &amp;agrave; la page de connexion.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/views/sessions/new.html.erb&lt;/p&gt;
&lt;pre class="ruby"&gt;&amp;lt;h1&amp;gt;Log in&amp;lt;/h1&amp;gt;

&amp;lt;%= form_tag sessions_path do %&amp;gt;
  &amp;lt;div class=&amp;quot;field&amp;quot;&amp;gt;
    &amp;lt;%= label_tag :email %&amp;gt;
    &amp;lt;%= text_field_tag :email, params[:email] %&amp;gt;
  &amp;lt;/div&amp;gt;
  &amp;lt;div class=&amp;quot;field&amp;quot;&amp;gt;
    &amp;lt;%= label_tag :password %&amp;gt;
    &amp;lt;%= password_field_tag :password %&amp;gt;
  &amp;lt;/div&amp;gt;
  &amp;lt;p&amp;gt;&amp;lt;%= link_to &amp;quot;forgotten password?&amp;quot;, new_password_reset_path %&amp;gt;
  &amp;lt;div class=&amp;quot;actions&amp;quot;&amp;gt;&amp;lt;%= submit_tag &amp;quot;Log in&amp;quot; %&amp;gt;&amp;lt;/div&amp;gt;
&amp;lt;% end %&amp;gt;&lt;/pre&gt;

&lt;p&gt;Le lien pointe vers &lt;code&gt;new_password_reset_path&lt;/code&gt; mais, comme ce chemin n&amp;#x27;est pas encore d&amp;eacute;fini, Guard va nous donner une autre erreur lorsqu'il lancera la spec de nouveau.&lt;/p&gt;

&lt;pre class="terminal"&gt;  1) PasswordResets emails user when requesting password reset
     Failure/Error: visit login_path
     ActionView::Template::Error:
       undefined local variable or method `new_password_reset_path&amp;#x27; for #&amp;lt;#&amp;lt;Class:0x000001039349d8&amp;gt;:0x000001039269f0&amp;gt;&lt;/pre&gt;

&lt;p&gt;Cela montre les avantages de cette m&amp;eacute;thode de test. L'erreur suivante est montr&amp;eacute;e et sa correction ne devrait pas demander beaucoup de code. Nous allons g&amp;eacute;n&amp;eacute;rer un contr&amp;ocirc;leur &lt;code&gt;PasswordResets&lt;/code&gt; avec une action &lt;code&gt;new&lt;/code&gt;. Comme nous utilisons des specs de requ&amp;ecirc;te pour tester les couches contr&amp;ocirc;leur et vue, nous n&amp;#x27;avons pas besoin des fichiers de spec du contr&amp;ocirc;leur et des vues. Nous pouvons dire au g&amp;eacute;n&amp;eacute;rateur de ne pas les cr&amp;eacute;er en passant l&amp;#x27;option &lt;code&gt;--no-test-framework&lt;/code&gt;.&lt;/p&gt;

&lt;pre class="terminal"&gt;$ rails g controller password_resets new --no-test-framework&lt;/pre&gt;

&lt;p&gt;Nous devons &amp;eacute;galement modifier le fichier de routage pour faire de &lt;code&gt;PasswordResets&lt;/code&gt; une ressource.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/config/routes.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;Auth::Application.routes.draw do

  get &amp;quot;logout&amp;quot; =&amp;gt; &amp;quot;sessions#destroy&amp;quot;, :as =&amp;gt; &amp;quot;logout&amp;quot;
  get &amp;quot;login&amp;quot; =&amp;gt; &amp;quot;sessions#new&amp;quot;, :as =&amp;gt; &amp;quot;login&amp;quot;
  get &amp;quot;signup&amp;quot; =&amp;gt; &amp;quot;users#new&amp;quot;, :as =&amp;gt; &amp;quot;signup&amp;quot;
  root :to =&amp;gt; &amp;quot;home#index&amp;quot;
  resources :users
  resources :sessions
  resources :password_resets
end&lt;/pre&gt;

&lt;p&gt;Lorsque Guard lance notre spec, il nous indique maintenant qu&amp;#x27;il ne peut pas trouver le champ de texte email sur la page de r&amp;eacute;initialisation de mot de passe.&lt;/p&gt;

&lt;pre class="terminal"&gt;  1) PasswordResets emails user when requesting password reset
     Failure/Error: fill_in &amp;quot;Email&amp;quot;, :with =&amp;gt; user.email
     Capybara::ElementNotFound:
       cannot fill in, no text field, text area or password field with id, name, or label &amp;#x27;Email&amp;#x27; found&lt;/pre&gt;

&lt;p&gt;Pour corriger cela, nous allons remplacer le code par d&amp;eacute;faut de la vue de r&amp;eacute;initialisation de mot de passe par un formulaire contenant le champ et le bouton n&amp;eacute;cessaires.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/views/password_resets/new.html.erb&lt;/p&gt;
&lt;pre class="ruby"&gt;&amp;lt;%= form_tag password_resets_path, :method =&amp;gt; :post do %&amp;gt;
  &amp;lt;div class=&amp;quot;field&amp;quot;&amp;gt;
    &amp;lt;%= label_tag :email %&amp;gt;
    &amp;lt;%= text_field_tag :email, params[:email] %&amp;gt;
  &amp;lt;/div&amp;gt;
  &amp;lt;div class=&amp;quot;actions&amp;quot;&amp;gt;&amp;lt;%= submit_tag &amp;quot;Reset Password&amp;quot; %&amp;gt;&amp;lt;/div&amp;gt;
&amp;lt;% end %&amp;gt;&lt;/pre&gt;

&lt;p&gt;L&amp;#x27;erreur suivante est caus&amp;eacute;e par le fait qu&amp;#x27;il n&amp;#x27;y ait pas d&amp;#x27;action &lt;code&gt;create&lt;/code&gt; &amp;agrave; laquelle le formulaire peut envoyer une requ&amp;ecirc;te POST.&lt;/p&gt;

&lt;pre class="terminal"&gt;  1) PasswordResets emails user when requesting password reset
     Failure/Error: click_button &amp;quot;Reset Password&amp;quot;
     AbstractController::ActionNotFound:
       The action &amp;#x27;create&amp;#x27; could not be found for PasswordResetsController&lt;/pre&gt;

&lt;p&gt;Nous allons cr&amp;eacute;er cette action dans le contr&amp;ocirc;leur et faire en sorte qu&amp;#x27;elle redirige vers la page d&amp;#x27;accueil.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/controllers/password_resets_controller.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;class PasswordResetsController &amp;lt; ApplicationController
  def new
  end

  def create
    redirect_to :root
  end

end&lt;/pre&gt;

&lt;p&gt;Nous avons maintenant le n&amp;eacute;cessaire pour que notre spec passe.&lt;/p&gt;

&lt;pre class="terminal"&gt;Running: spec/controllers/password_resets_controller_spec.rb
.

Finished in 0.14507 seconds
1 example, 0 failures&lt;/pre&gt;

&lt;h3&gt;&amp;Eacute;tendre notre sp&amp;eacute;cification&lt;/h3&gt;

&lt;p&gt;Maintenant que notre spec passe, nous pouvons l&amp;#x27;&amp;eacute;tendre. Nous voulons montrer une notification apr&amp;egrave;s que le bouton &amp;#x27;R&amp;eacute;initialiser mot de passe&amp;#x27; ait &amp;eacute;t&amp;eacute; cliqu&amp;eacute;. Nous allons donc ajouter cela &amp;agrave; la spec.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/spec/requests/password_resets_spec.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;require &amp;#x27;spec_helper&amp;#x27;

describe &amp;quot;PasswordResets&amp;quot; do
  it &amp;quot;emails user when requesting password reset&amp;quot; do
    user = Factory(:user)
    visit login_path
    click_link &amp;quot;password&amp;quot;
    fill_in &amp;quot;Email&amp;quot;, :with =&amp;gt; user.email
    click_button &amp;quot;Reset Password&amp;quot;
    page.should have_content(&amp;quot;Email sent&amp;quot;)
  end
end&lt;/pre&gt;

&lt;p&gt;Le test, bien s&amp;ucirc;r, &amp;eacute;choue puisque nous n&amp;#x27;avons pas encore &amp;eacute;crit le code pour afficher le message. Nous allons modifier le contr&amp;ocirc;leur pour que cela soit fait.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/controllers/password_resets.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;class PasswordResetsController &amp;lt; ApplicationController
  def new
  end

  def create
    redirect_to :root, :notice =&amp;gt; &amp;quot;Email sent with password reset instructions.&amp;quot;
  end

end&lt;/pre&gt;

&lt;p&gt;La spec passe de nouveau mais nous n&amp;#x27;envoyons toujours pas l&amp;#x27;e-mail. Nous pouvons le tester en utilisant &lt;code&gt;ActionMailer::Base::deliveries&lt;/code&gt; pour obtenir une liste des e-mails envoy&amp;eacute;s. Nous pouvons ensuite appeler &lt;code&gt;last&lt;/code&gt; sur cette liste pour r&amp;eacute;cup&amp;eacute;rer le dernier e-mail envoy&amp;eacute;. Nous le ferons souvent dans nos specs, nous allons donc cr&amp;eacute;er un nouveau fichier dans &lt;code&gt;/spec/support&lt;/code&gt; et y &amp;eacute;crire le code permettant de r&amp;eacute;cup&amp;eacute;rer le dernier e-mail envoy&amp;eacute;.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/spec/support/mailer_macros.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;module MailerMacros
  def last_email
    ActionMailer::Base.deliveries.last
  end

  def reset_email
    ActionMailer::Base.deliveries = []
  end
end&lt;/pre&gt;

&lt;p&gt;Nous avons &amp;eacute;galement &amp;eacute;crit une m&amp;eacute;thode &lt;code&gt;reset_email&lt;/code&gt; que nous allons appeler au d&amp;eacute;but de chaque spec. Elle va vider la liste de fa&amp;ccedil;on &amp;agrave; ce que nous puissions commencer chaque spec dans un &amp;eacute;tat connu.&lt;/p&gt;

&lt;p&gt;De fa&amp;ccedil;on &amp;agrave; ce que nous puissions utiliser ces nouvelles m&amp;eacute;thodes dans nos specs, nous allons appeler &lt;code&gt;config.include&lt;/code&gt; dans notre fichier &lt;code&gt;spec_helper.rb&lt;/code&gt; et inclure notre nouveau module.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/spec/spec_helper.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;# This file is copied to spec/ when you run &amp;#x27;rails generate rspec:install&amp;#x27;
ENV[&amp;quot;RAILS_ENV&amp;quot;] ||= &amp;#x27;test&amp;#x27;
require File.expand_path(&amp;quot;../../config/environment&amp;quot;, __FILE__)
require &amp;#x27;rspec/rails&amp;#x27;
require &amp;#x27;capybara/rspec&amp;#x27;

# Requires supporting ruby files with custom matchers and macros, etc,
# in spec/support/ and its subdirectories.
Dir[Rails.root.join(&amp;quot;spec/support/**/*.rb&amp;quot;)].each {|f| require f}

RSpec.configure do |config|
  config.mock_with :rspec
  config.use_transactional_fixtures = true
  config.include(MailerMacros)
  config.before(:each) { reset_email }
end&lt;/pre&gt;

&lt;p&gt;Apr&amp;egrave;s avoir inclu notre macro, nous allons utiliser &lt;code&gt;config.before(:each)&lt;/code&gt; pour appeler &lt;code&gt;reset_email&lt;/code&gt; de fa&amp;ccedil;on &amp;agrave; ce que la liste des e-mails envoy&amp;eacute;s soit vid&amp;eacute;e avant chaque lancement de spec.&lt;/p&gt;

&lt;p&gt;Nous pouvons maintenant utiliser notre nouvelle m&amp;eacute;thode &lt;code&gt;last_email&lt;/code&gt; dans nos specs et v&amp;eacute;rifier que le dernier e-mail envoy&amp;eacute; &amp;eacute;tait &amp;agrave; destination de l&amp;#x27;utilisateur que nous venons de cr&amp;eacute;er.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/spec/requests/password_resets_spec.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;require &amp;#x27;spec_helper&amp;#x27;

describe &amp;quot;PasswordResets&amp;quot; do
  it &amp;quot;emails user when requesting password reset&amp;quot; do
    user = Factory(:user)
    visit login_path
    click_link &amp;quot;password&amp;quot;
    fill_in &amp;quot;Email&amp;quot;, :with =&amp;gt; user.email
    click_button &amp;quot;Reset Password&amp;quot;
    page.should have_content(&amp;quot;Email sent&amp;quot;)
    last_email.to.should include(user.email)
  end
end&lt;/pre&gt;

&lt;p&gt;Ce test va &amp;eacute;videmment &amp;eacute;chouer. Le dernier e-mail aura pour valeur &lt;code&gt;nil&lt;/code&gt; puisque aucun code n&amp;#x27;a encore &amp;eacute;t&amp;eacute; &amp;eacute;crit pour l&amp;#x27;exp&amp;eacute;dier. Nous allons g&amp;eacute;n&amp;eacute;rer un mailer de fa&amp;ccedil;on &amp;agrave; pouvoir le faire.&lt;/p&gt;

&lt;pre class="terminal"&gt;$ rails g mailer user_mailer password_reset&lt;/pre&gt;

&lt;p&gt;Le g&amp;eacute;n&amp;eacute;rateur cr&amp;eacute;e son propre fichier de sp&amp;eacute;cification que nous regarderons un peu plus tard. Pour le moment, nous allons le commenter pour pouvoir nous concentrer sur notre spec en cours. Nous allons modifier le mailer de fa&amp;ccedil;on &amp;agrave; ce qu&amp;#x27;il envoie l&amp;#x27;e-mail &amp;agrave; l&amp;#x27;adresse de l&amp;#x27;utilisateur avec un sujet appropri&amp;eacute;.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/mailers/user_mailer.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;class UserMailer &amp;lt; ActionMailer::Base
  default from: &amp;quot;from@example.com&amp;quot;

  def password_reset(user)
    @user = user
    mail :to =&amp;gt; user.email, :subject =&amp;gt; &amp;quot;Password Reset&amp;quot;
  end
end&lt;/pre&gt;

&lt;p&gt;Dans notre &lt;code&gt;PasswordResetsController&lt;/code&gt;, nous allons changer l&amp;#x27;action &lt;code&gt;create&lt;/code&gt; de fa&amp;ccedil;on &amp;agrave; ce qu&amp;#x27;elle trouve l&amp;#x27;utilisateur par l&amp;#x27;adresse e-mail saisie dans le formulaire et envoie l&amp;#x27;e-mail.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/controllers/password_resets_controller.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;def create
  user = User.find_by_email(params[:email])
  UserMailer.password_reset(user).deliver
  redirect_to :root, :notice =&amp;gt; &amp;quot;Email sent with password &amp;crarr;
   reset instructions.&amp;quot;
end&lt;/pre&gt;

&lt;p&gt;Notre spec passe &amp;agrave; nouveau.&lt;/p&gt;

&lt;h3&gt;G&amp;eacute;rer le token de r&amp;eacute;initialisation de mot de passe&lt;/h3&gt;

&lt;p&gt;Bien que la spec passe, la fonctionnalit&amp;eacute; qu&amp;#x27;elle d&amp;eacute;finit est loin d&amp;#x27;&amp;ecirc;tre compl&amp;egrave;te. Nous devrions g&amp;eacute;n&amp;eacute;rer un token (jeton) de r&amp;eacute;initialisation de mot de passe et l&amp;#x27;ajouter dans l&amp;#x27;e-mail. Ces d&amp;eacute;tails n&amp;#x27;ont pas besoin d&amp;#x27;&amp;ecirc;tre plac&amp;eacute;s dans la sp&amp;eacute;cification de requ&amp;ecirc;te. Il est pr&amp;eacute;f&amp;eacute;rable de faire en sorte qu&amp;#x27;elle d&amp;eacute;finisse le flux g&amp;eacute;n&amp;eacute;ral de la requ&amp;ecirc;te, dans notre cas, v&amp;eacute;rifier que l&amp;#x27;utilisateur re&amp;ccedil;oit un e-mail de r&amp;eacute;initialisation de mot de passe lorsqu&amp;#x27;il le demande. Nous pouvons utiliser des tests plus bas niveau pour v&amp;eacute;rifier les d&amp;eacute;tails.&lt;/p&gt;

&lt;p&gt;Maintenant que nous avons une spec qui passe, c&amp;#x27;est le moment de jeter un oeil sur notre code pour voir ce qui peut &amp;ecirc;tre pris du contr&amp;ocirc;leur et plac&amp;eacute; dans le mod&amp;egrave;le. Un bon exemple ici est la ligne de code dans &lt;code&gt;PasswordResetsController&lt;/code&gt; qui envoie l&amp;#x27;e-mail. Nous pouvons la d&amp;eacute;placer dans une nouvelle m&amp;eacute;thode &lt;code&gt;send_password_reset&lt;/code&gt; dans le mod&amp;egrave;le &lt;code&gt;User&lt;/code&gt;.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/controllers/password_resets_controller.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;def create
  user = User.find_by_email(params[:email])
  user.send_password_reset
  redirect_to :root, :notice =&amp;gt; &amp;quot;Email sent with password &amp;crarr;
   reset instructions.&amp;quot;
end&lt;/pre&gt;

&lt;p class="codeFilePath"&gt;/app/models/user.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;class User &amp;lt; ActiveRecord::Base
  attr_accessible :email, :password, :password_confirmation
  has_secure_password
  validates_presence_of :password, :on =&amp;gt; :create

  def send_password_reset
    UserMailer.password_reset(self).deliver
  end
end&lt;/pre&gt;

&lt;p&gt;Nous allons maintenant v&amp;eacute;rifier que nos specs passent toujours. C&amp;#x27;est le cas, nous pouvons donc continuer. Nous allons ensuite &amp;eacute;crire plus de specs pour ajouter un peu de mati&amp;egrave;re &amp;agrave; notre mod&amp;egrave;le &lt;code&gt;User&lt;/code&gt;. Nous allons cr&amp;eacute;er un fichier de specs dans &lt;code&gt;/spec/models/user.rb&lt;/code&gt; et y &amp;eacute;crire quelques specs.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/spec/models/user_spec.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;require &amp;#x27;spec_helper&amp;#x27;

describe User do
  describe &amp;quot;#send_password_reset&amp;quot; do
    let(:user) { Factory(:user) }

    it &amp;quot;generates a unique password_reset_token each time&amp;quot; do
      user.send_password_reset
      last_token = user.password_reset_token
      user.send_password_reset
      user.password_reset_token.should_not eq(last_token)
    end

    it &amp;quot;saves the time the password reset was sent&amp;quot; do
      user.send_password_reset
      user.reload.password_reset_sent_at.should be_present
    end

    it &amp;quot;delivers email to user&amp;quot; do
      user.send_password_reset
      last_email.to.should include (user.email)
    end
  end
end&lt;/pre&gt;

  &lt;p&gt;Nous voulons que la m&amp;eacute;thode &lt;code&gt;send_password_reset&lt;/code&gt; fasse trois choses lorsqu&amp;#x27;elle est appel&amp;eacute;e. Elle devrait cr&amp;eacute;er un token unique, enregistrer le moment auquel le token a &amp;eacute;t&amp;eacute; envoy&amp;eacute; et exp&amp;eacute;dier un e-mail &amp;agrave; l&amp;#x27;utilisateur. Elle effectue d&amp;eacute;j&amp;agrave; la derni&amp;egrave;re t&amp;acirc;che. Nous allons modifier la m&amp;eacute;thode afin qu&amp;#x27;elle se charge &amp;eacute;galement des deux autres. Notez qu&amp;#x27;avant les specs, nous appelons &lt;code&gt;let(:user)&lt;/code&gt;. Cela assigne un nouvel utilisateur, issue de la factory, &amp;agrave; &lt;code&gt;user&lt;/code&gt; avant chaque ex&amp;eacute;cution de spec.&lt;/p&gt;

&lt;p&gt;Deux des specs &amp;eacute;chouent pour le moment et cela est d&amp;ucirc; au fait que nous n&amp;#x27;avons ni le champ &lt;code&gt;password_reset_token&lt;/code&gt;, ni le champ &lt;code&gt;password_reset_sent_at&lt;/code&gt; dans la table des utilisateurs en base.&lt;/p&gt;

&lt;pre class="terminal"&gt;$ rails g migration add_password_reset_to_users password_reset_token:string password_reset_sent_at:datetime&lt;/pre&gt;

&lt;p&gt;Avec les nouveaux champs en base, les specs &amp;eacute;chouent toujours mais pour d&amp;#x27;autres raisons.&lt;/p&gt;

&lt;pre class="terminal"&gt;Failures:

  1) User#send_password_reset generates a unique password_reset_token each time
     Failure/Error: user.password_reset_token.should_not eq(last_token)

       expected nil not to equal nil

       (compared using ==)
     # ./spec/models/user_spec.rb:11:in `block (3 levels) in &amp;lt;top (required)&amp;gt;&amp;#x27;

  2) User#send_password_reset saves the time the password reset was sent
     Failure/Error: user.reload.password_reset_sent_at.should be_present
       expected present? to return true, got false
     # ./spec/models/user_spec.rb:16:in `block (3 levels) in &amp;lt;top (required)&amp;gt;&amp;#x27;&lt;/pre&gt;

&lt;p&gt;Les specs &amp;eacute;chouent maintenant parce que &lt;code&gt;password_reset_token&lt;/code&gt; et &lt;code&gt;password_reset_sent_at&lt;/code&gt; ne sont pas renseign&amp;eacute;s dans la m&amp;eacute;thode &lt;code&gt;sent_password_reset&lt;/code&gt;. Cela peut &amp;ecirc;tre corrig&amp;eacute; en &amp;eacute;crivant une m&amp;eacute;thode &lt;code&gt;generate_token&lt;/code&gt; qui va cr&amp;eacute;er un token unique. Nous pouvons ensuite modifier &lt;code&gt;sent_password_reset&lt;/code&gt; afin qu&amp;#x27;elle appelle &lt;code&gt;generate_token&lt;/code&gt;, donne une valeur &amp;agrave; &lt;code&gt;password_reset_sent_at&lt;/code&gt; et sauvegarde l&amp;#x27;utilisateur.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/models/user.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;class User &amp;lt; ActiveRecord::Base
  attr_accessible :email, :password, :password_confirmation
  has_secure_password
  validates_presence_of :password, :on =&amp;gt; :create

  def send_password_reset
    generate_token(:password_reset_token)
    self.password_reset_sent_at = Time.zone.now
    save!
    UserMailer.password_reset(self).deliver
  end

  def generate_token(column)
    begin
      self[column] = SecureRandom.urlsafe_base64
    end while User.exists?(column =&amp;gt; self[column])
  end
end&lt;/pre&gt;

&lt;p&gt;Nos specs passent toutes &amp;agrave; nouveau.&lt;/p&gt;

&lt;h3&gt;Tester le Mailer&lt;/h3&gt;

&lt;p&gt;Maintenant que nos specs passent, nous allons retourner &amp;agrave; celle de notre mailer, cr&amp;eacute;&amp;eacute;e lors de la g&amp;eacute;n&amp;eacute;ration de ce dernier. Nous l&amp;#x27;avions alors comment&amp;eacute;e. Nous allons devoir modifier le code par d&amp;eacute;faut de fa&amp;ccedil;on &amp;agrave; pouvoir v&amp;eacute;rifier que notre mailer fonctionne correctement. Dans la spec, nous allons cr&amp;eacute;er un nouvel utilisateur depuis la factory mais cette fois, nous allons renseigner le champ &lt;code&gt;password_reset_token&lt;/code&gt; de cet utilisateur. Nous allons ensuite changer la ligne cr&amp;eacute;ant l&amp;#x27;e-mail afin que l&amp;#x27;utilisateur soit pass&amp;eacute; en param&amp;egrave;tre de l&amp;#x27;appel &amp;agrave; &lt;code&gt;UserMailer.password_reset&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;La spec va v&amp;eacute;rifier que l&amp;#x27;e-mail est envoy&amp;eacute; &amp;agrave; la bonne adresse et que le corps contient le lien vers le token de r&amp;eacute;initialisation de l&amp;#x27;utilisateur.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/spec/mailers/user_mailer_spec.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;require &amp;quot;spec_helper&amp;quot;

describe UserMailer do
  describe &amp;quot;password_reset&amp;quot; do
    let(:user) { Factory(:user, :password_reset_token =&amp;gt; &amp;quot;anything&amp;quot;) }
    let(:mail) { UserMailer.password_reset(user) }

    it &amp;quot;sends user password reset url&amp;quot; do
      mail.subject.should eq(&amp;quot;Password Reset&amp;quot;)
      mail.to.should eq([user.email])
      mail.from.should eq([&amp;quot;from@example.com&amp;quot;])
    end

    it &amp;quot;renders the body&amp;quot; do
      mail.body.encoded.should match(edit_password_reset_path(user.password_reset_token))
    end
  end
end&lt;/pre&gt;

&lt;p&gt;Notre spec &amp;eacute;choue puisque le corps de l&amp;#x27;e-mail ne contient pas le lien, ajoutons le donc.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/views/user_mailer/password_reset.text.erb&lt;/p&gt;
&lt;pre class="ruby"&gt;To reset your password, click the URL below.

&amp;lt;%= edit_password_reset_url(@user.password_reset_token) %&amp;gt;

If you did not request your password to be reset just ignore this email and your password will continue to stay the same.&lt;/pre&gt;

&lt;p&gt;La spec &amp;eacute;choue toujours car une option &lt;code&gt;:host&lt;/code&gt; est manquante pour l&amp;#x27;envoie de l&amp;#x27;e-mail. Nous pouvons la configurer dans le fichier de r&amp;eacute;glage de notre environnement de test en ajoutant la ligne suivante&amp;nbsp;:&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/config/environments/test.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;config.action_mailer.default_url_options = { :host =&amp;gt; &amp;quot;www.example.com&amp;quot; }&lt;/pre&gt;

&lt;p&gt;Nous devons &amp;eacute;galement configurer cette option dans nos environnements de d&amp;eacute;veloppement et de production mais nous n&amp;#x27;allons pas le faire maintenant.&lt;/p&gt;

&lt;p&gt;Toutes nos specs passent maintenant. Au passage, si nous avions besoin de dire &amp;agrave; Guard de relancer les specs, nous pourrions le faire gr&amp;acirc;ce &amp;agrave; &lt;code&gt;CTRL+\&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;Tester d&amp;#x27;autres sc&amp;eacute;narios&lt;/h3&gt;

&lt;p&gt;L&amp;#x27;une des parties les plus difficiles du d&amp;eacute;veloppement dirig&amp;eacute; par les tests et de se lancer et d&amp;#x27;&amp;eacute;tablir un workflow. Une fois que vous avez commenc&amp;eacute;, il est facile de copier/coller les tests pour ajouter des variations et tester de nouvelles fonctionnalit&amp;eacute;s. Par exemple, testons le cas o&amp;ugrave; un utilisateur saisit une adresse e-mail erron&amp;eacute;e et demande une r&amp;eacute;initialisation de mot de passe. Nous pouvons facilement copier la spec existante dans &lt;code&gt;password_resets_spec.rb&lt;/code&gt; et en cr&amp;eacute;er une nouvelle pour tester cela.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/spec/requests/password_resets_spec.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;it &amp;quot;does not email invalid user when requesting password reset&amp;quot; do
  visit login_path
  click_link &amp;quot;password&amp;quot;
  fill_in &amp;quot;Email&amp;quot;, :with =&amp;gt; &amp;quot;madeupuser@example.com&amp;quot;
  click_button &amp;quot;Reset Password&amp;quot;
  page.should have_content(&amp;quot;Email sent&amp;quot;)
  last_email.should be_nil
end&lt;/pre&gt;

&lt;p&gt;La spec &amp;eacute;choue puisque le code du contr&amp;ocirc;leur &amp;eacute;choue si l&amp;#x27;utilisateur n&amp;#x27;est pas trouv&amp;eacute;. Nous allons corriger cela.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/controllers/password_resets_controller.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;def create
  user = User.find_by_email(params[:email])
  user.send_password_reset if user?
  redirect_to :root, :notice =&amp;gt; &amp;quot;Email sent with password &amp;crarr;
    reset instructions.&amp;quot;
end&lt;/pre&gt;

&lt;p&gt;Cela r&amp;eacute;pond au test et toutes nos specs passent &amp;agrave; nouveau.&lt;/p&gt;

&lt;p&gt;Avec ce mod&amp;egrave;le de d&amp;eacute;veloppement &amp;eacute;tabli, il est facile d&amp;#x27;aller dans la sp&amp;eacute;cification de requ&amp;ecirc;te et d&amp;#x27;ajouter de nouvelles fonctionnalit&amp;eacute;s &amp;agrave; la r&amp;eacute;initialisation de mot de passe, par exemple, pour tester que le token n&amp;#x27;a pas expir&amp;eacute; ou qu&amp;#x27;il est bien valide, etc. D&amp;#x27;autres cas de tests sont disponibles dans le code source final de cet &amp;eacute;pisode sur &lt;a href="https://github.com/ryanb/railscasts-episodes"&gt;la page Github de Ryan Bates&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;C&amp;#x27;est tout pour cet &amp;eacute;pisode sur le test du lien &amp;#x27;Mot de passe oubli&amp;eacute;&amp;#x27;. Tester peut &amp;ecirc;tre un sujet controvers&amp;eacute; et diff&amp;eacute;rents points de vue sont &amp;eacute;mis quant &amp;agrave; la meilleure fa&amp;ccedil;on de les &amp;eacute;crire pour une application Rails. Le plus important est que vous testiez votre application, peu importe la m&amp;eacute;thode.&lt;/p&gt;</description>
      <pubDate>Mon, 08 Aug 2011 18:43:36 +0000</pubDate>
      <guid>http://fr.asciicasts.com/episodes/275-comment-nous-testons</guid>
      <link>http://fr.asciicasts.com/episodes/275-comment-nous-testons</link>
    </item>
  </channel>
</rss>

