<?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>Sun, 18 Jul 2010 21:21:10 +0000</pubDate>
    <ttl>1440</ttl>
    <item>
      <title>Appareils mobiles</title>
      <description>&lt;p&gt;C&amp;#x27;est devenu de plus en plus courant de naviguer sur des sites en utilisant des appareils mobiles, comme les smartphones. Compar&amp;eacute;s aux ordinateurs portables ou de bureau, ces machines ont de plus petits &amp;eacute;crans et des fonctionalit&amp;eacute;s plus limit&amp;eacute;es, et ayant cela en t&amp;ecirc;te, il est important de v&amp;eacute;rifier vos applications web sur ces petits appareils pour voir comment ils r&amp;eacute;agissent.&lt;/p&gt;

&lt;p&gt;La meilleur fa&amp;ccedil;on de le faire est de tester concr&amp;egrave;tement votre application sur un appareil. De toute &amp;eacute;vidence,&amp;ldquo;localhost&amp;rdquo; ne fonctionnera pas sur un mobile, et vous devrez donc utiliser soit l&amp;#x27;adresse IP de votre machine sur laquelle tourne votre application soit sur votre domaine local, en pr&amp;eacute;sumant que le mobile soit aussi sur votre r&amp;eacute;seau local. Par exemple, la machine sur laquelle tourne l&amp;#x27;application que l&amp;#x27;on va utiliser dans cet &amp;eacute;pisode s&amp;#x27;appelle noonoo, si bien que l&amp;#x27;on va y avoir acc&amp;egrave;s sur le r&amp;eacute;seau en tapant l&amp;#x27;adresse &lt;code&gt;http://noonoo.local:3000/&lt;/code&gt;.&lt;/p&gt;

&lt;div class="imageWrapper"&gt;
 &lt;img src="/system/photos/316/original/E199I01.png" width="800" height="323" alt="La page projets de notre application."/&gt;
&lt;/div&gt;

&lt;p&gt;Si vous ne pouvez pas y acc&amp;eacute;der physiquement, vous serez oblig&amp;eacute; de t&amp;eacute;l&amp;eacute;charger un simulateur pour l&amp;#x27;appareil, pour lequel vous voulez tester votre application. Si vous voulez tester sur un iPhone, alors un simulateur est disponible sur le &lt;a href="http://developer.apple.com/iphone/program/"&gt;site d&amp;#x27;Apple pour les d&amp;eacute;veloppeurs&lt;/a&gt;. De la m&amp;ecirc;le mani&amp;egrave;re, un &amp;eacute;mulateur fait partie du &lt;a href="http://developer.palm.com/index.php?option=com_content&amp;amp;view=article&amp;amp;layout=page&amp;amp;id=1788"&gt;SDK Palm Pr&amp;eacute;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Pour tester sur l&amp;#x27;iPhone, une autre alternative est &lt;a href="http://sourceforge.net/projects/iphonesimulator/"&gt;iPhoney&lt;/a&gt;. Il fournit presqu&amp;#x27;exactement la m&amp;ecirc;me &amp;eacute;mulation qu&amp;#x27;un iPhone, m&amp;ecirc;me s&amp;#x27;il n&amp;#x27;est pas aussi fid&amp;egrave;le que le simulateur Apple, sauf qu&amp;#x27;il n&amp;#x27;est pas aussi lourd &amp;agrave; t&amp;eacute;l&amp;eacute;charger que le SDK iPhone. Si vous avez pr&amp;eacute;vu de tester un site qui devra avoir des comportements diff&amp;eacute;rents pour les mobiles, alors il ne faudra pas oublier de d&amp;eacute;finir le user agent correctement dans  le menu iPhoney, de telle sorte que le contenu appropri&amp;eacute; soit bien affich&amp;eacute;.&lt;/p&gt;

&lt;div class="imageWrapper"&gt;
  &lt;img src="/system/photos/317/original/E199I02.png" width="728" height="386" alt="Le site vu sur l'&#233;mulateur iPhoney." /&gt;
&lt;/div&gt;
&lt;p class="title"&gt;Notre application tournant sur iPhoney.&lt;/p&gt;

&lt;p&gt;L&amp;#x27;apparence de l&amp;#x27;application peut de tout &amp;eacute;vidence &amp;ecirc;tre am&amp;eacute;lior&amp;eacute;e pour l&amp;#x27;affichage sur un mobile, et c&amp;#x27;est que nous allons faire tout au long de cet &amp;eacute;pisode.&lt;/p&gt;

&lt;p&gt;Commen&amp;ccedil;ons par ajouter une feuille de style (stylesheet) dans la layout de notre application, qui ne sera incluse que si notre application est visit&amp;eacute;e par un mobile.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/views/products/_fields.html.erb&lt;/p&gt;
&lt;pre class="ruby"&gt;
  &amp;lt;!DOCTYPE html PUBLIC &amp;quot;-//W3C//DTD XHTML 1.0 Strict//EN&amp;quot;
    &amp;quot;http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd&amp;quot;&amp;gt;
  &amp;lt;html&amp;gt;
    &amp;lt;head&amp;gt;
      &amp;lt;title&amp;gt;&amp;lt;%= h(yield(:title) || &amp;quot;Untitled&amp;quot;) %&amp;gt;&amp;lt;/title&amp;gt;

      &amp;lt;%= stylesheet_link_tag &amp;#x27;application&amp;#x27; %&amp;gt;
      &amp;lt;%= stylesheet_link_tag &amp;#x27;mobile&amp;#x27; if mobile_device? %&amp;gt;
      &amp;lt;%= yield(:head) %&amp;gt;
    &amp;lt;/head&amp;gt;

    &amp;lt;body&amp;gt;
    &amp;lt;!-- content omitted --&amp;gt;
    &amp;lt;/body&amp;gt;
  &amp;lt;/html&amp;gt;
&lt;/pre&gt;

&lt;p&gt;La nouvelle feuille de style mobile ne sera incluse que si une m&amp;eacute;thode appel&amp;eacute;e &lt;code&gt;mobile_device?&lt;/code&gt; retourne &lt;code&gt;true&lt;/code&gt;, et pour cela nous allons &amp;eacute;crire cette m&amp;eacute;thode. On aurait pu aussi utiliser l&amp;#x27;attribut &lt;code&gt;media&lt;/code&gt; de la balise &lt;code&gt;link&lt;/code&gt; 
 pour restreindre aux mobiles l&amp;#x27;utilisation de cette feuille de style, mais les navigateurs mobiles pourraient interpr&amp;eacute;ter cet attribut de fa&amp;ccedil;ons fort diff&amp;eacute;rentes. En utilisant notre propre m&amp;eacute;thode pour d&amp;eacute;terminer s&amp;#x27;il faut ou non inclure la feuille de style, on va avoir un meilleur contr&amp;ocirc;le sur quels appareils vont afficher cette feuille, lorsque l&amp;#x27;on va lire la cha&amp;icirc;ne de leur user agent envoy&amp;eacute; par leur navigateur.&lt;/p&gt;

&lt;p&gt;La prochaine &amp;eacute;tape est d&amp;#x27;&amp;eacute;crire la m&amp;eacute;thode &lt;code&gt;mobile_device?&lt;/code&gt;. on va la placer dans l&amp;#x27;application controller, ainsi tous les controllers pourront avoir acc&amp;egrave;s &amp;agrave; cette m&amp;eacute;thode.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/controllers/application_controller.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;
class ApplicationController &amp;lt; ActionController::Base
  helper :all
  protect_from_forgery

  private
  def mobile_device?
    request.user_agent =~ /Mobile|webOS/
  end
  helper_method :mobile_device?
end
&lt;/pre&gt;

&lt;p&gt;Dans cette m&amp;eacute;thode, on va v&amp;eacute;rifier la requ&amp;ecirc;te du user agent pour voir s&amp;#x27;il contient soit le mot &amp;ldquo;Mobile&amp;rdquo;, correspondant aux appareils iPhone et Android, soit &amp;ldquo;webOS&amp;rdquo; correspondant au Palm Pr&amp;eacute;. Vous pouvez, bien s&amp;ucirc;r, customiser cette expression r&amp;eacute;guli&amp;egrave;re pour cibler quels appareils doivent afficher la feuille de style mobile. Au final on d&amp;eacute;signe cette m&amp;eacute;thode comme une helper m&amp;eacute;thode, de telle sorte qu&amp;#x27;on pourra y avoir acc&amp;egrave;s dans toutes nos vues. Si vous d&amp;eacute;cidez de cibler un appareil sp&amp;eacute;cifique, il existe une &lt;a href="http://www.zytrax.com/tech/web/mobile_ids.html"&gt;liste compl&amp;egrave;te&lt;/a&gt; d&amp;#x27;agents pour appareils mobiles.&lt;/p&gt;

&lt;p&gt;Maintenant que l&amp;#x27;on a &amp;eacute;crit notre helper m&amp;eacute;thode, on va &amp;eacute;crire la feuille de style mobile, que les mobiles vont utiliser.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/public/stylesheets/mobile.css&lt;/p&gt;
&lt;pre class="ruby"&gt;
body {
  background-color: #FFF;
}

#container {
  width: 90%;
  min-width: none;
  margin: 0 auto;
  background-color: #FFF;
  padding: 0;
  border: none;
  margin-top: 20px;
}
&lt;/pre&gt;

&lt;p&gt;Afin de voir &amp;agrave; quoi ressemble notre page avec notre feuille de style mobile, on peut utiliser les fonctions de simulation du user-agent dans Safari. (Safari propose un menu D&amp;eacute;veloppeur qui est, par d&amp;eacute;faut, d&amp;eacute;sactiv&amp;eacute;. Pour l&amp;#x27;activer, il faut se rendre dans les pr&amp;eacute;f&amp;eacute;rences du navigateur, menu Avanc&amp;eacute; et cocher la case correspondante; pour la version anglaise, Show Develop menu in menu bar.) (NdT: il existe aussi un module pour Firefox, appel&amp;eacute; &lt;code&gt;User Agent Switcher&lt;/code&gt; qui permet de changer dynamiquement son user agent, suivant diff&amp;eacute;rents profils.) Dans le menu &lt;code&gt;D&amp;eacute;veloppeur &amp;gt; User Agent&lt;/code&gt; se trouve une liste de user-agents, qui peuvent &amp;ecirc;tre s&amp;eacute;lectionn&amp;eacute;s, incluant plusieurs des diff&amp;eacute;rentes versions de Safari Mobile. Si on choisit l&amp;#x27;une d&amp;#x27;elles et que l&amp;#x27;on regarde de nouveau notre application, on va voir la page avec la feuille de style mobile qui lui est appliqu&amp;eacute;e.&lt;/p&gt;

&lt;div class="imageWrapper"&gt;
  &lt;img src="/system/photos/318/original/E199I03.png" width="800" height="280" alt="Le site avec notre stylesheet mobile appliqu&amp;eacute;e."/&gt;
&lt;/div&gt;

&lt;h3&gt;Basculer entre les Sites&lt;/h3&gt;
&lt;p&gt;Maintenant que nous avons notre helper m&amp;eacute;thode &lt;code&gt;mobile_device?&lt;/code&gt;, on peut l&amp;#x27;utiliser pour modifier le comportement du site en fonction de l&amp;#x27;appareil qui le visite. Ce que l&amp;#x27;on va ajouter, c&amp;#x27;est un lien qui va permettre aux utilisateurs de basculer entre la version int&amp;eacute;grale et la version mobile du site. Pour ce faire, on va modifier notre layout d&amp;#x27;application en ajoutant le code suivant avant la balise &lt;code&gt;body&lt;/code&gt;.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/views/layouts/application.html.erb&lt;/p&gt;
&lt;pre class="ruby"&gt;
&amp;lt;p&amp;gt;
  &amp;lt;% if mobile_device? %&amp;gt;
    &amp;lt;%= link_to &amp;quot;Full Site&amp;quot;, :mobile =&amp;gt; 0 %&amp;gt;

  &amp;lt;% else %&amp;gt;
    &amp;lt;%= link_to &amp;quot;Mobile Site&amp;quot;, :mobile =&amp;gt; 1 %&amp;gt;
  &amp;lt;% end %&amp;gt;
&amp;lt;/p&amp;gt;
&lt;/pre&gt;

&lt;p&gt;Ce code va afficher un lien vers le site int&amp;eacute;gral si on est actuellement sur les pages mobiles et vice versa. Le lien va rediriger vers la page qui est actuellement visit&amp;eacute;e avec une cha&amp;icirc;ne de requ&amp;ecirc;te comme param&amp;egrave;tre, appel&amp;eacute;e mobile, qui va d&amp;eacute;terminer quelle version du site &amp;agrave; afficher.&lt;/p&gt;

&lt;p&gt;Dans notre application controller, on peut d&amp;eacute;finir un &lt;code&gt;before_filter&lt;/code&gt; qui va d&amp;eacute;finir une variable de session, si bien que, d&amp;egrave;s que le lien est cliqu&amp;eacute;, cette version continuera d&amp;#x27;&amp;ecirc;tre affich&amp;eacute;e tout au long de la navigation de l&amp;#x27;utilisateur sur le site. Le &lt;code&gt;before_filter&lt;/code&gt; va d&amp;eacute;finir une variable de session s&amp;#x27;il y a un param&amp;egrave;tre &amp;#x27;mobile&amp;#x27; dans la cha&amp;icirc;ne de requ&amp;ecirc;te. On va aussi modifier notre m&amp;eacute;thode &lt;code&gt;mobile_device?&lt;/code&gt; de telle sorte qu&amp;#x27;elle v&amp;eacute;rifie si cette variable existe et, auquel cas,  choisira quelle version du site &amp;agrave; afficher, en se basant sur sa valeur. Si cette valeur n&amp;#x27;a pas &amp;eacute;t&amp;eacute; d&amp;eacute;finie, on se basera sur la cha&amp;icirc;ne de requ&amp;ecirc;te.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/controllers/application_controller.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;
class ApplicationController &amp;lt; ActionController::Base
  helper :all
  protect_from_forgery
  before_filter :prepare_for_mobile

  private
  def mobile_device?
    if session[:mobile_param]
      session[:mobile_param] == &amp;quot;1&amp;quot;
    else
      request.user_agent =~ /Mobile|webOS/
    end
  end
  helper_method :mobile_device?

  def prepare_for_mobile
    session[:mobile_param] = params[:mobile] if params[:mobile]
  end
end
&lt;/pre&gt;
&lt;p&gt;Si on recharge la page maintenant, il va y avoir un lien vers la version int&amp;eacute;grale du site, et lorsque l&amp;#x27;on clique, on verra la version compl&amp;egrave;te, m&amp;ecirc;me si on est en train de voir le site avec un user agent, dont la cha&amp;icirc;ne contient le mot &amp;ldquo;mobile&amp;rdquo;.&lt;/p&gt;

&lt;div class="imageWrapper"&gt;
  &lt;img src="/system/photos/319/original/E199I04.png" width="800" height="353" alt="Le lien vers le site mobile est maintenant visible."/&gt;
&lt;/div&gt;

&lt;p&gt;Cette pr&amp;eacute;f&amp;eacute;rence va demeurer, si bien que si l&amp;#x27;on clique sur n&amp;#x27;importe quel lien ci-dessus, on restera sur la version int&amp;eacute;grale de l&amp;#x27;application.&lt;/p&gt;

&lt;h3&gt;Vues distinctes pour les Appareils Mobiles&lt;/h3&gt;

&lt;p&gt;Tout ce que l&amp;#x27;on a fait jusqu&amp;#x27;&amp;agrave; pr&amp;eacute;sent marchera pour les cas o&amp;ugrave; l&amp;#x27;on veut une application cousue-main pour des mobiles, mais qu&amp;#x27;en serait-il si l&amp;#x27;on a de plus grandes ambitions et que l&amp;#x27;on veuille changer l&amp;#x27;application afin qu&amp;#x27;elle ressemble et r&amp;eacute;ponde comme une application mobile native? Pour cela, il faudrait changer toutes les vues ou presque de notre application. 
 Comment allons-nous faire?&lt;/p&gt;

&lt;p&gt;L&amp;#x27;astuce est de cr&amp;eacute;er un nouveau type MIME dans notre application, et Rails fournit justement un fichier ad hoc pour cela: &lt;code&gt;/config/initializers/mime_types.rb&lt;/code&gt;. Ce fichier contient un exemple comment&amp;eacute; pour fournir un nouveau type &lt;code&gt;iphone&lt;/code&gt;, que nous allons modifier pour cr&amp;eacute;er notre nouveau type &lt;code&gt;mobile&lt;/code&gt;. Cela nous permet d&amp;#x27;avoir un nouveau format HTML alternatif pour les appareils mobiles.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/config/initializers/mime_types.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;
# Be sure to restart your server when you modify this file.

# Add new mime types for use in respond_to blocks:
# Mime::Type.register &amp;quot;text/richtext&amp;quot;, :rtf
# Mime::Type.register_alias &amp;quot;text/html&amp;quot;, :iphone
Mime::Type.register_alias &amp;quot;text/html&amp;quot;, :mobile
&lt;/pre&gt;

&lt;p&gt;De toute fa&amp;ccedil;on, on doit encore d&amp;eacute;finir ce type MIME, et pour ce faire, on revient dans notre &lt;code&gt;before_filter&lt;/code&gt; dans l&amp;#x27;application controller et d&amp;eacute;finir le format &amp;agrave; &lt;code&gt;:mobile&lt;/code&gt; si c&amp;#x27;est la version mobile qui est demand&amp;eacute;e.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/controllers/application_controller.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;
def prepare_for_mobile
  session[:mobile_param] = params[:mobile] if params[:mobile]
  format :mobile if mobile_device?
end
&lt;/pre&gt;
&lt;p&gt;Maintenant que le type MIME est d&amp;eacute;fini, on peut l&amp;#x27;utiliser dans nos actions des controllers pour changer le comportement de chaque action selon le type en utilisant &lt;code&gt;respond_to&lt;/code&gt;, comme on va le d&amp;eacute;montrer dans l&amp;#x27;action &lt;code&gt;index&lt;/code&gt; du controller des projects.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/controllers/projects_controller.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;
def index
  @projects = Project.all
  respond_to do |format|
    format.html
    format.mobile
  end
end
&lt;/pre&gt;
&lt;p&gt;Le bloc &lt;code&gt;respond_to&lt;/code&gt; n&amp;#x27;est pas n&amp;eacute;cessaire, si nous pouvons fournir une vue alternative bas&amp;eacute;e sur le format. Dans ce cas, on a juste besoin de fournir a nouveau template ayant comme nom celui du nouveau format,l&amp;agrave; o&amp;ugrave; normallement se trouve html. Pour la vue index ci-dessus, on va cr&amp;eacute;er un fichier appel&amp;eacute; &lt;code&gt;/app/views/projects/index.mobile.erb&lt;/code&gt; et pour commencer, on y placer un peu de texte.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/views/projects/index.mobile.erb&lt;/p&gt;
  &lt;pre class="ruby"&gt;
  Voil&amp;agrave; la version mobile!
  &lt;/pre&gt;
&lt;p&gt;Si on regarde la version mobile de cette page, on voit maintenant que la vue mobile s&amp;#x27;affiche.&lt;/p&gt;

&lt;div class="imageWrapper"&gt;
 &lt;img src="/system/photos/320/original/E199I05.png" width="740" height="280" alt="Le template de la vue mobile est bien rendu."/&gt;
&lt;/div&gt;

&lt;p&gt;Maintenant que c&amp;#x27;est en place, on peut cr&amp;eacute;er une Interface Utilisateur (IU) qui va bien plus ressembler &amp;agrave; une applicaion mobile native. Il existe un certain nombre de librairies qui permettent de rendre les choses plus faciles: &lt;a href="http://code.google.com/p/iui/"&gt;iui&lt;/a&gt; et &lt;a href="http://www.jqtouch.com"&gt;jQTouch&lt;/a&gt; et celle que nous allons utiliser ici est jQTouch. jQTouch facilite grandement les choses pour cr&amp;eacute;er une appli web, qui ressemble &amp;agrave; une appli iPhone.&lt;/p&gt;

&lt;p&gt;Apr&amp;egrave;s avoir t&amp;eacute;l&amp;eacute;charg&amp;eacute; et d&amp;eacute;zipp&amp;eacute; jQTouch, la structure des r&amp;eacute;pertoires devrait &amp;ecirc;tre:&lt;/p&gt;

&lt;div class="imageWrapper"&gt;
 &lt;img src="/system/photos/321/original/E199I06.png" width="808" height="393" alt="La structure des dossiers pour jQTouch."/&gt;
&lt;/div&gt;

&lt;p&gt;Pour faciliter l&amp;#x27;utilisation de jQTouch, on va d&amp;eacute;placer les r&amp;eacute;pertoires extensions et themes dans le r&amp;eacute;pertoire &lt;code&gt;jqtouch&lt;/code&gt; et ensuite faire glisser ce r&amp;eacute;pertoire dans le dossier &lt;code&gt;public&lt;/code&gt; de notre application.&lt;/p&gt;

&lt;p&gt;Ensuite, on va cr&amp;eacute;er un nouveau fichier layout pour la version mobile de notre application.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/views/layouts/application.mobile.erb&lt;/p&gt;
&lt;pre class="ruby"&gt;
&amp;lt;!DOCTYPE html PUBLIC &amp;quot;-//W3C//DTD XHTML 1.0 Strict//EN&amp;quot;
  &amp;quot;http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd&amp;quot;&amp;gt;

&amp;lt;html&amp;gt;
  &amp;lt;head&amp;gt;
    &amp;lt;title&amp;gt;&amp;lt;%= h(yield(:title) || &amp;quot;Untitled&amp;quot;) %&amp;gt;&amp;lt;/title&amp;gt;
    &amp;lt;%= stylesheet_link_tag &amp;quot;/jqtouch/jqtouch.min.css&amp;quot;, &amp;quot;/jqtouch/themes/apple/theme.min.css&amp;quot; %&amp;gt;

    &amp;lt;%= javascript_include_tag &amp;quot;/jqtouch/jquery.1.3.2.min.js&amp;quot;, &amp;quot;/jqtouch/jqtouch.min.js&amp;quot;, &amp;quot;mobile&amp;quot; %&amp;gt;
    &amp;lt;%= yield(:head) %&amp;gt;
  &amp;lt;/head&amp;gt;
  &amp;lt;body&amp;gt;

    &amp;lt;div class=&amp;quot;current&amp;quot;&amp;gt;
      &amp;lt;%- if show_title? -%&amp;gt;
      &amp;lt;div class=&amp;quot;toolbar&amp;quot;&amp;gt;
        &amp;lt;%= link_to &amp;quot;Back&amp;quot;, nil, :class =&amp;gt; &amp;quot;back&amp;quot; unless current_page? root_path %&amp;gt;

        &amp;lt;h1&amp;gt;&amp;lt;%=h yield(:title) %&amp;gt;&amp;lt;/h1&amp;gt;
        &amp;lt;%= yield(:toolbar) %&amp;gt;
      &amp;lt;/div&amp;gt;
      &amp;lt;%- end -%&amp;gt;

      &amp;lt;% unless flash.empty? %&amp;gt;

        &amp;lt;div class=&amp;quot;info&amp;quot;&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;/div&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;Dans ce fichier layout, on va inclure quelques fichiers CSS, fournis par jQTouch et dans le m&amp;ecirc;me temps les r&amp;eacute;f&amp;eacute;rences JavaScript de &lt;code&gt;jQuery&lt;/code&gt; et de &lt;code&gt;jQTouch&lt;/code&gt;. On va y mettre aussi une r&amp;eacute;f&amp;eacute;rence au fichier &lt;code&gt;mobile.js&lt;/code&gt;, que l&amp;#x27;on va cr&amp;eacute;er. Dans cette layout, le contenu de la page est englob&amp;eacute; dans une balise &lt;code&gt;div&lt;/code&gt; ayant comme classe &lt;code&gt;current&lt;/code&gt;. si cette page doit afficher un titre, alors il sera englob&amp;eacute; dans une autre &lt;code&gt;div&lt;/code&gt; de classe &lt;code&gt;toolbar&lt;/code&gt;. Pareillement, si on doit afficher un m&amp;eacute;ssage flash, il sera plac&amp;eacute; dans une autre &lt;code&gt;div&lt;/code&gt;, cette fois avec une classe &lt;code&gt;info&lt;/code&gt;. Enfin, on retourne &lt;code&gt;yield&lt;/code&gt; de ce qui doit &amp;ecirc;tre affich&amp;eacute; dans le template courant.&lt;/p&gt;

&lt;p&gt;ensuite, il nous faut &amp;eacute;crire le nouveau fichier &lt;code&gt;mobile.js&lt;/code&gt;. Tout ce qu&amp;#x27;on doit y mettre est un appel pour initaliser jQTouch.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/public/javascripts/mobile.js&lt;/p&gt;
&lt;pre class="javascript"&gt;
$.jQTouch({});
&lt;/pre&gt;

&lt;p&gt;La fonction d&amp;#x27;initialisation prend un &lt;a href="http://code.google.com/p/jqtouch/wiki/InitOptions"&gt;hash d&amp;#x27;options&lt;/a&gt;, mais ici, on ne va d&amp;eacute;finir aucun d&amp;#x27;eux. Quand on va recharger de nouveau la page mobile des projets, on peut voir que les styles jQTouch sont bien appliqu&amp;eacute;s, mais le rendu est assez moche, et aussi on n&amp;#x27;y voit aucun contenu.&lt;/p&gt;

&lt;div class="imageWrapper"&gt;
  &lt;img src="/system/photos/322/original/E199I07.png" width="814" height="293" alt="Le CSS jQTouch est maintenant appliqu&#233;."/&gt;
&lt;/div&gt;

&lt;p&gt;Si on revient au code de la vue mobile de la page, on peut remplacer le code substituable par un code qui listerait tous les projets et un compteur du nombre de t&amp;acirc;ches pour chacun des projets, et enfin un lien pour cr&amp;eacute;er un nouveau projet.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/views/projects/index.mobile.erb&lt;/p&gt;
&lt;pre class="ruby"&gt;
&amp;lt;% title &amp;quot;Projects&amp;quot; %&amp;gt;

&amp;lt;ul&amp;gt;
  &amp;lt;% for project in @projects %&amp;gt;
  &amp;lt;li class=&amp;quot;arrow&amp;quot;&amp;gt;
    &amp;lt;%= link_to h(project.name), project %&amp;gt;
    &amp;lt;small class=&amp;quot;counter&amp;quot;&amp;gt;&amp;lt;%= project.tasks.size %&amp;gt;&amp;lt;/small&amp;gt;

  &amp;lt;/li&amp;gt;
  &amp;lt;% end %&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;ul&amp;gt;&amp;lt;li class=&amp;quot;arrow&amp;quot;&amp;gt;&amp;lt;%= link_to &amp;quot;New Project&amp;quot;, new_project_path %&amp;gt;&amp;lt;/li&amp;gt;&amp;lt;/ul&amp;gt;

&lt;/pre&gt;

&lt;p&gt;Apr&amp;egrave;s avoir recharg&amp;eacute; de nouveau la page, on va voir une belle interface qui ressemble beaucoup &amp;agrave; une application mobile native.&lt;/p&gt;

&lt;div class="imageWrapper"&gt;
  &lt;img src="/system/photos/323/original/E199I08.png" width="784" height="350" alt="La version mobile de notre home page ressemble maintenant &amp;agrave; une application native."/&gt;
&lt;/div&gt;

&lt;p&gt;&amp;Eacute;videmment l&amp;#x27;interface sera bien plus petite lorsqu&amp;#x27;affich&amp;eacute;e sur un iPhone, mais cela fonctionnera de la m&amp;ecirc;me fa&amp;ccedil;on sur un navigateur d&amp;#x27;ordinateur.&lt;/p&gt; 

&lt;p&gt;Chaque vue de notre application aura aussi besoin d&amp;#x27;une version mobile. Cela rep&amp;eacute;sente bien trop de code &amp;agrave; vous pr&amp;eacute;senter, mais vous pouvez &lt;a href="http://github.com/ryanb/railscasts-episodes/tree/master/episode-199/"&gt;t&amp;eacute;l&amp;eacute;charger les sources&lt;/a&gt; sur la page Github de Ryan Bates. Une fois que cela est fait, on a une application mobile compl&amp;egrave;tment fonctionnelle, qui ressemble &amp;agrave; une application mobile.&lt;/p&gt;

&lt;div class="imageWrapper"&gt;
  &lt;img src="/system/photos/324/original/E199I09.png" width="783" height="285" alt="La page d'un nouveau projet sur la version mobile du site."/&gt;
&lt;/div&gt;

&lt;p&gt;Alors que l&amp;#x27;on a un bien meilleur rendu mobile de notre application, on a perdu la possibilit&amp;eacute; de basculer vers la version int&amp;eacute;grale. On va rajouter un bouton sur le c&amp;ocirc;t&amp;eacute; droit de la barre d&amp;#x27;outils (toolbar) du haut pour r&amp;eacute;activer cette fonctionalit&amp;eacute;.&lt;/p&gt;

&lt;p&gt;La toolbar est definie dans la layout mobile, et lui ajouter de nouveaux contr&amp;ocirc;les est facile, dans le sens o&amp;ugrave; les &amp;eacute;l&amp;eacute;ments de jQTouch sont definis par des balises HTML. On peut donc ajouter un nouveau bouton en cr&amp;eacute;ant un nouveau lien &amp;agrave; l&amp;#x27;int&amp;eacute;rieur de la div toolbar et en lui d&amp;eacute;finissant une classe &lt;code&gt;button&lt;/code&gt;.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/views/layouts/application.mobile.erb&lt;/p&gt;
&lt;pre class="ruby"&gt;
&amp;lt;div class=&amp;quot;toolbar&amp;quot;&amp;gt;
  &amp;lt;%= link_to &amp;quot;Back&amp;quot;, nil, :class =&amp;gt; &amp;quot;back&amp;quot; unless current_page? root_path %&amp;gt;

  &amp;lt;h1&amp;gt;&amp;lt;%=h yield(:title) %&amp;gt;&amp;lt;/h1&amp;gt;
  &amp;lt;%= link_to &amp;quot;Full Site&amp;quot;, root_url(:mobile =&amp;gt; 0), :class =&amp;gt; &amp;quot;button&amp;quot;, :rel =&amp;gt; &amp;quot;external&amp;quot; %&amp;gt;

   &amp;lt;%= yield(:toolbar) %&amp;gt;
&amp;lt;/div&amp;gt;
&lt;/pre&gt;

&lt;p&gt;On doit aussi d&amp;eacute;finir un attribut &lt;code&gt;rel&lt;/code&gt; ayant une valeur d&amp;#x27;&lt;code&gt;external&lt;/code&gt;, ainsi jQTouch traitera ce lien comme un appel externe &amp;agrave; un autre site. Si on ne fait pas cela, une requ&amp;ecirc;te AJAX sera faite, ce qui n&amp;#x27;est pas exactement ce que l&amp;#x27;on recherche.&lt;/p&gt; 

&lt;p&gt;Lorsqu&amp;#x27;on recharge la page une derni&amp;egrave;re fois, on aura un bouton sur chaque page, qui pourra nous emmener sur la version int&amp;eacute;grale du site.&lt;/p&gt;</description>
      <pubDate>Wed, 10 Feb 2010 23:00:26 +0000</pubDate>
      <guid>http://fr.asciicasts.com/episodes/199-appareils-mobiles</guid>
      <link>http://fr.asciicasts.com/episodes/199-appareils-mobiles</link>
    </item>
    <item>
      <title>Formulaire avec mod&#232;les imbriqu&#233;s (2&#232;me partie)</title>
      <description>&lt;p&gt;Dans l&amp;#x27;&amp;eacute;pisode pr&amp;eacute;c&amp;eacute;dent, nous avions abord&amp;eacute; comment cr&amp;eacute;er un formulaire pouvant g&amp;eacute;rer plusieurs mod&amp;egrave;les imbriqu&amp;eacute;s. Dans cette application, on avait cr&amp;eacute;&amp;eacute; pour cela un mod&amp;egrave;le Enqu&amp;ecirc;te &lt;code&gt;Survey&lt;/code&gt;, pour lequel chaque &lt;code&gt;Survey&lt;/code&gt; poss&amp;egrave;de plusieurs &lt;code&gt;Questions&lt;/code&gt; et chaque &lt;code&gt;Question&lt;/code&gt; ayant elle-m&amp;ecirc;me plusieurs r&amp;eacute;ponses &lt;code&gt;Answers&lt;/code&gt;.&lt;/p&gt; 

&lt;div class="imageWrapper"&gt;
  &lt;img src="/system/photos/300/original/E197I01.png" width="816" height="490" alt="Edition d&amp;#x27;une enqu&amp;ecirc;te."/&gt;
&lt;/div&gt;

&lt;p&gt;Dans les mod&amp;egrave;les &lt;code&gt;Survey&lt;/code&gt; et &lt;code&gt;Question&lt;/code&gt;, on a utilis&amp;eacute; &lt;code&gt;accepts_nested_attributes_for&lt;/code&gt; pour pouvoir cr&amp;eacute;er, &amp;eacute;diter et supprimer des enregistrements imbriqu&amp;eacute;s &amp;agrave; travers un seul mod&amp;egrave;le.&lt;/p&gt;

&lt;p&gt;Actuellement dans notre application, si on veut supprimer une question ou une r&amp;eacute;ponse, on doit utiliser un checkbox. Parall&amp;egrave;lement, on n&amp;#x27;a aucun autre moyen d&amp;#x27;ajouter de nouvelles questions ou r&amp;eacute;ponses au moyen du m&amp;ecirc;me formulaire. Dans cet &amp;eacute;pisode on se propose de r&amp;eacute;gler ces probl&amp;egrave;mes par l&amp;#x27;utilisation de JavaScript afin de modifier le formulaire existant au moyen de liens, pour cr&amp;eacute;er et supprimer des mod&amp;egrave;les dynamiquement.&lt;/p&gt;

&lt;p&gt;Le JavaScript que l&amp;#x27;on va &amp;eacute;crire implique quelques manipulations du DOM, aussi allons-nous utiliser &lt;a href="http://www.prototypejs.org"&gt;Prototype&lt;/a&gt; pour nous simplifier la t&amp;acirc;che.  Pour ajouter Prototype &amp;agrave; notre application, on va rajouter la ligne suivante dans la partie &amp;lt;head&amp;gt; de la layout de l&amp;#x27;application.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/views/layouts/application.html.erb&lt;/p&gt;
&lt;pre class="ruby"&gt;
&amp;lt;%= javascript_include_tag :defaults, :cache =&amp;gt; true %&amp;gt;
&lt;/pre&gt;
&lt;p&gt;Si vous pr&amp;eacute;f&amp;eacute;rez utiliser jQuery, c&amp;#x27;est tout &amp;agrave; fait possible et vous trouverez l&amp;#x27;&amp;eacute;quivalent jQuery &amp;agrave; la fin de cet &amp;eacute;pisode.&lt;/p&gt; 

&lt;h3&gt;Ajout de liens pour supprimer des r&amp;eacute;ponses&lt;/h3&gt;

&lt;p&gt;Commen&amp;ccedil;ons par la partie la plus facile: remplacer les checkbox, utilis&amp;eacute;s pour supprimer les questions et les r&amp;eacute;ponses, par des liens. Tout d&amp;#x27;abord, voyons le cas des r&amp;eacute;ponses.&lt;/p&gt;

&lt;p&gt;Le code responsable de l&amp;#x27;affichage de chaque r&amp;eacute;ponse se trouve dans le partial appel&amp;eacute; &lt;code&gt;answer_fields&lt;/code&gt; et ressemble &amp;agrave; ceci:&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/views/surveys/_answer_fields.html.erb&lt;/p&gt;
&lt;pre class="ruby"&gt;
&amp;lt;p&amp;gt;
  &amp;lt;%= f.label :content, &amp;quot;Answer&amp;quot; %&amp;gt;

  &amp;lt;%= f.text_field :content %&amp;gt;
  &amp;lt;%= f.check_box :_destroy %&amp;gt;
  &amp;lt;%= f.label :_destroy, &amp;quot;Remove&amp;quot; %&amp;gt;
&amp;lt;/p&amp;gt;
&lt;/pre&gt;
&lt;p&gt;Dans le code ci-dessus, se trouve le checkbox &lt;code&gt;_destroy&lt;/code&gt;, que nous voulons cocher pour supprimer la r&amp;eacute;ponse. On va le remplacer par un champ cach&amp;eacute;, dont la valeur sera d&amp;eacute;finie quand le lien &amp;ldquo;remove&amp;rdquo; sera cliqu&amp;eacute;. De cette fa&amp;ccedil;on, on pourra toujours indiquer quelle sera la r&amp;eacute;ponse &amp;agrave; supprimer.&lt;/p&gt;

&lt;p&gt;On va remplacer le label du code ci-dessus par un lien et utiliser &lt;code&gt;link_to_function&lt;/code&gt; pour cr&amp;eacute;er un lien qui d&amp;eacute;clenchera un appel Javascript lorsqu&amp;#x27;il sera cliqu&amp;eacute;.  Avec le champ cach&amp;eacute; et le lien, le code du partial devrait ressembler &amp;agrave; ceci:&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/views/surveys/_answer_fields.html.erb&lt;/p&gt;
&lt;pre class="ruby"&gt;
&amp;lt;p class=&amp;quot;fields&amp;quot;&amp;gt;
  &amp;lt;%= f.label :content, &amp;quot;Answer&amp;quot; %&amp;gt;

  &amp;lt;%= f.text_field :content %&amp;gt;
  &amp;lt;%= f.hidden_field :_destroy %&amp;gt;
  &amp;lt;%= link_to_function &amp;quot;remove&amp;quot;, &amp;quot;remove_fields(this)&amp;quot; %&amp;gt;
&amp;lt;/p&amp;gt;
&lt;/pre&gt;

&lt;p&gt;Quand le lien &amp;ldquo;remove&amp;rdquo; &amp;agrave; c&amp;ocirc;t&amp;eacute; d&amp;#x27;une r&amp;eacute;ponse est cliqu&amp;eacute;, cela va d&amp;eacute;clencher un appel &amp;agrave; une fonction JavaScript, appel&amp;eacute;e &lt;code&gt;remove_fields&lt;/code&gt;, qui sera pass&amp;eacute;e comme argument dans le lien, nous permettant ainsi d&amp;#x27;utiliser comme &amp;eacute;l&amp;eacute;ment de reference pour retrouver les autres &amp;eacute;l&amp;eacute;ments relatifs &amp;agrave; cette r&amp;eacute;ponse. Il n&amp;#x27;y a pas de moyen direct d&amp;#x27;avoir acc&amp;egrave;s &amp;agrave; tous ces champs, si bien que l&amp;#x27;on va ajouter un nom de class au paragraphe englobant tous ces &amp;eacute;l&amp;eacute;ments, de telle sorte qu&amp;#x27;on puisse les retrouver plus facilement.&lt;/p&gt;

&lt;p&gt;Ensuite il nous faut &amp;eacute;crire cette fonction &lt;code&gt;remove_fields&lt;/code&gt;. On va le faire dans le fichier &lt;code&gt;application.js&lt;/code&gt;, car c&amp;#x27;est un fichier qui est automatiquement charg&amp;eacute; dans nos pages, parce qu&amp;#x27;on a sp&amp;eacute;cifi&amp;eacute; la propri&amp;eacute;t&amp;eacute; JavaScript &lt;code&gt;:defaults&lt;/code&gt;.&lt;/p&gt; 

&lt;p class="codeFilePath"&gt;/public/javascripts/application.js&lt;/p&gt;
&lt;pre class="javascript"&gt;
function remove_fields(link) {
	$(link).previous(&amp;quot;input[type=hidden]&amp;quot;).value = &amp;quot;1&amp;quot;;
	$(link).up(&amp;quot;.fields&amp;quot;).hide();
}
&lt;/pre&gt;
&lt;p&gt;Cette fonction effectue deux actions. La premi&amp;egrave;re utilise la fonction Prototype &lt;a href="http://api.prototypejs.org/dom/element.html#previous-class_method"&gt;&lt;code&gt;previous&lt;/code&gt;&lt;/a&gt; pour trouver le premier champ cach&amp;eacute; relatif au lien qui l&amp;#x27;a appel&amp;eacute;, le champ _destroy, et lui assigne sa valeur &amp;agrave; &lt;code&gt;1&lt;/code&gt;, de telle sorte que la r&amp;eacute;ponse sera marqu&amp;eacute;e comme &amp;eacute;tant &amp;agrave; supprimer. Elle utilise ensuite &lt;a href="http://api.prototypejs.org/dom/element.html#up-class_method"&gt;&lt;code&gt;up&lt;/code&gt;&lt;/a&gt; pour remonter l&amp;#x27;arbre du DOM &amp;agrave; partir du lien, jusqu&amp;#x27;&amp;agrave; ce qu&amp;#x27;elle retrouve un &amp;eacute;l&amp;eacute;ment de la classe  &lt;code&gt;fields&lt;/code&gt;, qui est le nom de la classe que nous avons donn&amp;eacute; au paragraphe, englobant les champs r&amp;eacute;ponses, et qui le masque aussi lorsque la r&amp;eacute;ponse est cach&amp;eacute;e.&lt;/p&gt;

&lt;p&gt;Si maintenant on recharge la page enqu&amp;ecirc;te, on verra appara&amp;icirc;tre un lien en face de chaque r&amp;eacute;ponse.&lt;/p&gt;

&lt;div class="imageWrapper"&gt;
  &lt;img src="/system/photos/301/original/E197I02.png" width="816" height="471" alt="Les checkbox &amp;ldquo;remove&amp;rdquo; ont &amp;eacute;t&amp;eacute; remplac&amp;eacute; par des liens."/&gt;
&lt;/div&gt;

&lt;p&gt;Si on clique sur quelques liens, la valeur du champ cach&amp;eacute; &lt;code&gt;_destroy&lt;/code&gt; sera mise &amp;agrave; &lt;code&gt;1&lt;/code&gt; pour toutes ces r&amp;eacute;ponses comme &amp;eacute;tant &amp;agrave; supprimer et leurs champs dans le formulaire seront cach&amp;eacute;s.&lt;/p&gt;

&lt;div class="imageWrapper"&gt;
  &lt;img src="/system/photos/302/original/E197I03.png" width="816" height="471" alt="Les r&amp;eacute;ponses sont cach&amp;eacute;es quand on clique sur le lien &amp;ldquo;remove&amp;rdquo;."/&gt;
&lt;/div&gt;

&lt;p&gt;Notez bien que l&amp;#x27;on n&amp;#x27;utilise pas AJAX pour renvoyer les valeurs mises &amp;agrave; jour du formulaire, lorsque l&amp;#x27;on clique sur le lien et bien que l&amp;#x27;on masque imm&amp;eacute;diatement les r&amp;eacute;ponses supprim&amp;eacute;es, rien ne sera mis &amp;agrave; jour dans la base de donn&amp;eacute;es tant que le formulaire n&amp;#x27;aura pas &amp;eacute;t&amp;eacute; envoy&amp;eacute;. Lorsqu&amp;#x27;on envoie le formulaire, les r&amp;eacute;ponses seront supprim&amp;eacute;es et on verra le r&amp;eacute;sultat appara&amp;icirc;tre sur la &lt;code&gt;show&lt;/code&gt; de l&amp;#x27;enqu&amp;ecirc;te.&lt;/p&gt;

&lt;div class="imageWrapper"&gt;
  &lt;img src="/system/photos/303/original/E197I04.png" width="816" height="471" alt="Les r&#233;ponses sont maintenant supprim&#233;es."/&gt;
&lt;/div&gt;

&lt;h3&gt;Suppression des Questions&lt;/h3&gt;
&lt;p&gt;A pr&amp;eacute;sent que l&amp;#x27;on peut supprimer des r&amp;eacute;ponses via des liens, on va s&amp;#x27;int&amp;eacute;resser au cas des questions. La mani&amp;egrave;re de supprimer une question est fondamentalement la m&amp;ecirc;me que celle pour une r&amp;eacute;ponse, on va pouvoir r&amp;eacute;utiliser une partie du code que l&amp;#x27;on avait &amp;eacute;crit un peu plus t&amp;ocirc;t.&lt;/p&gt;
&lt;p&gt;Comme on l&amp;#x27;a fait pour les r&amp;eacute;ponses, on va remplacer le checkbox et le label par un champ cach&amp;eacute; et on va reprendre cette partie du code du partial &lt;code&gt;answer_fields&lt;/code&gt; et on va le placer dans une nouvelle helper m&amp;eacute;thode appel&amp;eacute;e &lt;code&gt;link_to_remove_fields&lt;/code&gt;,  en lui passant dans le lien, le texte qu&amp;#x27;on veut lui voire appara&amp;icirc;tre et la variable form &lt;code&gt;f&lt;/code&gt;.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/views/surveys/_answer_fields.html.erb&lt;/p&gt;
&lt;pre class="ruby"&gt;
&amp;lt;p class=&amp;quot;fields&amp;quot;&amp;gt;
  &amp;lt;%= f.label :content, &amp;quot;Answer&amp;quot; %&amp;gt;
  &amp;lt;%= f.text_field :content %&amp;gt;
  &amp;lt;%= link_to_remove_fields &amp;quot;remove&amp;quot;, f %&amp;gt;

&amp;lt;/p&amp;gt;
&lt;/pre&gt;
&lt;p&gt;On va maintenant &amp;eacute;crire cette m&amp;eacute;thode dans le fichier &lt;code&gt;application_helper&lt;/code&gt;.&lt;/p&gt;
&lt;p class="codeFilePath"&gt;/app/helpers/application_helper.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;
# Methods added to this helper will be available to all templates in the application.
module ApplicationHelper
  def link_to_remove_fields(name, f)
    f.hidden_field(:_destroy) + link_to_function(name, &amp;quot;remove_fields(this)&amp;quot;)
  end
end
&lt;/pre&gt;

&lt;p&gt;Les m&amp;eacute;thodes qui cr&amp;eacute;ent des champs de formulaire retournent des cha&amp;icirc;nes de caract&amp;egrave;res (strings), si bien que l&amp;#x27;on peut concatenater le HTML g&amp;eacute;n&amp;eacute;r&amp;eacute; par les m&amp;eacute;thodes &lt;code&gt;f.hidden_field&lt;/code&gt; et &lt;code&gt;link_to_function&lt;/code&gt;et les retourner dans le partial.&lt;/p&gt;
&lt;p&gt;On pourra aussi utiliser notre m&amp;eacute;thode dans le partial &lt;code&gt;question_fields&lt;/code&gt;.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/views/surveys/_question_fields.html.erb&lt;/p&gt;
&lt;pre class="ruby"&gt;
&amp;lt;div class=&amp;quot;fields&amp;quot;&amp;gt;
  &amp;lt;p&amp;gt;
    &amp;lt;%= f.label :content, &amp;quot;Question&amp;quot; %&amp;gt;
    &amp;lt;%= link_to_remove_fields &amp;quot;remove&amp;quot;, f%&amp;gt;&amp;lt;br /&amp;gt;

    &amp;lt;%= f.text_area :content, :rows =&amp;gt; 3 %&amp;gt;&amp;lt;br /&amp;gt;
  &amp;lt;/p&amp;gt;
  &amp;lt;% f.fields_for :answers do |builder| %&amp;gt;
    &amp;lt;%= render &amp;#x27;answer_fields&amp;#x27;, :f =&amp;gt; builder %&amp;gt;

  &amp;lt;% end %&amp;gt;
&amp;lt;/div&amp;gt;
&lt;/pre&gt;
&lt;p&gt;Comme notre fonction JavaScript &lt;code&gt;remove_fields&lt;/code&gt; recherche un &amp;eacute;l&amp;eacute;ment de la classe &lt;code&gt;fields&lt;/code&gt; lorsque l&amp;#x27;on masque une question ou une r&amp;eacute;ponse, on a englob&amp;eacute; tout le partial dans un &amp;eacute;l&amp;eacute;ment &lt;code&gt;div&lt;/code&gt; avec ce m&amp;ecirc;me nom de classe, de telle sorte que lorsqu&amp;#x27;on clique sur un lien &amp;ldquo;remove&amp;rdquo; pour une question, cette question sera masqu&amp;eacute;e en m&amp;ecirc;me temps que ses r&amp;eacute;ponses.&lt;/p&gt;

&lt;p&gt;Si maintenant, on regarde la page &lt;code&gt;edit&lt;/code&gt; d&amp;#x27;une enqu&amp;ecirc;te et que l&amp;#x27;on clique sur le lien &amp;ldquo;remove&amp;rdquo; d&amp;#x27;une question, celle-ci va &amp;ecirc;tre supprim&amp;eacute;e en m&amp;ecirc;me temps que ses r&amp;eacute;ponses qui l&amp;#x27;accompagnent, et quand on envoie le formulaire, la question et toutes ses r&amp;eacute;ponses seront supprim&amp;eacute;es de l&amp;#x27;enqu&amp;ecirc;te.&lt;/p&gt;

&lt;div class="imageWrapper"&gt;
  &lt;img src="/system/photos/304/original/E197I05.png" width="815" height="423" alt="La question a &amp;eacute;t&amp;eacute; supprim&amp;eacute;e avec ses r&amp;eacute;ponses."/&gt;
&lt;/div&gt;

&lt;h3&gt;Ajout de Questions et R&amp;eacute;ponses&lt;/h3&gt;

&lt;p&gt;Et maintenant, la partie la plus d&amp;eacute;licate: ajouter de nouvelles questions and r&amp;eacute;ponses. On veut des liens sur le formulaire qui cr&amp;eacute;eront les nouveaux champs dynamiquement lorsqu&amp;#x27;on cliquera dessus. Ce qui rend ceci difficile est que le JavaScript aura besoin d&amp;#x27;avoir acc&amp;egrave;s &amp;agrave; un ensemble de champs vides pour que l&amp;#x27;on puisse cr&amp;eacute;er une nouvelle question ou r&amp;eacute;ponse, lorsque le lien est cliqu&amp;eacute;.&lt;/p&gt;

&lt;p&gt;Pour ce faire, on va &amp;eacute;crire une nouvelle m&amp;eacute;thode dans l&amp;#x27;application helper, appel&amp;eacute;e &lt;code&gt;link_to_add_fields&lt;/code&gt;. On pourra utiliser cette m&amp;eacute;thode d&amp;egrave;s lors que l&amp;#x27;on a besoin d&amp;#x27;afficher un lien pour ajouter les champs d&amp;#x27;une nouvelle question, ou r&amp;eacute;ponse, sur le formulaire. Le code de cette m&amp;eacute;thode ressemblera &amp;agrave; ceci:&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/helpers/application_helper.rb&lt;/p&gt;
&lt;pre class="ruby"&gt;
def link_to_add_fields(name, f, association)
  new_object = f.object.class.reflect_on_association(association).klass.new
  fields = f.fields_for(association, new_object, :child_index =&amp;gt; &amp;quot;new_#{association}&amp;quot;) do |builder|
    render(association.to_s.singularize + &amp;quot;_fields&amp;quot;, :f =&amp;gt; builder)
  end
  link_to_function(name, h(&amp;quot;add_fields(this, \&amp;quot;#{association}\&amp;quot;, \&amp;quot;#{escape_javascript(fields)}\&amp;quot;)&amp;quot;))
end

&lt;/pre&gt;
&lt;p&gt;Cette m&amp;eacute;thode prend trois arguments: &lt;code&gt;name&lt;/code&gt;, qui sera le texte du lien, &lt;code&gt;f&lt;/code&gt;, l&amp;#x27;objet form builder et l&amp;#x27;&lt;code&gt;association&lt;/code&gt;, qui dans ce cas sera soit &amp;ldquo;questions&amp;rdquo; soit &amp;ldquo;answers&amp;rdquo;.&lt;/p&gt;

&lt;p&gt;La premi&amp;egrave;re ligne de cette m&amp;eacute;thode cr&amp;eacute;e une nouvelle instance de la classe de cette nouvelle association, c-&amp;agrave;-d une nouvelle &lt;code&gt;Question&lt;/code&gt; ou &lt;code&gt;Answer&lt;/code&gt;. Cela signifie que l&amp;#x27;on a un objet template, qui va nous servir &amp;agrave; cr&amp;eacute;er les nouveaux champs du formulaire.&lt;/p&gt;

&lt;p&gt;La seconde partie du code construit une cha&amp;icirc;ne avec les champs du formulaire de cet objet, de telle sorte que l&amp;#x27;on peut les ins&amp;eacute;rer dans la fonction javascript qui les ajoutera au formulaire quand le lien sera cliqu&amp;eacute;. Ceci est possible en appelant le partial appropri&amp;eacute;, pass&amp;eacute; par le form builder f. La seule chose vraiment nouvelle ici est &lt;code&gt;:child_index&lt;/code&gt;. On a fait cela pour avoir une r&amp;eacute;f&amp;eacute;rence de la nouvelle question ou r&amp;eacute;ponse lors de la cr&amp;eacute;ation des champs. Dans le code JavaScript, on va remplacer ce nom par un identifiant unique bas&amp;eacute; sur l&amp;#x27;heure courante. De cette fa&amp;ccedil;on, chaque fois que l&amp;#x27;on va cr&amp;eacute;er une question ou r&amp;eacute;ponse, on aura un index unique, qui nous permettra de l&amp;#x27;identifier lorsqu&amp;#x27;on enverra le formulaire.&lt;/p&gt;

&lt;p&gt;On va de nouveau utiliser la m&amp;eacute;thode &lt;code&gt;link_to_function&lt;/code&gt;, lui passant le nom du lien etun appel &amp;agrave; la fonction JavaScript appel&amp;eacute;e &lt;code&gt;add_fields&lt;/code&gt;, &amp;agrave; laquelle on lui passe le lien, le nom de l&amp;#x27;association et une cha&amp;icirc;ne contenant le texte &amp;eacute;chapp&amp;eacute; des champs du formulaire.&lt;/p&gt;

&lt;p&gt;Maintenant, revenons au JavaScript et &amp;eacute;crivons la fonction &lt;code&gt;add_fields&lt;/code&gt;.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/public/javascripts/application.js&lt;/p&gt;
&lt;pre class="javascript"&gt;
function add_fields(link, association, content) {
  var new_id = new Date().getTime();
  var regexp = new RegExp(&amp;quot;new_&amp;quot; + association, &amp;quot;g&amp;quot;);
  $(link).up().insert({
	before: content.replace(regexp, new_id)
  });
}
&lt;/pre&gt;
&lt;p&gt;Cette fonction prend les 3 arguments, dont on a parl&amp;eacute; un peu plus t&amp;ocirc;t: le lien qui a &amp;eacute;t&amp;eacute; cliqu&amp;eacute;, le nom de l&amp;#x27;association et une cha&amp;icirc;ne contenant le HTML des champs du formulaire. La premi&amp;egrave;re chose que cette fonction fait est de cr&amp;eacute;er un nouvel id pour les &amp;eacute;l&amp;eacute;ments du formulaire. Si on cr&amp;eacute;e plusieurs nouvelles questions ou r&amp;eacute;ponses, on ne veut pas qu&amp;#x27;ils aient tous le m&amp;ecirc;me index, sinon ils seraient consid&amp;eacute;r&amp;eacute;s comme appartenant au m&amp;ecirc;me mod&amp;egrave;le lors de l&amp;#x27;insertion. On va utiliser l&amp;#x27;heure courante pour rendre l&amp;#x27;id unique dans une expression r&amp;eacute;guli&amp;egrave;re pour remplacer la cha&amp;icirc;ne &amp;ldquo;new_question&amp;rdquo; ou &amp;ldquo;new_answer&amp;rdquo; des champs du formulaire par ce nouvel identifiant unique. Ceci &amp;eacute;tant fait, on va ins&amp;eacute;rer la  cha&amp;icirc;ne des champs du formulaire &amp;agrave; la bonne place dans le DOM.&lt;/p&gt;

&lt;p&gt;Ceci marque la fin de la partie la plus d&amp;eacute;licate. Tout ce que l&amp;#x27;on a &amp;agrave; faire maintenant, c&amp;#x27;est de rajouter les liens eux-m&amp;ecirc;mes. Dans le partial &lt;code&gt;question_fields&lt;/code&gt;, on va rajouter un lien &lt;code&gt;link_to_add_fields&lt;/code&gt;, qui permet d&amp;#x27;ajouter une nouvelle r&amp;eacute;ponse, en lui passant comme param&amp;egrave;tre  :answers comme de l&amp;#x27;association ,car une question poss&amp;egrave;de plusieurs r&amp;eacute;ponses.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/views/surveys/_question_fields.html.erb&lt;/p&gt;
&lt;pre class="ruby"&gt;
&amp;lt;div class=&amp;quot;fields&amp;quot;&amp;gt;

  &amp;lt;p&amp;gt;
    &amp;lt;%= f.label :content, &amp;quot;Question&amp;quot; %&amp;gt;
    &amp;lt;%= link_to_remove_fields &amp;quot;remove&amp;quot;, f %&amp;gt;&amp;lt;br /&amp;gt;
    &amp;lt;%= f.text_area :content, :rows =&amp;gt; 3 %&amp;gt;&amp;lt;br /&amp;gt;

  &amp;lt;/p&amp;gt;
  &amp;lt;% f.fields_for :answers do |builder| %&amp;gt;
    &amp;lt;%= render &amp;#x27;answer_fields&amp;#x27;, :f =&amp;gt; builder %&amp;gt;
  &amp;lt;% end %&amp;gt;
  &amp;lt;p&amp;gt;&amp;lt;%= link_to_add_fields &amp;quot;Add Answer&amp;quot;, f, :answers %&amp;gt;&amp;lt;/p&amp;gt;

&amp;lt;/div&amp;gt;
&lt;/pre&gt;
&lt;p&gt;On peut faire la m&amp;ecirc;me chose dans le formulaire enqu&amp;ecirc;te pour ajouter un lien &amp;ldquo;Add Question&amp;rdquo;.&lt;/p&gt;

&lt;p class="codeFilePath"&gt;/app/views/surveys/_form.html.erb&lt;/p&gt;
&lt;pre class="ruby"&gt;
&amp;lt;% form_for @survey do |f| %&amp;gt;
  &amp;lt;%= f.error_messages %&amp;gt;

  &amp;lt;p&amp;gt;
    &amp;lt;%= f.label :name %&amp;gt;&amp;lt;br /&amp;gt;
    &amp;lt;%= f.text_field :name %&amp;gt;
  &amp;lt;/p&amp;gt;
  &amp;lt;% f.fields_for :questions do |builder| %&amp;gt;
    &amp;lt;%= render &amp;#x27;question_fields&amp;#x27;, :f =&amp;gt; builder %&amp;gt;

  &amp;lt;% end %&amp;gt;
  &amp;lt;p&amp;gt;&amp;lt;%= link_to_add_fields &amp;quot;Add Question&amp;quot;, f, :questions %&amp;gt;
  &amp;lt;p&amp;gt;&amp;lt;%= f.submit &amp;quot;Submit&amp;quot; %&amp;gt;&amp;lt;/p&amp;gt;

&amp;lt;% end %&amp;gt;
&lt;/pre&gt;
&lt;p&gt;Si on recharge la page enqu&amp;ecirc;te maintenant, on devrait voir les liens pour ajouter une nouvelle question ou r&amp;eacute;ponse et lorsqu&amp;#x27;on clique sur l&amp;#x27;un d&amp;#x27;eux, un nouveau champ va appara&amp;icirc;tre sur le formulaire.&lt;/p&gt;

&lt;div class="imageWrapper"&gt;
  &lt;img src="/system/photos/305/original/E197I06.png" width="800" height="546" alt="A new blank field appears when we click the &amp;ldquo;Add Answer&amp;rdquo; link."/&gt;
&lt;/div&gt;
&lt;p class="title"&gt;Un champ r&amp;eacute;ponse appara&amp;icirc;t sur le formulaire, lorqu&amp;#x27;on clique sur le lien  &amp;ldquo;Add Answer&amp;rdquo;.&lt;/p&gt;

&lt;p&gt;Si on remplit le nouveau champ r&amp;eacute;ponse ci-dessus avec &amp;ldquo;jQuery&amp;rdquo; et que l&amp;#x27;on soumet le formulaire, la nouvelle r&amp;eacute;ponse sera ajout&amp;eacute;e.&lt;/p&gt;

&lt;div class="imageWrapper"&gt;
  &lt;img src="/system/photos/306/original/E197I07.png" width="801" height="375" alt="La nouvelle question a &#233;t&#233; ajout&#233;e."/&gt;
&lt;/div&gt;

&lt;p&gt;Nous avons atteint notre but et maintenant nous avons un formulaire, sur lesquel on peut dynamiquement ajouter ou supprimer des champs et avoir la base de donn&amp;eacute;es mise &amp;agrave; jour de fa&amp;ccedil;on appropri&amp;eacute;e, lorsque le formulaire est envoy&amp;eacute;.&lt;/p&gt;

&lt;h3&gt;Alternative utilisant jQuery&lt;/h3&gt;

&lt;p&gt;Le code JavaScript, que l&amp;#x27;on a &amp;eacute;crit dans cet &amp;eacute;pisode fonctionne avec Prototype. Si vous pr&amp;eacute;f&amp;eacute;rez utilier jQuery, le code devrait ressembler &amp;agrave; ceci:&lt;/p&gt;
&lt;pre class="javascript"&gt;
function remove_fields(link) {
	$(link).prev(&amp;quot;input[type=hidden]&amp;quot;).val(&amp;quot;1&amp;quot;);
	$(link).closest(&amp;quot;.fields&amp;quot;).hide();
}

function add_fields(link, association, content) {
	var new_id = new Date().getTime();
	var regexp = new RegExp(&amp;quot;new_&amp;quot; + association, &amp;quot;g&amp;quot;);
	$(link).parent().before(content.replace(regexp, new_id));
}

&lt;/pre&gt;
&lt;p&gt;Ce code est tr&amp;egrave;s semblable au code pour Prototype, que l&amp;#x27;on a pu &amp;eacute;crire.&lt;/p&gt;

&lt;p&gt;Certains d&amp;#x27;entre vous seront peut-&amp;ecirc;tre choqu&amp;eacute;s que le JavaScript que nous avons &amp;eacute;crit manque un peu de discr&amp;eacute;tion. Bien qu&amp;#x27;une solution discr&amp;egrave;te soit toujours pr&amp;eacute;f&amp;eacute;rable, il n&amp;#x27;y en a pas vraiment pour notre probl&amp;egrave;me, qui soit suffisamment simple &amp;agrave; pr&amp;eacute;senter dans cet &amp;eacute;pisode. Ryan Bates travaille actuellement sur un plugin appel&amp;eacute; &lt;a href="http://github.com/ryanb/nested_form"&gt;nested_form&lt;/a&gt;, utilisant jQuery et qui permettra de g&amp;eacute;rer des formulaires imbriqu&amp;eacute;s de fa&amp;ccedil;on discr&amp;egrave;te. Ce plugin en est encore &amp;agrave; un stade primitif, et s&amp;#x27;il peut vous &amp;ecirc;tre utile, pensez &amp;agrave; venir le visiter de temps &amp;agrave; autre et &amp;agrave; suivre ses &amp;eacute;volutions.&lt;/p&gt;</description>
      <pubDate>Tue, 09 Feb 2010 20:57:29 +0000</pubDate>
      <guid>http://fr.asciicasts.com/episodes/197-Formulaire-avec-modeles-imbriques-2eme-partie</guid>
      <link>http://fr.asciicasts.com/episodes/197-Formulaire-avec-modeles-imbriques-2eme-partie</link>
    </item>
    <item>
      <title>Formulaire avec mod&#232;les imbriqu&#233;s (1&#232;re partie)</title>
      <description>  &lt;p&gt;En 2007, une &lt;a href="http://railscasts.com/episodes/73-complex-forms-part-1"&gt;s&amp;eacute;rie d&amp;rsquo;&amp;eacute;pisodes &lt;/a&gt; couvrait la cr&amp;eacute;ation de formulaires complexes, qui pouvaient g&amp;eacute;rer plusieurs mod&amp;egrave;les dans le m&amp;ecirc;me formulaire. Cette s&amp;eacute;rie est maintenant un peu d&amp;eacute;pass&amp;eacute;e et &amp;agrave; pr&amp;eacute;sent, on va aborder des techniques plus modernes pour g&amp;eacute;rer des formulaires incluant plusieurs mod&amp;egrave;les.&lt;/p&gt;

  &lt;p&gt;Une des diff&amp;eacute;rences majeures dans l&amp;rsquo;approche de ce probl&amp;egrave;me est la m&amp;eacute;thode &lt;a href="http://api.rubyonrails.org/classes/ActiveRecord/NestedAttributes/ClassMethods.html"&gt;accepts_nested_attributes_for&lt;/a&gt;, qui a &amp;eacute;t&amp;eacute; ajout&amp;eacute;e &amp;agrave; Rails 2.3. Nous allons l&amp;rsquo;utiliser tout au long de cette s&amp;eacute;rie, si bien qu&amp;rsquo;il vous faudra une version de Rails r&amp;eacute;cente (&amp;gt;2.3) pour que vous puissiez utiliser cette technique dans votre propre application.&lt;/p&gt;

  &lt;p&gt;La &lt;a href= "http://api.rubyonrails.org/classes/ActiveRecord/NestedAttributes/ClassMethods.html"&gt;documentation&lt;/a&gt; est int&amp;eacute;ressante &amp;agrave; lire et montre bien comment l&amp;rsquo;utiliser avec des attributs imbriqu&amp;eacute;s sur une simple mise &amp;agrave; jour, mais cela devient moins &amp;eacute;vident lorsqu&amp;rsquo;il faut l&amp;rsquo;utiliser au niveau de la vue elle-m&amp;ecirc;me. C&amp;rsquo;est ce que nous allons voir.&lt;/p&gt;

  &lt;h3&gt;Notre application &amp;lsquo;Survey&amp;rsquo;&lt;/h3&gt;
  &lt;p&gt;Tout d&amp;rsquo;abord, l&amp;rsquo;objectif de cette application a pour but de g&amp;eacute;rer des enqu&amp;ecirc;tes (surveys).
  Cette application comportera un formulaire (complexe) pour cr&amp;eacute;er et modifier des enqu&amp;ecirc;tes, nous permettant d&amp;rsquo;entrer un nom pour l&amp;rsquo;enqu&amp;ecirc;te, ainsi qu&amp;rsquo;un certain nombre de questions et chaque question pouvant avoir plusieurs r&amp;eacute;ponses. Le formulaire comportera aussi des liens pour ajouter ou retirer dynamiquement des questions et des r&amp;eacute;ponses &amp;agrave; partir d&amp;rsquo;une m&amp;ecirc;me enqu&amp;ecirc;te.&lt;/p&gt;

  &lt;div class="imageWrapper"&gt; 
   &lt;img src="/system/photos/290/original/E196I01.png" width="815" height="598" alt="Le formulaire pour cr&amp;eacute;er et modifier les enqu&amp;ecirc;tes." /&gt; 
  &lt;/div&gt; 
  &lt;p class="title"&gt;Le formulaire pour cr&amp;eacute;er et modifier les enqu&amp;ecirc;tes.&lt;/p&gt; 

  &lt;p&gt;Ce que nous avons ici est une association fortement imbriqu&amp;eacute;e, dans laquelle une enqu&amp;ecirc;te a plusieurs questions, qui ont elles-m&amp;ecirc;mes plusieurs r&amp;eacute;ponses. Dans les &amp;eacute;pisodes pr&amp;eacute;c&amp;eacute;dents sur les formulaires complexes, il n&amp;rsquo;&amp;eacute;tait pas possible de cr&amp;eacute;er des formulaires avec un tel type de relation, mais maintenant, depuis Rails 2.3, c&amp;rsquo;est possible.&lt;/p&gt;

  &lt;h3&gt;Pour commencer&lt;/h3&gt;
  &lt;p&gt;Nous allons d&amp;eacute;marrer de z&amp;eacute;ro cette application d&amp;rsquo;enqu&amp;ecirc;tes et nous commencerons donc par cr&amp;eacute;er une application Rails que nous appellerons: &lt;code&gt;surveysays&lt;/code&gt;.&lt;/p&gt;
  &lt;pre class="terminal"&gt;rails surveysays&lt;/pre&gt; 
  &lt;p&gt;Pour simplifer l&amp;rsquo;&amp;eacute;criture, on utilisera 2 des &lt;a href="http://github.com/ryanb/nifty-generators"&gt;g&amp;eacute;n&amp;eacute;rateurs de Ryan Bates&lt;/a&gt; et on commencera par nifty_layout pour g&amp;eacute;n&amp;eacute;rer un mod&amp;egrave;le de page (layout) pour  toute l&amp;rsquo;application.&lt;/p&gt;
  &lt;pre class="terminal"&gt;script/generate nifty_layout&lt;/pre&gt; 
  &lt;p&gt;Notre application comportera 3 mod&amp;egrave;les: &lt;code&gt;Survey&lt;/code&gt; (Enqu&amp;ecirc;te), &lt;code&gt;Question&lt;/code&gt;, &lt;code&gt;Answer&lt;/code&gt; (R&amp;eacute;ponse). Commen&amp;ccedil;ons par les enqu&amp;ecirc;tes et utilisons le g&amp;eacute;n&amp;eacute;rateur nifty_scaffold pour cr&amp;eacute;er un scaffold. Survey aura un seul attribut, son nom (name).&lt;/p&gt;
  &lt;pre class="terminal"&gt;script/generate nifty_scaffold survey name:string&lt;/pre&gt; 
  &lt;p&gt;Ensuite lan&amp;ccedil;ons la migration pour cr&amp;eacute;er la table des enqu&amp;ecirc;tes dans la base de donn&amp;eacute;es.&lt;/p&gt;
  &lt;pre class="terminal"&gt;rake db:migrate&lt;/pre&gt;
  &lt;p&gt;Si on regarde de plus pr&amp;egrave;s les fichiers g&amp;eacute;n&amp;eacute;r&amp;eacute;s par le scaffold, on peut &amp;agrave; pr&amp;eacute;sent lister, cr&amp;eacute;er et modifier les enqu&amp;ecirc;tes &amp;agrave; travers un formulaire basique sur lequel nous allons nous appuyer. &lt;/p&gt;
  &lt;div class="imageWrapper"&gt; 
    &lt;img src="/system/photos/291/original/E196I02.png" width="800" height="343" alt="Formulaire basique g&amp;eacute;n&amp;eacute;r&amp;eacute; par le scaffold."/&gt; 
  &lt;/div&gt;

  &lt;p&gt;La premi&amp;egrave;re &amp;eacute;tape est de cr&amp;eacute;er le mod&amp;egrave;le &lt;code&gt;Question&lt;/code&gt; des questions. Il incluera un champ &lt;code&gt;survey_id&lt;/code&gt; et un champ &lt;code&gt;contenu&lt;/code&gt; (content) r&amp;eacute;f&amp;eacute;rent au texte de la question.&lt;/p&gt;
  &lt;p&gt;Ceci &amp;eacute;tant fait, migrons une nouvelle fois pour cr&amp;eacute;er la table questions.&lt;/p&gt;

  &lt;p&gt;L&amp;rsquo;&amp;eacute;tape suivante est de cr&amp;eacute;er la relation entre &lt;code&gt;Survey&lt;/code&gt; et &lt;code&gt;Question&lt;/code&gt; dans leur mod&amp;egrave;le respectif.&lt;/p&gt;
  &lt;pre class="codeFilePath"&gt;/app/models/question.rb&lt;/pre&gt; 
  &lt;pre class="ruby"&gt; 
  class Question &amp;lt; ActiveRecord::Base
    belongs_to :survey
  end
  &lt;/pre&gt; 
  &lt;pre class="codeFilePath"&gt;/app/models/survey.rb&lt;/pre&gt; 
  &lt;pre class="ruby"&gt; 
  class Survey &amp;lt; ActiveRecord::Base
    has_many :questions, :dependent =&amp;gt; :destroy
  end
  &lt;/pre&gt; 
  &lt;p&gt;Notez que dans le mod&amp;egrave;le &lt;code&gt;Survey&lt;/code&gt; nous avons utilis&amp;eacute; &lt;code&gt;:dependent =&amp;gt; :destroy&lt;/code&gt; 
  de telle sorte que si on supprime une enqu&amp;ecirc;te, les questions le seront aussi.&lt;/p&gt; 
  &lt;p&gt;Dans le mod&amp;egrave;le &lt;code&gt;Survey&lt;/code&gt; nous allons utiliser &lt;code&gt;accepts_nested_attributes_for&lt;/code&gt; afin de g&amp;eacute;rer les questions &amp;agrave; travers le mod&amp;egrave;le &lt;code&gt;Survey&lt;/code&gt;. Ce faisant, nous pouvons cr&amp;eacute;er, modifier ou d&amp;eacute;truire des questions lorsque nous mettons &amp;agrave; jour un attribut d&amp;rsquo;une enqu&amp;ecirc;te.&lt;/p&gt;
  &lt;pre class="codeFilePath"&gt;/app/models/survey.rb&lt;/pre&gt; 
  &lt;pre class="ruby"&gt; 
    class Survey &amp;lt; ActiveRecord::Base
      has_many :questions, :dependent =&amp;gt; :destroy
      accepts_nested_attributes_for :questions
    end
  &lt;/pre&gt; 

  &lt;h3&gt;Cr&amp;eacute;ation du formulaire&lt;/h3&gt; 
  &lt;p&gt;Maintenant que les mod&amp;egrave;les &lt;code&gt;Survey&lt;/code&gt; et &lt;code&gt;Question&lt;/code&gt; sont bien &amp;eacute;tablis, nous pouvons pousuivre avec le formulaire des enqu&amp;ecirc;tes. Ce que nous voulons faire &amp;agrave; pr&amp;eacute;sent, c&amp;rsquo;est d&amp;rsquo;ajouter dans les champs pour chaque question de l&amp;rsquo;enqu&amp;ecirc;te. Nous pouvons utiliser  la m&amp;eacute;thode&lt;code&gt;fields_for&lt;/code&gt;
  pour g&amp;eacute;rer les champs associ&amp;eacute;s. Le g&amp;eacute;n&amp;eacute;rateur va rendre un label et une zone de texte pour chaque question.&lt;/p&gt;
  &lt;pre class="codeFilePath"&gt;/app/views/survey/_form.html.erb&lt;/pre&gt; 
  &lt;pre class="ruby"&gt; 
  &amp;lt;% form_for @survey do |f| %&amp;gt;
    &amp;lt;%= f.error_messages %&amp;gt;
    &amp;lt;p&amp;gt;
      &amp;lt;%= f.label :name %&amp;gt;&amp;lt;br /&amp;gt;
      &amp;lt;%= f.text_field :name %&amp;gt;
    &amp;lt;/p&amp;gt;
    &amp;lt;% f.fields_for :questions do |builder| %&amp;gt;
    &amp;lt;p&amp;gt;
      &amp;lt;%= builder.label :content, &amp;quot;Question&amp;quot; %&amp;gt;&amp;lt;br /&amp;gt;
      &amp;lt;%= builder.text_area :content, :rows =&amp;gt; 3 %&amp;gt;
    &amp;lt;/p&amp;gt;
    &amp;lt;% end %&amp;gt;
    &amp;lt;p&amp;gt;&amp;lt;%= f.submit &amp;quot;Submit&amp;quot; %&amp;gt;&amp;lt;/p&amp;gt;
  &amp;lt;% end %&amp;gt;
  &lt;/pre&gt;
  &lt;p&gt;Lorsque nous rechargeons le formulaire, il ressemble &amp;agrave; ce qu&amp;rsquo;il &amp;eacute;tait auparavant. Parce qu&amp;rsquo;une nouvelle enqu&amp;ecirc;te ne poss&amp;egrave;de aucune question associ&amp;eacute;e, cela n&amp;rsquo;affichera aucun champ question. Au final, nous voulons avoir un lien &amp;ldquo;Add Question&amp;rdquo; sur le formulaire, mais pour l&amp;rsquo;instant nous allons cr&amp;eacute;er seulement quelques questions avec l&amp;rsquo;action new du &lt;code&gt;SurveyController&lt;/code&gt;.&lt;/p&gt; 
  &lt;pre class="codeFilePath"&gt;/app/controllers/surveys_controller.rb&lt;/pre&gt; 
  &lt;pre class="ruby"&gt; 
  def new
    @survey = Survey.new
    3.times { @survey.questions.build }
  end
  &lt;/pre&gt; 
  &lt;p&gt;Ceci va g&amp;eacute;n&amp;eacute;rer 3 questions pour une nouvelle enqu&amp;ecirc;te, que nous voyons appara&amp;icirc;tre lorsque nous rechargeons la page. Remplissons maintenant le nom et les 2 premi&amp;egrave;res questions puis souemttons la nouvelle enqu&amp;ecirc;te.&lt;/p&gt;
   &lt;div class="imageWrapper"&gt; 
  &lt;img src="/system/photos/292/original/E196I03.png" width="800" height="570" alt="Remplir le formulaire new survey."/&gt; 
   &lt;/div&gt; 
  &lt;p&gt;Lorsque nous soumettons l&amp;rsquo;enqu&amp;ecirc;te, un nouvel enregistrement &lt;code&gt;Survey&lt;/code&gt; va &amp;ecirc;tre cr&amp;eacute;&amp;eacute;, mais nous ne pourrons voir ses questions , car elles ne sont pas affich&amp;eacute;es sur la page. Pour r&amp;eacute;gler cela, on va modifier la vu de &lt;code&gt;show&lt;/code&gt; pour &lt;code&gt;Survey&lt;/code&gt; pour afficher les questions de l&amp;rsquo;enqu&amp;ecirc;te.&lt;/p&gt; 
  &lt;div class="imageWrapper"&gt; 
  &lt;img src="/system/photos/293/original/E196I04.png" width="800" height="320" alt="Les questions ne s&amp;rsquo;affichent pas sur la page enqu&amp;ecirc;te."/&gt; 
  &lt;/div&gt; 
  &lt;pre class="codeFilePath"&gt;/app/views/survey/show.html.erb&lt;/pre&gt; 
  &lt;pre class="ruby"&gt; 
  &amp;lt;% title &amp;quot;Survey&amp;quot; %&amp;gt;

  &amp;lt;p&amp;gt;
    &amp;lt;strong&amp;gt;Name:&amp;lt;/strong&amp;gt;
    &amp;lt;%=h @survey.name %&amp;gt;
  &amp;lt;/p&amp;gt;

  &amp;lt;ol&amp;gt;
    &amp;lt;% for question in @survey.questions %&amp;gt;
    &amp;lt;li&amp;gt;&amp;lt;%= h question.content %&amp;gt;&amp;lt;/li&amp;gt;
    &amp;lt;% end %&amp;gt;
  &amp;lt;/ol&amp;gt;

  &amp;lt;p&amp;gt;
    &amp;lt;%= link_to &amp;quot;Edit&amp;quot;, edit_survey_path(@survey) %&amp;gt; |
    &amp;lt;%= link_to &amp;quot;Destroy&amp;quot;, @survey, :confirm =&amp;gt; &amp;rsquo;Are you sure?&amp;rsquo;, :method =&amp;gt; :delete %&amp;gt; |
    &amp;lt;%= link_to &amp;quot;View All&amp;quot;, surveys_path %&amp;gt;
  &amp;lt;/p&amp;gt;
  &lt;/pre&gt; 
  &lt;p&gt;Lorque nous rechargeons la page de l&amp;rsquo;enqu&amp;ecirc;te, nous allons voir les questions, ce qui prouve bien qu&amp;rsquo;une fois l&amp;rsquo;enqu&amp;ecirc;te enregistr&amp;eacute;e, les questions le sont bien aussi.&lt;/p&gt;
  &lt;div class="imageWrapper"&gt; 
    &lt;img src="/system/photos/294/original/E196I05.png" width="800" height="338" alt="Les questions s&amp;rsquo;affichent maintenant."/&gt; 
  &lt;/div&gt; 

  &lt;p&gt;On peut aussi &amp;eacute;diter une enqu&amp;ecirc;te et si on change n&amp;rsquo;importe quelle question, elles seront toutes mises &amp;agrave; jour lorsque nous allons soumettre le formulaire.&lt;/p&gt; 

  &lt;p&gt;Sur la page ci-dessus, trois questions s&amp;rsquo;affichent, m&amp;ecirc;me si on n&amp;rsquo;a rentr&amp;eacute; des valeurs que pour deux. Ce serait bien mieux si les questions vides pouvaient &amp;ecirc;tre automatiquement retir&amp;eacute;es. La m&amp;eacute;thode &lt;code&gt;accepts_nested_attributes_for&lt;/code&gt; a une option &lt;code&gt;reject_if&lt;/code&gt; que l&amp;rsquo;on va utiliser pour cela. Cette m&amp;eacute;thode accepte un &lt;code&gt;lambda&lt;/code&gt; qui prend un hash d&amp;rsquo;attributs en param&amp;egrave;tre et on va utiliser ce hash to rejeter une question si &lt;code&gt;content&lt;/code&gt; est vide.&lt;/p&gt; 
  &lt;pre class="codeFilePath"&gt;/app/models/survey.rb&lt;/pre&gt; 
  &lt;pre class="ruby"&gt; 
  class Survey &amp;lt; ActiveRecord::Base
    has_many :questions, :dependent =&amp;gt; :destroy
    accepts_nested_attributes_for :questions, :reject_if =&amp;gt; lambda { |a| a[:content].blank? }
  end
  &lt;/pre&gt; 
  &lt;p&gt;Si on cr&amp;eacute;e maintenant une nouvelle enqu&amp;ecirc;te avec seulement deux champs questions remplis, uniquement 2 questions seront cr&amp;eacute;&amp;eacute;es et on ne verra pas de question vide s&amp;rsquo;afficher.&lt;/p&gt; 

  &lt;div class="imageWrapper"&gt; 
    &lt;img src="/system/photos/295/original/E196I06.png" width="800" height="363" alt="Les questions vides ne sont &amp;agrave; pr&amp;eacute;sent plus affich&amp;eacute;es."/&gt; 
  &lt;/div&gt; 
  &lt;p&gt;Comment faire si on veut supprimer des questions existantes lorsqu&amp;rsquo;on est en train de modifier une enqu&amp;ecirc;te? Dans l&amp;rsquo;application finale, on veut utiliser un lien pour supprimer les questions, mais pour l&amp;rsquo;instant nous allons au plus facile et simplement mettre un checkbox. Dans le partial _form, on ajoute un checkbox et un label qui va de pair.&lt;/p&gt; 
  &lt;pre class="codeFilePath"&gt;/app/views/survey/_form.html.erb&lt;/pre&gt; 
  &lt;pre class="ruby"&gt; 
  &amp;lt;% form_for @survey do |f| %&amp;gt;
    &amp;lt;%= f.error_messages %&amp;gt;
    &amp;lt;p&amp;gt;
      &amp;lt;%= f.label :name %&amp;gt;&amp;lt;br /&amp;gt;
      &amp;lt;%= f.text_field :name %&amp;gt;
    &amp;lt;/p&amp;gt;
    &amp;lt;% f.fields_for :questions do |builder| %&amp;gt;
    &amp;lt;p&amp;gt;
      &amp;lt;%= builder.label :content, &amp;quot;Question&amp;quot; %&amp;gt;&amp;lt;br /&amp;gt;
      &amp;lt;%= builder.text_area :content, :rows =&amp;gt; 3 %&amp;gt;
      &amp;lt;%= builder.check_box :_destroy %&amp;gt;
      &amp;lt;%= builder.label :_destroy, &amp;quot;Remove Question&amp;quot; %&amp;gt;
    &amp;lt;/p&amp;gt;
    &amp;lt;% end %&amp;gt;
    &amp;lt;p&amp;gt;&amp;lt;%= f.submit &amp;quot;Submit&amp;quot; %&amp;gt;&amp;lt;/p&amp;gt;
  &amp;lt;% end %&amp;gt;
  &lt;/pre&gt; 
  &lt;p&gt;L&amp;rsquo;astuce ici est dans le nom de l&amp;rsquo;attribut pour la checkbox: &lt;code&gt;_destroy&lt;/code&gt;. Quand il a une valeur de &lt;code&gt;true&lt;/code&gt;, c-a-d quand le checkbox est coch&amp;eacute;, L&amp;rsquo;enregistrement sera supprim&amp;eacute; lorsque le formulaire sera soumis.&lt;/p&gt; 

  &lt;p&gt;Afin que tout ceci fontionne, on doit l&amp;rsquo;activer &amp;agrave; travers &lt;code&gt;accepts_nested_attributes_for&lt;/code&gt; dans le mod&amp;egrave;le &lt;code&gt;Survey&lt;/code&gt; en ajoutant &lt;code&gt;:allow_destroy =&amp;gt; true&lt;/code&gt;.&lt;/p&gt; 
  &lt;pre class="codeFilePath"&gt;/apps/models/survey.rb&lt;/pre&gt; 
  &lt;pre class="ruby"&gt; 
  class Survey &amp;lt; ActiveRecord::Base
    has_many :questions, :dependent =&amp;gt; :destroy
    accepts_nested_attributes_for :questions, :reject_if =&amp;gt; lambda { |a| a[:content].blank? }, :allow_destroy =&amp;gt; true
  end
  &lt;/pre&gt; 
  &lt;p&gt;Lorqu&amp;rsquo;on recharge la page, on a &amp;agrave; pr&amp;eacute;sent un checkbox &amp;ldquo;Remove Question&amp;rdquo; &amp;agrave; c&amp;ocirc;t&amp;eacute; de chaque question.&lt;/p&gt; 

  &lt;div class="imageWrapper"&gt; 
    &lt;img src="/system/photos/296/original/E196I07.png" width="815" height="529" alt="On a maintenant des checkbox pour retirer questions."/&gt; 
  &lt;/div&gt;
  &lt;p&gt;Si on coche le checkbox &amp;ldquo;Remove Question&amp;rdquo; en face d&amp;rsquo;une des questions et que l&amp;rsquo;on soumet le formulaire, cette question sera supprim&amp;eacute;e.&lt;/p&gt; 

  &lt;div class="imageWrapper"&gt; 
    &lt;img src="/system/photos/297/original/E196I08.png" width="800" height="356" alt="La question a &amp;eacute;t&amp;eacute; supprim&amp;eacute;e avec succ&amp;egrave;s."/&gt; 
  &lt;/div&gt; 

  &lt;h3&gt;Ajout de questions&lt;/h3&gt; 
  &lt;p&gt;Les questions sont maintenant d&amp;eacute;finies comme on voulait mais pas les r&amp;eacute;ponses. On commence donc par cr&amp;eacute;er le mod&amp;egrave;le &lt;code&gt;Answer&lt;/code&gt; et son imbrication. Premi&amp;egrave;rement on va g&amp;eacute;n&amp;eacute;rer le mod&amp;egrave;le.&lt;/p&gt; 
  &lt;pre class="terminal"&gt;script/generate model answer question_id:integer content:string&lt;/pre&gt; 
  &lt;p&gt;Ensuite on migre de nouveau la base de donn&amp;eacute;es.&lt;/p&gt; 
  &lt;pre class="terminal"&gt;rake db:migrate&lt;/pre&gt; 
  &lt;p&gt;Puis on cr&amp;eacute;e la relation entre &lt;code&gt;Answer&lt;/code&gt; et &lt;code&gt;Question&lt;/code&gt;. &lt;code&gt;Answer&lt;/code&gt; d&amp;eacute;finit &lt;code&gt;belong_to&lt;/code&gt; &lt;code&gt;Question&lt;/code&gt;.&lt;/p&gt; 
  &lt;pre class="codeFilePath"&gt;/app/models/answer.rb&lt;/pre&gt;
  &lt;pre class="ruby"&gt; 
  class Answer &amp;lt; ActiveRecord::Base
    belongs_to :question
  end
  &lt;/pre&gt; 
  &lt;p&gt;Pour &lt;code&gt;Question&lt;/code&gt; il va falloir utiliser &lt;code&gt;accepts_nested_attributes_for&lt;/code&gt; de la m&amp;ecirc;me fa&amp;ccedil;on que cela avait &amp;eacute;t&amp;eacute; fait pour &lt;code&gt;Survey&lt;/code&gt;.&lt;/p&gt;

  &lt;pre class="codeFilePath"&gt;/app/models/question.rb&lt;/pre&gt;
  &lt;pre class="ruby"&gt;
  class Question &amp;lt; ActiveRecord::Base
    belongs_to :survey
    has_many :answers, :dependent =&amp;gt; :destroy
    accepts_nested_attributes_for :answers, :reject_if =&amp;gt; lambda { |a| a[:content].blank? }, :allow_destroy =&amp;gt; true
  end
  &lt;/pre&gt;

  &lt;p&gt;Dans le formulaire on aura besoin de champs pour les r&amp;eacute;ponses, mais le code du form view va vite devenir fouilli si on lui rajoute un autre mod&amp;egrave;le imbriqu&amp;eacute;. Plus tard, on voudra ajouter des questions sur le formulaire via un lien avec du JavaScript, et pour ces deux raisons, on va placer le code responsable de chaque question dans un partial appel&amp;eacute; &lt;code&gt;question_fields&lt;/code&gt;.&lt;/p&gt; 

  &lt;p&gt;Le form view devrait ressembler &amp;agrave; cela.&lt;/p&gt; 
  &lt;pre class="codeFilePath"&gt;/app/views/surveys/_form.html.erb&lt;/pre&gt; 
  &lt;pre class="ruby"&gt; 
  &amp;lt;% form_for @survey do |f| %&amp;gt;
    &amp;lt;%= f.error_messages %&amp;gt;
    &amp;lt;p&amp;gt;
      &amp;lt;%= f.label :name %&amp;gt;&amp;lt;br /&amp;gt;
      &amp;lt;%= f.text_field :name %&amp;gt;
    &amp;lt;/p&amp;gt;
    &amp;lt;% f.fields_for :questions do |builder| %&amp;gt;
      &amp;lt;%= render &amp;rsquo;question_fields&amp;rsquo;, :f =&amp;gt; builder %&amp;gt;
    &amp;lt;% end %&amp;gt;
    &amp;lt;p&amp;gt;&amp;lt;%= f.submit &amp;quot;Submit&amp;quot; %&amp;gt;&amp;lt;/p&amp;gt;
  &amp;lt;% end %&amp;gt;
  &lt;/pre&gt; 
  &lt;p&gt;Notez qu&amp;rsquo;on lui passe juste le nom du partial en tant que string,  c&amp;rsquo;est un raccourci qui a &amp;eacute;t&amp;eacute; introduit dans Rails 2.3. On lui passe aussi le &lt;code&gt;builder&lt;/code&gt; ayant pour nom &lt;code&gt;f&lt;/code&gt;. Dans le nouveau partial &lt;code&gt;question_fields&lt;/code&gt;  on pourra alors utiliser la variable &lt;code&gt;f&lt;/code&gt; pour le rendu des &amp;eacute;l&amp;eacute;ments du formulaire du mod&amp;egrave;le &lt;code&gt;Question&lt;/code&gt;.&lt;/p&gt; 
  &lt;pre class="codeFilePath"&gt;/app/views/surveys/_question_fields.html.erb&lt;/pre&gt; 
  &lt;pre class="ruby"&gt; 
  &amp;lt;p&amp;gt;
    &amp;lt;%= f.label :content, &amp;quot;Question&amp;quot; %&amp;gt;&amp;lt;br /&amp;gt;
    &amp;lt;%= f.text_area :content, :rows =&amp;gt; 3 %&amp;gt;&amp;lt;br /&amp;gt;
    &amp;lt;%= f.check_box :_destroy %&amp;gt;
    &amp;lt;%= f.label :_destroy, &amp;quot;Remove Question&amp;quot; %&amp;gt;
  &amp;lt;/p&amp;gt;
  &lt;/pre&gt; 
  &lt;p&gt;On peut g&amp;eacute;rer les champs r&amp;eacute;ponses de la m&amp;ecirc;me mani&amp;egrave;re et les mettre dans leur propre partial. Dans le partial &lt;code&gt;_question_fields&lt;/code&gt; on va parcourir toutes les r&amp;eacute;ponses de la question and g&amp;eacute;n&amp;eacute;rer un nouveau partial que l&amp;rsquo;on appellera &lt;code&gt;_answer_fields&lt;/code&gt;.&lt;/p&gt; 
  &lt;pre class="codeFilePath"&gt;/app/views/surveys/_question_fields.html.erb&lt;/pre&gt; 
  &lt;pre class="ruby"&gt; 
  &amp;lt;p&amp;gt;
    &amp;lt;%= f.label :content, &amp;quot;Question&amp;quot; %&amp;gt;&amp;lt;br /&amp;gt;
    &amp;lt;%= f.text_area :content, :rows =&amp;gt; 3 %&amp;gt;&amp;lt;br /&amp;gt;
    &amp;lt;%= f.check_box :_destroy %&amp;gt;
    &amp;lt;%= f.label :_destroy, &amp;quot;Remove Question&amp;quot; %&amp;gt;
  &amp;lt;/p&amp;gt;
  &amp;lt;% f.fields_for :answers do |builder| %&amp;gt;
    &amp;lt;%= render &amp;rsquo;answer_fields&amp;rsquo;, :f =&amp;gt; builder %&amp;gt;
  &amp;lt;% end %&amp;gt;
  &lt;/pre&gt; 
  &lt;p&gt;Dans notre nouveau partial &lt;code&gt;_answer_fields&lt;/code&gt; on va placer le code pour afficher une &lt;code&gt;Answer&lt;/code&gt;.&lt;/p&gt;  
  &lt;pre class="codeFilePath"&gt;/app/views/survey/_answer_fields.html.erb&lt;/pre&gt; 
  &lt;pre class="ruby"&gt; 
  &amp;lt;p&amp;gt;
    &amp;lt;%= f.label :content, &amp;quot;Answer&amp;quot; %&amp;gt;
    &amp;lt;%= f.text_field :content %&amp;gt;
    &amp;lt;%= f.check_box :_destroy %&amp;gt;
    &amp;lt;%= f.label :_destroy, &amp;quot;Remove&amp;quot; %&amp;gt;
  &amp;lt;/p&amp;gt;
  &lt;/pre&gt; 
  &lt;p&gt;Maintenant que l&amp;rsquo;on voit les champs r&amp;eacute;ponses, on va modifier l&amp;rsquo;action &lt;code&gt;new&lt;/code&gt; du &lt;code&gt;SurveyController&lt;/code&gt; afin que les 3 nouvelles questions ainsi cr&amp;eacute;&amp;eacute;es aient chacune 4 r&amp;eacute;ponses.&lt;/p&gt;
  &lt;pre class="codeFilePath"&gt;/app/controllers/survey_controller.rb&lt;/pre&gt;
  &lt;pre class="ruby"&gt;
  def new
    @survey = Survey.new
    3.times do
      question = @survey.questions.build
      4.times { question.answers.build }
    end
  end
  &lt;/pre&gt;

  &lt;p&gt;A pr&amp;eacute;sent, lorsqu&amp;rsquo;on cr&amp;eacute;e une enqu&amp;ecirc;te, on a 3 questions avec chacune 4 r&amp;eacute;ponses.&lt;/p&gt;

  &lt;div class="imageWrapper"&gt;
    &lt;img src="/system/photos/298/original/E196I09.png" width="815" height="509" alt="Les champs r&amp;eacute;ponses s&amp;#x27;affichent dans le formulaire."/&gt;
  &lt;/div&gt;

  &lt;p&gt;Quand on remplit les champs et que l&amp;rsquo;on soumet le formulaire, les r&amp;eacute;ponses ne vont pas s&amp;rsquo;afficher, mais on peut facilement y rem&amp;eacute;dier.  Dans la partie de la vue &lt;code&gt;show&lt;/code&gt; pour une enqu&amp;ecirc;te qui affiche chaque question, on va rajouter un peu de code pour afficher les r&amp;eacute;ponses &amp;agrave; chaque question.&lt;/p&gt;
  &lt;pre class="codeFilePath"&gt;/app/views/survey/show.html.erb&lt;/pre&gt;
  &lt;pre class="ruby"&gt;
  &amp;lt;ol&amp;gt;
    &amp;lt;% for question in @survey.questions %&amp;gt;
    &amp;lt;li&amp;gt;&amp;lt;%= h question.content %&amp;gt;&amp;lt;/li&amp;gt;
    &amp;lt;ul&amp;gt;
      &amp;lt;% for answer in question.answers %&amp;gt;

        &amp;lt;li&amp;gt;&amp;lt;%= h answer.content %&amp;gt;&amp;lt;/li&amp;gt;
      &amp;lt;% end %&amp;gt;
    &amp;lt;/ul&amp;gt;
    &amp;lt;% end %&amp;gt;
  &amp;lt;/ol&amp;gt;
  &lt;/pre&gt;

  &lt;p&gt;Si maintenant on recharge la page de l&amp;rsquo;enqu&amp;ecirc;te, on verra les questions et les r&amp;eacute;ponses.&lt;/p&gt;
  &lt;div class="imageWrapper"&gt;
    &lt;img src="/system/photos/299/original/E196I10.png" width="815" height="509" alt="Les r&amp;eacute;ponses apparaissent en dessous de leurs propres questions."/&gt;
  &lt;/div&gt;

  &lt;p&gt;On n&amp;rsquo;a pas encore termin&amp;eacute;, dans la mesure o&amp;ugrave; on veut &amp;ecirc;tre capable d&amp;rsquo;ajouter ou supprimer des questions ou des r&amp;eacute;ponses dynamiquement sur le formulaire gr&amp;acirc;ce &amp;agrave; des liens. C&amp;rsquo;est ce que nous aborderons dans le prochain &amp;eacute;pisode.&lt;/p&gt;</description>
      <pubDate>Wed, 27 Jan 2010 21:19:36 +0000</pubDate>
      <guid>http://fr.asciicasts.com/episodes/196-Formulaire-avec-modeles-imbriques-1ere-partie</guid>
      <link>http://fr.asciicasts.com/episodes/196-Formulaire-avec-modeles-imbriques-1ere-partie</link>
    </item>
    <item>
      <title>M&#233;thode dynamique find_by</title>
      <description>&lt;p&gt;C&amp;rsquo;est un moyen vraiment utile de faire un &lt;code&gt;Find&lt;/code&gt; dans Rails. Ci-dessous, vous avez un mod&amp;egrave;le &lt;code&gt;Task&lt;/code&gt; qui recherche les t&amp;acirc;ches qui ne sont pas accomplies (C&amp;rsquo;est &amp;agrave; dire : la colonne &lt;code&gt;complete&lt;/code&gt; est &amp;agrave; &lt;code&gt;false&lt;/code&gt;).&lt;/p&gt;
&lt;pre class="ruby"&gt;
class TaskController &amp;lt; ApplicationController
    def incomplete
        @tasks = Task.find(:all, :conditions =&amp;gt; [&amp;#x27;complete = ?&amp;#x27;, false])
    end

    def last_incomplete
        @task = Task.find(:first, :conditions =&amp;gt; [&amp;#x27;complete =?&amp;#x27;, false], :order =&amp;gt; &amp;#x27;created_at DESC&amp;#x27;)
    end
end
&lt;/pre&gt;
&lt;p&gt;Ceci est une meilleure fa&amp;ccedil;on de faire avec &lt;code&gt;find_by_all&lt;/code&gt;. Remplacez :&lt;/p&gt;
&lt;pre class="ruby"&gt;
@tasks = Task.find(:all, :conditions =&amp;gt; [&amp;#x27;complete = ?&amp;#x27;, false])
&lt;/pre&gt;
&lt;p&gt;par&lt;/p&gt;
&lt;pre class="ruby"&gt;
@tasks = Task.find_all_by_complete(false)
&lt;/pre&gt;
&lt;p&gt;Si vous souhaitez trouver une t&amp;acirc;che en utilisant &lt;code&gt;find_by&lt;/code&gt;,  pour trouver la derni&amp;egrave;re t&amp;acirc;che incompl&amp;egrave;te. La ligne :&lt;/p&gt;
&lt;pre class="ruby"&gt;
@task = Task.find(:first, :conditions =&amp;gt; [&amp;#x27;complete =?&amp;#x27;, false], :order =&amp;gt; &amp;#x27;created_at DESC&amp;#x27;)
&lt;/pre&gt;
&lt;p&gt;devient&lt;/p&gt;
&lt;pre class="ruby"&gt;
@task = Task.find_by_complete(false, :order =&amp;gt; &amp;#x27;created_at DESC&amp;#x27;)
&lt;/pre&gt;
&lt;p&gt;La m&amp;eacute;thode &lt;code&gt;find_by&lt;/code&gt; prend le param&amp;egrave;tre &lt;code&gt;order&lt;/code&gt; comme la m&amp;eacute;thode &lt;code&gt;find&lt;/code&gt;.&lt;/p&gt;</description>
      <pubDate>Thu, 13 May 2010 22:46:24 +0000</pubDate>
      <guid>http://fr.asciicasts.com/episodes/2-methode-dynamique-find-by</guid>
      <link>http://fr.asciicasts.com/episodes/2-methode-dynamique-find-by</link>
    </item>
    <item>
      <title>Mise en cache des variables d&amp;apos;instance</title>
      <description>&lt;pre class="ruby"&gt;
	class ApplicationController &amp;lt; ActionController::Base
		def current_user
			User.find(session[:user_id])
		end
	end
&lt;/pre&gt;
&lt;p&gt;La m&amp;eacute;thode ci-dessus r&amp;eacute;cup&amp;egrave;re l&amp;#x27;utilisateur actuellement connect&amp;eacute;. Elle ex&amp;eacute;cute find du mod&amp;egrave;le User pour le user_id de la session. la m&amp;eacute;thode est appel&amp;eacute;e plusieurs fois par requ&amp;ecirc;te, ce qui signifie que la base de donn&amp;eacute;es est &amp;eacute;galement interrog&amp;eacute;e plusieurs fois par requ&amp;ecirc;te. Ce probl&amp;egrave;me peut &amp;ecirc;tre r&amp;eacute;solu en mettant en cache le r&amp;eacute;sultat de la base de donn&amp;eacute;es dans une variable d&amp;#x27;instance.&lt;/p&gt;
  &lt;pre class="ruby"&gt;@current_user ||= User.find(session[:user_id])&lt;/pre&gt;
  &lt;p&gt;La chose importante &amp;agrave; retenir est le symbole OR. La premi&amp;egrave;re fois que la ligne ci-dessus est ex&amp;eacute;cut&amp;eacute;e, la variable &lt;code&gt;@current_user&lt;/code&gt; vaut &lt;code&gt;nil&lt;/code&gt; and par cons&amp;eacute;quent on interrogera la base de donn&amp;eacute;es. Pour tous les appels suivants de cette m&amp;ecirc;me m&amp;eacute;thode, &lt;code&gt;@current_user&lt;/code&gt; vaudra l&amp;#x27;utilisateur actuel et la base de donn&amp;eacute;es ne sera pas sollicit&amp;eacute;e. Cette technique am&amp;eacute;liore les performances.&lt;/p&gt;
&lt;pre class="ruby"&gt;
	class ApplicationController &amp;lt; ActionController::Base
		def current_user
			@current_user ||= User.find(session[:user_id])
		end
	end
&lt;/pre&gt;
&lt;p class="title"&gt;L&amp;#x27;action mise &amp;agrave; jour avec l&amp;#x27;utilisation de la variable d&amp;#x27;instance.&lt;/p&gt;</description>
      <pubDate>Thu, 13 May 2010 22:17:23 +0000</pubDate>
      <guid>http://fr.asciicasts.com/episodes/1-mise-en-cache-des-variables-dinstance</guid>
      <link>http://fr.asciicasts.com/episodes/1-mise-en-cache-des-variables-dinstance</link>
    </item>
  </channel>
</rss>
