<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet href="http://feeds.feedburner.com/~d/styles/rss2full.xsl" type="text/xsl" media="screen"?><?xml-stylesheet href="http://feeds.feedburner.com/~d/styles/itemcontent.css" type="text/css" media="screen"?><rss version="2.0">
  <channel>
    <title>Frailers.net: Articles</title>
    <link>http://www.frailers.net/articles.rss</link>
    <description>Ressources Ruby on Rails en Français</description>
    <pubDate>Thu, 27 Mar 2008 00:00:00 +0100</pubDate>
    <lastBuildDate>Thu, 27 Mar 2008 00:00:00 +0100</lastBuildDate>
    <language>fr</language>
    <atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" href="http://feeds.feedburner.com/FrailersArticles" type="application/rss+xml" /><item>
      <title>Utiliser attachment_fu avec la sauvegarde en DB</title>
      <description>&lt;h2&gt;Introduction&lt;/h2&gt;


	&lt;p&gt;&lt;a href="http://svn.techno-weenie.net/projects/plugins/attachment_fu/"&gt;attachment_fu&lt;/a&gt;, développé par le célèbre Rick Olson (&lt;a href="http://techno-weenie.net/"&gt;techno weenie&lt;/a&gt;) est un plugin qui vous permet de faciliter la gestion des fichiers téléchargés vers votre application via les formulaires. Il permet ainsi à chaque utilisateur, par exemple, de rajouter sa photo ou son logo sur sa page profil.&lt;/p&gt;


	&lt;p&gt;Pour ce faire, attachment_fu propose 3 méthodes de stockage:&lt;/p&gt;


	&lt;ul&gt;
	&lt;li&gt;&lt;strong&gt;le système de fichiers&lt;/strong&gt;: les fichiers sont simplement déposés dans un dossier de votre serveur, idéalement public afin qu&amp;#8217;ils puissent ensuite être affichés sur votre site;&lt;/li&gt;
		&lt;li&gt;&lt;strong&gt;Amazon S3&lt;/strong&gt;: la plateforme de stockage distribuée (et payante) proposée par Amazon;&lt;/li&gt;
		&lt;li&gt;&lt;strong&gt;la base de données&lt;/strong&gt;: déjà utilisée pour vos autres données.&lt;/li&gt;
	&lt;/ul&gt;


	&lt;p&gt;Le fichier &lt;span class="caps"&gt;README&lt;/span&gt; du plugin documente (relativement) bien les 2 premières solutions, mais ne donne pas beaucoup d&amp;#8217;indications sur la dernière. Les avantages proposés par cette solution sont pourtant évidents:&lt;/p&gt;


	&lt;ul&gt;
	&lt;li&gt;elle permet la centralisation de toutes vos données au même endroit ce qui est bien pratique pour la stratégie de backup;&lt;/li&gt;
		&lt;li&gt;par rapport à la solution &amp;#8220;système de fichiers&amp;#8221;, elle évite d&amp;#8217;avoir à faire des manipulations supplémentaires si vous déployez avec capistrano (vu que votre dossier d&amp;#8217;application rails change à chaque mise à jour);&lt;/li&gt;
		&lt;li&gt;elle est évidemment gratuite, contrairement à Amazon S3.&lt;/li&gt;
	&lt;/ul&gt;


	&lt;p&gt;L&amp;#8217;inconvénient majeur de la solution, à savoir sa lenteur, peut être circonvenu en utilisant un système de caching des fichiers (mais cela sort du cadre de cet article).&lt;/p&gt;


	&lt;h2&gt;Installation du plugin et configuration&lt;/h2&gt;


	&lt;p&gt;Vous aurez tout d&amp;#8217;abord besoin de l&amp;#8217;une des 3 librairies graphiques suivantes, au choix: &lt;a href="http://rmagick.rubyforge.org/"&gt;RMagick&lt;/a&gt;, &lt;a href="http://seattlerb.rubyforge.org/ImageScience.html"&gt;ImageScience&lt;/a&gt; ou &lt;a href="http://rubyforge.org/projects/mini-magick/"&gt;minimagick&lt;/a&gt;. Ensuite, vous pouvez installer le plugin proprement dit, à partir de la racine de votre application:&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;
script/plugin install http://svn.techno-weenie.net/projects/plugins/attachment_fu/
&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Nous choisissons de nommer &amp;#8220;Avatar&amp;#8221; le modèle qui stockera les fichiers téléchargés. Nous créons donc la migration suivante:&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;
class CreateAvatars &amp;lt; ActiveRecord::Migration
  def self.up
    create_table :avatars do |t|
      t.column :filename, :string
      t.column :type, :string
      t.column :content_type, :string
      t.column :size, :integer
      t.column :width, :integer
      t.column :height, :integer
      t.column :parent_id, :integer
      t.column :thumbnail, :string
      t.column :created_at, :datetime
      t.column :db_file_id, :integer
    end
    create_table :db_files do |t|
    end
    execute 'ALTER TABLE db_files ADD COLUMN data LONGBLOB'
  end
  def self.down
    drop_table :avatars
    drop_table :db_files
  end
end
&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Vous pouvez constater la présence dans la migration d&amp;#8217;une table additionnelle nommée &amp;#8220;db_files&amp;#8221;; elle est imposée par attachment_fu si l&amp;#8217;on désire un stockage via base de données. A noter que nous y utilisons un champ de type &lt;a href="http://dev.mysql.com/doc/refman/5.0/en/blob.html"&gt;blob&lt;/a&gt; et non &lt;a href="http://dev.mysql.com/doc/refman/5.0/en/binary-varbinary.html"&gt;binary&lt;/a&gt; pour éviter la limite des 65536 caractères imposée par MySQL, ce qui nécessite malheureusement d&amp;#8217;effectuer l&amp;#8217;ajout de la colonne manuellement en &lt;span class="caps"&gt;SQL&lt;/span&gt;.&lt;/p&gt;


	&lt;p&gt;Le modèle proprement dit est comme suit:&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;
class Avatar &amp;lt; ActiveRecord::Base
  has_attachment  :storage =&amp;gt; :db_file,
                  :content_type =&amp;gt; :image,
                  :max_size =&amp;gt; 1.megabytes,
                  :thumbnails =&amp;gt; { :thumb =&amp;gt; "100×100&amp;gt;" }
  validates_as_attachment
end
&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Enfin, pour afficher nos avatars dans l&amp;#8217;application, nous utilisons la méthode show du contrôleur AvatarsController:&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;
class AvatarsController &amp;lt; ApplicationController
  def show
    @avatar = Avatar.find(params[:id])
    send_data(@avatar.current_data,
              :type  =&amp;gt; @avatar.content_type,
              :filename =&amp;gt; @avatar.filename,
              :disposition =&amp;gt; 'inline')
  end
end
&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Pour afficher un avatar dans vos vues, rien de plus simple:&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;
&amp;lt;%= image_tag avatar_path(@avatar) %&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Bien entendu, il faudrait sans doute également ajouter les méthode create, destroy et compagnie à ce contrôleur ainsi qu&amp;#8217;un formulaire d&amp;#8217;upload pour que les utilisateurs puissent ajouter/supprimer leurs avatars, mais le fonctionnement n&amp;#8217;est pas différent pour le stockage en DB par rapport aux autres techniques, et cela sort donc du cadre de cet article; reportez-vous par example à &lt;a href="http://clarkware.com/cgi/blosxom/2007/02/24"&gt;l&amp;#8217;article de Mike Clark&lt;/a&gt; pour plus d&amp;#8217;info à ce sujet.&lt;/p&gt;


	&lt;h2&gt;Références&lt;/h2&gt;


	&lt;ul&gt;
	&lt;li&gt;&lt;a href="http://svn.techno-weenie.net/projects/plugins/attachment_fu/"&gt;attachment_fu&lt;/a&gt;&lt;/li&gt;
		&lt;li&gt;&lt;a href="http://clarkware.com/cgi/blosxom/2007/02/24"&gt;File Upload Fu&lt;/a&gt;&lt;/li&gt;
		&lt;li&gt;&lt;a href="http://deadprogrammersociety.blogspot.com/2007/04/getting-your-attachmentfu-back-out-of.html"&gt;Getting Your attachment_fu Back Out Of The Database&lt;/a&gt;&lt;/li&gt;
		&lt;li&gt;&lt;a href="http://jeremyweiland.com/2008/03/23/using-attachment_fu-with-storage-db_file/"&gt;http://jeremyweiland.com/2008/03/23/using-attachment_fu-with-storage-db_file/&lt;/a&gt;&lt;/li&gt;
	&lt;/ul&gt;</description>
      <pubDate>Thu, 27 Mar 2008 00:00:00 +0100</pubDate>
      <link>http://www.frailers.net/articles/14-utiliser-attachment-fu-avec-la-sauvegarde-en-db</link>
      <guid>http://www.frailers.net/articles/14-utiliser-attachment-fu-avec-la-sauvegarde-en-db</guid>
    </item>
    <item>
      <title>Recherche sur un laps de temps avec ActiveRecord</title>
      <description>&lt;p&gt;Comme vous le savez, il est possible de définir des conditions sur une recherche ActiveRecord en Ruby au lieu d&amp;#8217;une chaîne de caractères. Par exemple, on peut remplacer:&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;
Article.find :all, :conditions =&amp;gt; ["published = 1"]
&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;par&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;
Article.find :all, :conditions =&amp;gt; {:published =&amp;gt; true}
&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Cela ne marche cependant pour l&amp;#8217;instant qu&amp;#8217;avec l&amp;#8217;égalité (comme l&amp;#8217;exemple ci-dessus), les ranges (par exemple &lt;code&gt;{:score =&amp;gt; 8..10}&lt;/code&gt;, qui génère automatiquement un &lt;span class="caps"&gt;BETWEEN&lt;/span&gt; en &lt;span class="caps"&gt;SQL&lt;/span&gt;) et les tableaux (par exemple &lt;code&gt;{:user_id =&amp;gt; [1,4,8]}&lt;/code&gt;, qui génère un IN).&lt;/p&gt;


	&lt;p&gt;Cela marche même avec les ranges d&amp;#8217;objets plus compliqués telles que Date ou Time, ce qui simplifie pas mal les recherches sur ce type de champ. Par exemple, pour extraire les articles parus entre il y a un mois et aujourd&amp;#8217;hui:&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;
@articles_du_dernier_mois = Article.find(:all,
                            :conditions =&amp;gt; {:published_at =&amp;gt; 1.month.ago..Time.now})
&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Nous utilisons ce type de recherche sur Frailers pour extraire les articles parus un mois spécifique donné.&lt;/p&gt;</description>
      <pubDate>Tue, 25 Mar 2008 00:00:00 +0100</pubDate>
      <link>http://www.frailers.net/articles/13-recherche-sur-un-laps-de-temps-avec-activerecord</link>
      <guid>http://www.frailers.net/articles/13-recherche-sur-un-laps-de-temps-avec-activerecord</guid>
    </item>
    <item>
      <title>Attachment_fu en batch avec rubyzip</title>
      <description>&lt;p&gt;Premièrement, il faut installer &lt;code&gt;rubyzip&lt;/code&gt; :&lt;/p&gt;


	&lt;p&gt;&lt;code&gt;gem install rubyzip&lt;/code&gt;&lt;/p&gt;


	&lt;p&gt;Pas trop difficile jusque là. Vous aurez évidemment besoin de attachment_fu.&lt;/p&gt;


	&lt;p&gt;&lt;code&gt;script/plugin install http://svn.techno-weenie.net/projects/plugins/attachment_fu/&lt;/code&gt;&lt;/p&gt;


	&lt;p&gt;ou&lt;/p&gt;


	&lt;p&gt;&lt;code&gt;piston import install http://svn.techno-weenie.net/projects/plugins/attachment_fu/ vendor/&lt;/code&gt;&lt;/p&gt;


	&lt;p&gt;Il ne vous reste plus qu&amp;#8217;à ajouter un petit bout de code dans votre contrôlleur:&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;
class AssetsController &amp;lt; ApplicationController
  def create

    Zip::ZipFile.foreach(params[:asset][:uploaded_data].path) do |zip_entry|
      if zip_entry.file?
        ActionController::UploadedTempfile.open(zip_entry.to_s) do |temp|
          zip_entry.extract(temp.path){true}
          temp.original_path = zip_entry.to_s
          temp.content_type = 'image/jpeg' # Juste pour que ça passe dans 
                                           # attachment_fu
          @training_slot.assets.create!(:uploaded_data=&amp;gt;temp)
        end
      end
    end

    flash[:notice] = 'Les images ont été ajoutées correctement.'
    redirect_to ...

  rescue ActiveRecord::ActiveRecordError =&amp;gt; e
    flash[:notice] = 'Une erreur s\'est produite : ' + e
    redirect_to ...
  end
&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Et n&amp;#8217;oublliez pas d&amp;#8217;importer la librairie dans environnement.rb&lt;/p&gt;


	&lt;p&gt;&lt;code&gt;require 'zip/zip'&lt;/code&gt;&lt;/p&gt;


	&lt;p&gt;Voilà, c&amp;#8217;est tout. En espérant que ça puisse vous éviter le pénible remplissage de galleries. :)&lt;/p&gt;</description>
      <pubDate>Sun, 09 Mar 2008 00:00:00 +0100</pubDate>
      <link>http://www.frailers.net/articles/12-attachment-fu-en-batch-avec-rubyzip</link>
      <guid>http://www.frailers.net/articles/12-attachment-fu-en-batch-avec-rubyzip</guid>
    </item>
    <item>
      <title>Gestion aisée des plugins avec Piston</title>
      <description>&lt;h2&gt;Le dossier &lt;code&gt;vendor&lt;/code&gt;&lt;/h2&gt;


	&lt;p&gt;Le dossier &lt;code&gt;vendor&lt;/code&gt; d&amp;#8217;une application Rails est destiné à contenir tout ce qui n&amp;#8217;est pas développé par vous-même dans le cadre de votre application, à savoir principalement:&lt;/p&gt;


	&lt;ul&gt;
	&lt;li&gt;les &lt;strong&gt;plug-ins&lt;/strong&gt;, réalisés par la communauté Rails, et placés dans &lt;code&gt;vendor/plugins&lt;/code&gt;&lt;/li&gt;
		&lt;li&gt;une copie du code source de &lt;strong&gt;Rails&lt;/strong&gt; lui-même, placée dans &lt;code&gt;vendor/rails&lt;/code&gt;, si vous souhaitez que votre application utilise une version spécifique du framework différente des gemmes présentes dans le système.&lt;/li&gt;
	&lt;/ul&gt;


	&lt;h2&gt;Le problème&lt;/h2&gt;


	&lt;p&gt;Le problème survient lorsque vous commencez à utiliser Subversion pour gérer le code source de votre application (c&amp;#8217;est votre cas, n&amp;#8217;est-ce-pas ?). En cas de mise à jour d&amp;#8217;un plugin ou de Rails, vous souhaitez permettre à votre application de se synchroniser à la nouvelle version, mais cela implique de d&amp;#8217;abord supprimer le dossier correspondant de votre repository &lt;span class="caps"&gt;SVN&lt;/span&gt; (&lt;code&gt;svn remove&lt;/code&gt;), puis installer la nouvelle version dans votre copie locale, et enfin rajouter le nouveau dossier dans le repository (avec &lt;code&gt;svn add&lt;/code&gt;). De plus, il n&amp;#8217;y a pas de moyen aisé pour s&amp;#8217;informer de l&amp;#8217;apparition d&amp;#8217;une nouvelle mise à jour.&lt;/p&gt;


	&lt;p&gt;Il y a ceci dit une alternative, fournie par &lt;span class="caps"&gt;SVN&lt;/span&gt;: utiliser la propriété &lt;code&gt;svn:externals&lt;/code&gt; pour chaque dossier relatif à un plugin ou à Rails. Cette propriété indique à Subversion que le contenu dudit dossier n&amp;#8217;est pas disponible dans le repository mais qu&amp;#8217;il doit être téléchargé ailleurs (en l&amp;#8217;occurence, dans les différents repositories correspondant aux divers plugins et à Rails).&lt;/p&gt;


	&lt;p&gt;Le problème avec cette alternative est multiple:&lt;/p&gt;


	&lt;ul&gt;
	&lt;li&gt;elle consomme un temps bête, puisque la synchronisation avec les repositories extérieure se fait à chaque &lt;code&gt;svn update&lt;/code&gt; (pour chaque développeur!);&lt;/li&gt;
		&lt;li&gt;elle n&amp;#8217;est pas facultative: il est donc impossible de signaler que l&amp;#8217;on veut ignorer une mise à jour particulière, par exemple en cas d&amp;#8217;imcompatibilité de l&amp;#8217;application avec la nouvelle version.&lt;/li&gt;
		&lt;li&gt;si un des repositories externes est très lent, ou tombe en panne, vous perdez du temps ou rendez carrément votre application inutilisable.&lt;/li&gt;
	&lt;/ul&gt;


	&lt;h2&gt;La solution: Piston&lt;/h2&gt;


	&lt;p&gt;Piston est une gemme qui se greffe sur les fonctionnalités de &lt;span class="caps"&gt;SVN&lt;/span&gt; pour combiner les avantages des deux systèmes: il vous permet de conserver en local une copie de chaque dépendance externe (plugin, Rails, ou autre), tout en rendant possible les mises à jour, uniquement si et quand vous le désirez.&lt;/p&gt;


	&lt;p&gt;Commençons par installer Piston:&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;
$ sudo gem install piston
&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Il est dès lors possible, à partir de la racine de votre application, d&amp;#8217;importer un plugin:&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;
$ piston import http://svn.techno-weenie.net/projects/plugins/restful_authentication/ vendor/plugins/restful_authentication
Exported r3119 from 'http://svn.techno-weenie.net/projects/plugins/restful_authentication/' to 'vendor/plugins/restful_authentication'
&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Piston télécharge le dossier et le marque pour ajout dans le repository (&lt;code&gt;svn add&lt;/code&gt;); il sera rajouté dans votre repository lors du prochain commit (&lt;code&gt;svn commit&lt;/code&gt;). Vous êtes alors dans la situation d&amp;#8217;une copie purement locale à votre repository (aucune dépendance à un repository externe), à ceci près qu&amp;#8217;il est possible de vérifier si une mise à jour d&amp;#8217;un dossier est disponible, au moyen de la commande &lt;code&gt;piston status&lt;/code&gt;. Prenons par exemple le cas d&amp;#8217;une application où l&amp;#8217;on aurait rajouté Rails 2.0.2 et restful_authentication, ce dernier ayant une mise à jour:&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;
$ piston status
     vendor/rails (http://svn.rubyonrails.org/rails/tags/rel_2-0-2/)
M    vendor/plugins/restful_authentication (http://svn.techno-weenie.net/projects/plugins/restful_authentication/)
&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Dans notre exemple, la lettre &amp;#8220;M&amp;#8221; placée devant le plugin restful_authentication nous indique qu&amp;#8217;il a été mis à jour. Il est alors simple d&amp;#8217;installer cette mise à jour:&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;
$ piston update vendor/plugins/restful_authentication
&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Pour mettre à jour l&amp;#8217;entièreté du dossier &lt;code&gt;vendor&lt;/code&gt;, il suffit de lancer la commande &lt;code&gt;piston update&lt;/code&gt;.&lt;/p&gt;


	&lt;h2&gt;Resources&lt;/h2&gt;


	&lt;ul&gt;
	&lt;li&gt;&lt;a href="http://piston.rubyforge.org/usage.html"&gt;http://piston.rubyforge.org/usage.html&lt;/a&gt;&lt;/li&gt;
		&lt;li&gt;&lt;a href="http://www.robbyonrails.com/articles/2007/01/16/every-second-counts-with-a-piston-in-your-trunk"&gt;Every Second Counts with a Piston in your Trunk&lt;/a&gt;&lt;/li&gt;
		&lt;li&gt;&lt;a href="http://www.rubyinside.com/advent2006/12-piston.html"&gt;Managing Rails Plugins with Piston&lt;/a&gt;&lt;/li&gt;
	&lt;/ul&gt;</description>
      <pubDate>Fri, 01 Feb 2008 00:00:00 +0100</pubDate>
      <link>http://www.frailers.net/articles/10-gestion-aisee-des-plugins-avec-piston</link>
      <guid>http://www.frailers.net/articles/10-gestion-aisee-des-plugins-avec-piston</guid>
    </item>
    <item>
      <title>Editer plusieurs modèles avec fields_for</title>
      <description>&lt;h2&gt;Le problème&lt;/h2&gt;


	&lt;p&gt;Prenons l&amp;#8217;exemple habituel du blog.&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;
class Post &amp;lt; ActiveRecord::Base
  belongs_to :author
end

class Author &amp;lt; ActiveRecord::Base
  has_many :posts
end
&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Chaque &lt;code&gt;Post&lt;/code&gt; est écrit par un &lt;code&gt;Author&lt;/code&gt;. Dans le formulaire de création de &lt;code&gt;Post&lt;/code&gt;, les champs &lt;code&gt;name&lt;/code&gt; et &lt;code&gt;email&lt;/code&gt; de l&amp;#8217;auteur sont inclus.
Nous voudrions créer à la volée un enregistrement &lt;code&gt;Author&lt;/code&gt; dans la base de données au moment de la création de &lt;code&gt;Post&lt;/code&gt;.
Pour le moment, notre application ressemble à ceci.&lt;/p&gt;


	&lt;h3&gt;Vue du formulaire &lt;code&gt;(app/view/posts/_form.html.erb)&lt;/code&gt; :&lt;/h3&gt;


&lt;pre&gt;&lt;code&gt;
&amp;lt;p&amp;gt; &amp;lt;b&amp;gt;Title&amp;lt;/b&amp;gt;&amp;lt;br /&amp;gt; &amp;lt;%= f.text_field :title %&amp;gt; &amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt; &amp;lt;b&amp;gt;Content&amp;lt;/b&amp;gt;&amp;lt;br /&amp;gt; &amp;lt;%= f.text_area :content %&amp;gt; &amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt; &amp;lt;b&amp;gt;Name&amp;lt;/b&amp;gt;&amp;lt;br /&amp;gt; &amp;lt;%= text_field_tag :name, @post.author.name %&amp;gt; &amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt; &amp;lt;b&amp;gt;Email&amp;lt;/b&amp;gt;&amp;lt;br /&amp;gt; &amp;lt;%= text_field_tag :email, @post.author.email %&amp;gt; &amp;lt;/p&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

	&lt;h3&gt;Action &lt;code&gt;create&lt;/code&gt; dans &lt;code&gt;PostsController&lt;/code&gt; &lt;code&gt;(app/controllers/posts_controller.rb)&lt;/code&gt; :&lt;/h3&gt;


&lt;pre&gt;&lt;code&gt;
def create
  @post = Post.new(params[:post])
  @post.author = Author.new(:name =&amp;gt; params[:name], :email =&amp;gt; params[:email])

  respond_to do |format|
    if @post.save
      # response code
    end
  end
end
&lt;/code&gt;&lt;/pre&gt;

	&lt;h2&gt;La solution&lt;/h2&gt;


	&lt;p&gt;Nous désirons simplifier la vue et le contrôleur. La principale cause de désagrément est l&amp;#8217;organisation des attributs envoyés par le formulaire :&lt;/p&gt;


&lt;pre&gt;
  { "name"=&amp;gt;"Jean-Baptiste Escoyez",
    "email"=&amp;gt;"jbe at belighted point com",
    "post"=&amp;gt;{
      "title"=&amp;gt;"Editer plusieurs modèles avec fields_for", 
      "content"=&amp;gt;"Contenu..."}}
&lt;/pre&gt;

	&lt;p&gt;Nous voyons que &lt;code&gt;name&lt;/code&gt; et &lt;code&gt;email&lt;/code&gt; ne sont pas associés à &lt;code&gt;post&lt;/code&gt;. De ce fait, nous sommes obligés de créer un &lt;code&gt;Author&lt;/code&gt; dans le contrôleur.&lt;/p&gt;


	&lt;p&gt;Nous utilisons &lt;code&gt;fields_for&lt;/code&gt; pour nous aider à organiser les arguments.&lt;/p&gt;


	&lt;h3&gt;Vue du formulaire &lt;code&gt;(app/view/posts/_form.html.erb)&lt;/code&gt;:&lt;/h3&gt;


&lt;pre&gt;&lt;code&gt;
&amp;lt;p&amp;gt; &amp;lt;b&amp;gt;Title&amp;lt;/b&amp;gt;&amp;lt;br /&amp;gt; &amp;lt;%= f.text_field :title %&amp;gt; &amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt; &amp;lt;b&amp;gt;Content&amp;lt;/b&amp;gt;&amp;lt;br /&amp;gt; &amp;lt;%= f.text_area :content %&amp;gt; &amp;lt;/p&amp;gt;

&amp;lt;% fields_for :author, @post.author do |af| %&amp;gt;
  &amp;lt;p&amp;gt; &amp;lt;b&amp;gt;Name&amp;lt;/b&amp;gt;&amp;lt;br /&amp;gt; &amp;lt;%= af.text_field :name %&amp;gt; &amp;lt;/p&amp;gt;

  &amp;lt;p&amp;gt; &amp;lt;b&amp;gt;Email&amp;lt;/b&amp;gt;&amp;lt;br /&amp;gt; &amp;lt;%= af.text_field :email %&amp;gt; &amp;lt;/p&amp;gt;
&amp;lt;% end %&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

	&lt;h3&gt;Action &lt;code&gt;create&lt;/code&gt; dans &lt;code&gt;PostsController&lt;/code&gt; &lt;code&gt;(app/controllers/posts_controller.rb)&lt;/code&gt;:&lt;/h3&gt;


&lt;pre&gt;&lt;code&gt;
def create
  @post = Post.new(params[:post])
  @post.author = Author.new(params[:author])

  respond_to do |format|
    if @post.save
      # response code
    end
  end
end
&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Remarquez le second argument de &lt;code&gt;fields_for&lt;/code&gt;. Il s&amp;#8217;agit de l&amp;#8217;objet qui donnera les valeurs aux champs &lt;code&gt;name&lt;/code&gt; et &lt;code&gt;email&lt;/code&gt; au moment de l&amp;#8217;édition du &lt;code&gt;post&lt;/code&gt;. Le contrôleur a également changé car les arguments envoyés par le formulaire sont maintenant organisés différemment.&lt;/p&gt;


&lt;pre&gt;
  { "author"=&amp;gt;{
      "name"=&amp;gt;"Jean-Baptiste Escoyez",
      "email"=&amp;gt;"jbe at belighted point com"},
    "post"=&amp;gt;{
      "title"=&amp;gt;"Editer plusieurs modèles avec fields_for", 
      "content"=&amp;gt;"Contenu..."} }
&lt;/pre&gt;

	&lt;h2&gt;Encore mieux !&lt;/h2&gt;


	&lt;p&gt;Nous pouvons aller encore plus loin dans notre refactorisation. En changeant &lt;code&gt;fields_for&lt;/code&gt; par &lt;code&gt;f.fields_for&lt;/code&gt;, vous allez imbriquer les attributs des deux objets.&lt;/p&gt;


&lt;pre&gt;
  { "post"=&amp;gt;{
      "name"=&amp;gt;"Jean-Baptiste Escoyez",
      "email"=&amp;gt;"jbe at belighted point com",
      "author"=&amp;gt;{
        "title"=&amp;gt;"Editer plusieurs modèles avec fields_for", 
        "content"=&amp;gt;"Contenu..."} } }
&lt;/pre&gt;

	&lt;p&gt;Comme une des clefs du hash est &lt;code&gt;author&lt;/code&gt;, la méthode &lt;code&gt;author=&lt;/code&gt; de &lt;code&gt;post&lt;/code&gt; sera appelée lorsque vous appellerez &lt;code&gt;Post.new(params[:post])&lt;/code&gt;. Malheureusement, la méthode &lt;code&gt;author&lt;/code&gt; n&amp;#8217;est pas prévue pour prendre un hash en paramètre mais un objet &lt;code&gt;Author&lt;/code&gt;. Il faut donc remplacer &lt;code&gt;f.fields_for :author&lt;/code&gt; par &lt;code&gt;f.fields_for :author_attributes&lt;/code&gt; et créer une méthode &lt;code&gt;author_attributes=&lt;/code&gt; dans le modèle &lt;code&gt;Post&lt;/code&gt; ; comme la méthode &lt;code&gt;author_attributes=&lt;/code&gt; est semblable à build_author, un alias de méthode suffit:&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;
class Post &amp;lt; ActiveRecord::Base
  belongs_to :author
  alias author_attributes=  build_author
end
&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Vous pouvez dès lors supprimer la ligne &lt;code&gt;post.author = Author.new(params[:author])&lt;/code&gt; dans votre contrôleur.&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;
def create
  @post = Post.new(params[:post])
  @post.author = Author.new(params[:author])

  respond_to do |format|
    if @post.save
      # response code
    end
  end
end
&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;&lt;code&gt;fields_for&lt;/code&gt; peut être utilisé de manière imbriquée si vous avez plusieurs modèles à créer/éditer. N&amp;#8217;oubliez pas le &lt;code&gt;f.&lt;/code&gt; avant &lt;code&gt;fields_for&lt;/code&gt; si vous voulez imbriquer les attributs.&lt;/p&gt;


	&lt;p&gt;&lt;code&gt;fields_for&lt;/code&gt; peut également être utilisé sans modèle correspondant, juste pour structurer l&amp;#8217;information envoyée par un formulaire. Depuis que j&amp;#8217;utilise &lt;code&gt;fields_for&lt;/code&gt;, j&amp;#8217;ai complètement laissé tomber les &lt;a href="http://api.rubyonrails.com/classes/ActionView/Helpers/FormTagHelper.html"&gt;&lt;code&gt;FormTagHelper&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;</description>
      <pubDate>Wed, 23 Jan 2008 00:00:00 +0100</pubDate>
      <link>http://www.frailers.net/articles/11-editer-plusieurs-modeles-avec-fields-for</link>
      <guid>http://www.frailers.net/articles/11-editer-plusieurs-modeles-avec-fields-for</guid>
    </item>
    <item>
      <title>Rails et l'iPhone</title>
      <description>&lt;p&gt;Il y a quelques temps, j&amp;#8217;ai eu la chance de mettre la main sur un iPhone et je suis très vite tombé amoureux de l&amp;#8217;engin: malgré l&amp;#8217;écran de (relativement) petite taille par rapport à celui d&amp;#8217;un ordinateur classique, le browser Safari est particulièrement fabuleux et ouvre de nouvelles perspectives au surf mobile. C&amp;#8217;était donc pour moi un devoir d&amp;#8217;essayer de faire tourner une application Rails dessus; voici donc quelques conseils pour ce faire.&lt;/p&gt;


	&lt;h2&gt;iPhoney&lt;/h2&gt;


	&lt;p&gt;Tout d&amp;#8217;abord, si vous développez sur &lt;span class="caps"&gt;OSX&lt;/span&gt;, téléchargez vite &lt;a href="http://www.marketcircle.com/iphoney/"&gt;iPhoney&lt;/a&gt;: il s&amp;#8217;agit d&amp;#8217;une petite application qui simulera l&amp;#8217;apparence de votre site dans le navigateur Safari 320&amp;#215;480 pixels de l&amp;#8217;iPhone. Cela vous permettra de voir immédiatement le résultat de vos développements sans devoir systématiquement faire un refresh sur votre iPhone (voire carrément d&amp;#8217;en acheter un, si vous êtes dans un pays où l&amp;#8217;iPhone n&amp;#8217;est pas encore disponible&amp;#8230; hum hum).&lt;/p&gt;


	&lt;h2&gt;&lt;span class="caps"&gt;MIME&lt;/span&gt;-type iPhone&lt;/h2&gt;


	&lt;p&gt;Créez un alias &lt;span class="caps"&gt;MIME&lt;/span&gt;-type pour l&amp;#8217;iPhone en utilisant les initialiseurs de Rails 2 :&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;
# config/initializers/mime_types
Mime::Type.register_alias "text/html", :iphone
&lt;/code&gt;&lt;/pre&gt;

	&lt;h2&gt;Détection de l&amp;#8217;iPhone&lt;/h2&gt;


	&lt;p&gt;La recommandation officielle d&amp;#8217;Apple, lors de la détection d&amp;#8217;un navigateur client de type iPhone, est de non pas rediriger vers une version du site faite pour iPhone, mais plutôt de montrer le site dans sa version &amp;#8220;normale&amp;#8221; en proposant un lien vers la version iPhone. La raison pour cela est que les utilisateurs d&amp;#8217;iPhone sont habitués à naviguer sur l&amp;#8217;entièreté du web et ne veulent être contraint à n&amp;#8217;avoir accès qu&amp;#8217;à un sous-ensemble limité.&lt;/p&gt;


	&lt;p&gt;Pour effectuer la détection de l&amp;#8217;iPhone, Apple recommande de chercher la chaîne de caractères &amp;#8220;Mobile Safari&amp;#8221; (et non &amp;#8220;iPhone&amp;#8221; ou &amp;#8220;iPod Touch&amp;#8221;, ceci afin de rester ouvert à d&amp;#8217;éventuels autres appareils dans le futur). Une solution est donc d&amp;#8217;ajouter à votre &lt;code&gt;application_helper.rb&lt;/code&gt; la méthode suivante:&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;
# Détection d'une requête iPhone ou iPod touch (navigateur Mobile Safari)
def iphone_user_agent?
  request.env["HTTP_USER_AGENT"] &amp;#38;&amp;#38;
  request.env["HTTP_USER_AGENT"][/(Mobile\/.+Safari)/]
end
&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Dans votre vue, montrez un message pour les navigateurs iPhone pointant vers la version adaptée:&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;
&amp;lt;% if iphone_user_agent? -%&amp;gt;
&amp;lt;div class="message"&amp;gt;
  &amp;lt;p&amp;gt;
    Vous naviguez à partir d'un iPhone?
    &amp;lt;a href="http://iphone.monsite.com/"&amp;gt;Utilisez la version optimisée&amp;lt;/a&amp;gt;.
  &amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;% end -%&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

	&lt;h2&gt;Sous-domaine iPhone&lt;/h2&gt;


	&lt;p&gt;Donc, plutôt que de forcer l&amp;#8217;adaptation du site à l&amp;#8217;iPhone, nous proposons cette option via un sous-domaine alternatif (avec un lien retour au cas où l&amp;#8217;utilisateur voudrait malgré tout voir le site &amp;#8220;normal&amp;#8221;). A vous de configurer votre serveur &lt;span class="caps"&gt;DNS&lt;/span&gt; pour permettre cette possibilité. Pour le développement en local, une solution est de  simplement éditer votre fichier &lt;code&gt;/etc/hosts&lt;/code&gt; et y rajouter la référence à ce nom de domaine fictif:&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;
127.0.0.1 iphone.monsite.com
&lt;/code&gt;&lt;/pre&gt;

	&lt;h2&gt;Ajustement du format à l&amp;#8217;iPhone&lt;/h2&gt;


	&lt;p&gt;Ces quelques méthodes privées permettent d&amp;#8217;automatiquement appliquer le format pour iPhone si celui-ci est détecté:&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;
class ApplicationController &amp;lt; ActionController::Base

    before_filter :adjust_format_for_iphone

private

  # Utiliser le format iPhone si la requête est faite
  # au sous-domaine iphone.monsite.com
  def adjust_format_for_iphone    
    request.format = :iphone if iphone_request?
  end

  # Renvoie true pour les requêtes vers requests to iphone.monsite.com
  def iphone_request?
    return (request.subdomains.first == "iphone" ||
            params[:format] == "iphone")
  end

end
&lt;/code&gt;&lt;/pre&gt;

	&lt;h2&gt;Gestion de l&amp;#8217;orientation&lt;/h2&gt;


	&lt;p&gt;L&amp;#8217;iPhone permet aux utilisateurs de naviguer sur le web en mode portrait comme en mode paysage. Cette fonctionnalité peut avoir un énorme impact sur votre application. En effet, vous pourriez d&amp;#8217;une part vouloir adapter vos &lt;span class="caps"&gt;CSS&lt;/span&gt; en fonction de l&amp;#8217;orientation (position des menus, des publicités, etc.), et d&amp;#8217;autre part, utiliser Ruby pour suivre quelle orientation vos utilisateurs préfèrent.&lt;/p&gt;


	&lt;p&gt;Pour l&amp;#8217;instant, il n&amp;#8217;y a malheureusement pas de solution élégante au problème. Une solution est de sonder de manière régulière l&amp;#8217;orientation actuelle de l&amp;#8217;iPhone via JavaScript, et réagir en cas de changement. Par exemple, le code suivant vérifie 5 fois par seconde l&amp;#8217;orientation actuelle et met à jour un attribut de la balise body appelé &amp;#8220;orientation&amp;#8221; :&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;
currentWidth = 0;
window.setInterval( 'checkMyOrientation()', 200 );

function checkMyOrientation() {
 if (window.innerWidth != currentWidth) {
  currentWidth = window.innerWidth;
  var myOrientation = (currentWidth == 320) ? "upright" : "landscape";
  document.body.setAttribute("orientation", myOrientation);
  }
};
&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Cet attribut &amp;#8220;orientation&amp;#8221; n&amp;#8217;est pas un attribut standard mais cela est permis dans les &lt;span class="caps"&gt;CSS&lt;/span&gt;. Il est ainsi possible de définir en &lt;span class="caps"&gt;CSS&lt;/span&gt; un look tout à fait différent suivant l&amp;#8217;orientation, avec les sélecteurs &lt;code&gt;body[orientation="upright"]&lt;/code&gt; et &lt;code&gt;body[orientation="landscape"]&lt;/code&gt;, et ce entièrement du côté client.&lt;/p&gt;


	&lt;p&gt;Si, par contre, les changements à faire sont plus conséquents et nécessitent l&amp;#8217;intervention du serveur, libre à vous de remplacer la ligne mettant à jour l&amp;#8217;attribut &amp;#8220;orientation&amp;#8221; par un appel &lt;span class="caps"&gt;AJAX&lt;/span&gt;.&lt;/p&gt;


	&lt;h2&gt;Empêcher le zoom&lt;/h2&gt;


	&lt;p&gt;Même si c&amp;#8217;est, en quelque sorte, imposer une contrainte sur l&amp;#8217;expérience utilisateur de votre application, il est possible que vous souhaitiez désactiver le zoom disponible sur Mobile Safari. Cela peut servir, par exemple, si vous souhaitez rendre aussi discret que possible le côté &amp;#8220;page web&amp;#8221; de votre application et simuler le comportement d&amp;#8217;une application iPhone native. Pour désactiver le zoom, utilisez &lt;code&gt;user-scalable=no&lt;/code&gt; :&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;
&amp;lt;meta name="viewport" content="user-scalable=no" /&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

	&lt;h2&gt;Liens vers un numéro de téléphone&lt;/h2&gt;


	&lt;p&gt;En principe, l&amp;#8217;iPhone détecte automatiquement les numéros et les convertit si nécessaire, ce qui vous permet d&amp;#8217;appeler un numéro indiqué sur une page rien qu&amp;#8217;en cliquant dessus. Evidemment, l&amp;#8217;iPhone ne reconnaît pas tous les formats de numéros de téléphone et il est possible que vous vouliez permettre un appel via un lien sans afficher platement le numéro sur la page.&lt;/p&gt;


	&lt;p&gt;Pour ce faire, le format &amp;#8220;tel:&amp;#8221; est reconnu par Mobile Safari; il fonctionne de la même manière que le fameux &amp;#8220;mailto:&amp;#8221;, et vous permet d&amp;#8217;appeler un numéro en cas de clic tout en permettant de rendre le lien plus descriptif: &lt;code&gt;&amp;lt;a href="tel:33612345678"&amp;gt;Pierre&amp;lt;/a&amp;gt;&lt;/code&gt;.&lt;/p&gt;


	&lt;h2&gt;Utilisation d&amp;#8217;iUI et création de vues pour iPhone&lt;/h2&gt;


	&lt;p&gt;Pour conclure, parlons du framework &lt;a href="http://code.google.com/p/iui/"&gt;iUI&lt;/a&gt;, basé sur le travail de &lt;a href="http://joehewitt.com/"&gt;Joe Hewitt&lt;/a&gt;, qui simplifie énormément le développement d&amp;#8217;applications web pour iPhone. Il suffit d&amp;#8217;inclure les fichiers JavaScript et &lt;span class="caps"&gt;CSS&lt;/span&gt; d&amp;#8217;iUI et suivre certaines conventions dans les vues pour simuler un comportement iPhone natif, tels que les menus coulissants et les rechargements &lt;span class="caps"&gt;AJAX&lt;/span&gt;.&lt;/p&gt;


	&lt;p&gt;Rails 2 rend triviale la création de vues différentes en fonction du format, y compris les layouts. Voici un exemple de layout pour iPhone (&lt;code&gt;app/views/layouts/application.iphone.erb&lt;/code&gt;) qui utilise les conventions pour iUI:&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;
&amp;lt;!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" 
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"&amp;gt;
&amp;lt;html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"&amp;gt;
&amp;lt;head&amp;gt;
    &amp;lt;meta http-equiv="content-type" content="text/html; charset=utf-8" /&amp;gt;
    &amp;lt;meta id="viewport" name="viewport" content="width=320;
      initial-scale=1.0; maximum-scale=1.0; user-scalable=0;"/&amp;gt;
    &amp;lt;title&amp;gt;&amp;lt;%= @page_title -%&amp;gt;&amp;lt;/title&amp;gt;
  &amp;lt;%= stylesheet_link_tag 'iui' %&amp;gt;
  &amp;lt;%= javascript_include_tag 'iui' %&amp;gt;
&amp;lt;/head&amp;gt;
&amp;lt;body&amp;gt;
    &amp;lt;div class="toolbar"&amp;gt;
        &amp;lt;h1 id="pageTitle"&amp;gt;&amp;lt;/h1&amp;gt;
        &amp;lt;a id="backButton" class="button" href="#"&amp;gt;&amp;lt;/a&amp;gt;
    &amp;lt;/div&amp;gt;

    &amp;lt;%= yield %&amp;gt;
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;En ce qui concerne les vues, il faut s&amp;#8217;adapter aux conventions d&amp;#8217;iUI. Les liens &amp;#8220;normaux&amp;#8221; sont chargés via &lt;span class="caps"&gt;AJAX&lt;/span&gt; et provoquent un &amp;#8220;glissement latéral&amp;#8221; de la page vers la vue de destination. Il est possible de spécifier &lt;code&gt;target="_self"&lt;/code&gt; pour remplacer la page entière, ou &lt;code&gt;target="_replace"&lt;/code&gt; pour remplacer l&amp;#8217;élément avec la réponse &lt;span class="caps"&gt;AJAX&lt;/span&gt;.&lt;/p&gt;


	&lt;p&gt;Exemple:&lt;/p&gt;


	&lt;p&gt;&lt;code&gt;index.iphone.erb&lt;/code&gt;&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;
&amp;lt;ul title="Bienvenue" selected="true"&amp;gt;
    &amp;lt;li&amp;gt;&amp;lt;%= link_to 'Action exemple', example_path %&amp;gt;&amp;lt;/li&amp;gt;
    &amp;lt;li&amp;gt;&amp;lt;%= link_to 'Déconnexion', logout_path, :method =&amp;gt; :delete,
            :target =&amp;gt; '_self' %&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;&lt;code&gt;show.iphone.erb&lt;/code&gt;&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;
&amp;lt;div class="panel" title="Exemple" selected="true"&amp;gt;
    &amp;lt;h2&amp;gt;Contenu exemple&amp;lt;/h2&amp;gt;
    &amp;lt;p&amp;gt;Voici du contenu&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Attention: comme iUI charge toujours le contenu via &lt;span class="caps"&gt;AJAX&lt;/span&gt;, le layout ne doit être chargé que pour la première page. Toutes les requêtes suivantes doivent utiliser &lt;code&gt;render :layout =&amp;gt; false&lt;/code&gt; (sauf dans le cas particulier &lt;code&gt;target="_replace"&lt;/code&gt; qui charge une nouvelle page). Si vous observez des bizarreries dans le rendu de certaines pages, c&amp;#8217;est probablement à cause de cette particularité.&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;
respond_to do |format|
    format.iphone do  # action.iphone.erb
      render :layout =&amp;gt; false
    end
end
&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Bien entendu, rien ne vous oblige à utiliser iUI et dans pas mal de cas, ce framework s&amp;#8217;avèrera trop restrictif. Mais si vous aimez le &amp;#8220;look&amp;#8217;n&amp;#8217;feel&amp;#8221; de l&amp;#8217;interface proposée sur  l&amp;#8217;iPhone, iUI vous permet d&amp;#8217;avoir celui-ci sur votre site en vous épargnant tous les petits détails techniques.&lt;/p&gt;


	&lt;h2&gt;Resources&lt;/h2&gt;


	&lt;p&gt;Cet article est essentiellement une combinaison/traduction des ressources anglophones suivantes:&lt;/p&gt;


	&lt;ul&gt;
	&lt;li&gt;&lt;a href="http://www.slashdotdash.net/articles/2007/12/04/iphone-on-rails-creating-an-iphone-optimised-version-of-your-rails-site-using-iui-and-rails-2"&gt;iPhone on Rails &amp;#8211; Creating an iPhone optimised version of your Rails site using iUI and Rails 2&lt;/a&gt;&lt;/li&gt;
		&lt;li&gt;&lt;a href="http://railspikes.com/2007/11/8/iphone-subdomains-with-rails"&gt;iPhone subdomains with Rails&lt;/a&gt;&lt;/li&gt;
		&lt;li&gt;&lt;a href="http://www.devx.com/wireless/Article/35532"&gt;iPhone Web Development with Ruby on Rails&lt;/a&gt;&lt;/li&gt;
	&lt;/ul&gt;


	&lt;p&gt;Les pages suivantes vous donneront des informations additionnelles:&lt;/p&gt;


	&lt;ul&gt;
	&lt;li&gt;&lt;a href="http://developer.apple.com/iphone/"&gt;Le site officiel d&amp;#8217;Apple sur le développement iPhone&lt;/a&gt;&lt;/li&gt;
		&lt;li&gt;&lt;a href="http://code.google.com/p/iui/"&gt;Le site web officiel d&amp;#8217;iUI&lt;/a&gt;&lt;/li&gt;
		&lt;li&gt;&lt;a href="http://www.joehewitt.com/blog/introducing_iui.php"&gt;L&amp;#8217;article initial de Joe Hewitt sur iUI&lt;/a&gt;&lt;/li&gt;
	&lt;/ul&gt;</description>
      <pubDate>Fri, 21 Dec 2007 00:00:00 +0100</pubDate>
      <link>http://www.frailers.net/articles/9-rails-et-l-iphone</link>
      <guid>http://www.frailers.net/articles/9-rails-et-l-iphone</guid>
    </item>
    <item>
      <title>Plugin de la semaine : Rails Widgets (2)</title>
      <description>&lt;h2&gt;Les gestionnaires de visibilité&lt;/h2&gt;


	&lt;p&gt;Ce que j&amp;#8217;appelle ici un gestionnaire de visibilité est simplement le code javascript nécessaire à ajouter pour cacher ou montrer un élément du &lt;span class="caps"&gt;DOM&lt;/span&gt; d&amp;#8217;une page web donnée.&lt;/p&gt;


	&lt;p&gt;On rencontre souvent cette fonctionnalité lorsqu&amp;#8217;on affiche un liste d&amp;#8217;éléments et qu&amp;#8217;on désire afficher/cacher les éléments de cette liste.&lt;/p&gt;


	&lt;p&gt;Widgets permet de créer extrêmement rapidement un bloc de détails que l&amp;#8217;utilisateur peut afficher ou cacher.&lt;/p&gt;


	&lt;p&gt;Après avoir installé le plugin comme décrit dans le &lt;a href="http://www.frailers.net/articles/7"&gt;précédent article&lt;/a&gt;, il suffit d&amp;#8217;ajouter ces quelques lignes de code:&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;
&amp;lt;% for element in @list %&amp;gt;
  &amp;lt;div class="element"&amp;gt;
    &amp;lt;%= h element.info %&amp;gt;
     &amp;lt;%= show_detail_for element %&amp;gt;

    &amp;lt;% detail_for element do %&amp;gt;
      Plus de détails...
      &amp;lt;%= h element.detailed_info %&amp;gt;

      &amp;lt;%= hide_detail_for element %&amp;gt;
    &amp;lt;% end %&amp;gt;
  &amp;lt;/div&amp;gt;
&amp;lt;% end %&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;N&amp;#8217;oubliez pas d&amp;#8217;inclure les javascripts par défaut et particulièrement la librairie prototype dans votre vue.&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;
&amp;lt;%= javascript_include_tag :defaults %&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Profitez du résultat.&lt;/p&gt;


	&lt;h2&gt;Les info-bulles&lt;/h2&gt;


	&lt;p&gt;Avec Widgets, il devient aussi aisé de créer des info-bulles.&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;
&amp;lt;% tooltip "info" do %&amp;gt;
  &amp;lt;h3&amp;gt;Titre de mon info-bulle&amp;lt;/h3&amp;gt;
  Contenu...
&amp;lt;% end %&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;A la place de la chaine de caractère, vous pouvez, bien entendu, passer une image grâce à image_tag.&lt;/p&gt;


	&lt;p&gt;Si vous préférez rapatrier le contenu de l&amp;#8217;info-bulle à la volée grâce à &lt;span class="caps"&gt;AJAX&lt;/span&gt;, c&amp;#8217;est aussi possible.&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;
&amp;lt;% 
tooltip do |t|
  t.named image_tag('info') || 'info' 
  t.link_to_remote :action =&amp;gt; 'show_tooltip'
end
%&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Et voilà de quoi simplifier encore un peu plus vos vues. Qu&amp;#8217;en pensez-vous?
Nous verrons encore deux fonctionnalités de ce plugin la semaine prochaine.&lt;/p&gt;


	&lt;p&gt;&lt;strong&gt;Ressources&lt;/strong&gt; : &lt;a href="http://blog.seesaw.it/files/RailsToItaly-RailsWidgets-PaoloDona.pdf"&gt;Présentation de Rails Widgets&lt;/a&gt; par son créateur : Paolo Dona&lt;/p&gt;</description>
      <pubDate>Wed, 12 Dec 2007 00:00:00 +0100</pubDate>
      <link>http://www.frailers.net/articles/8-plugin-de-la-semaine-rails-widgets-2</link>
      <guid>http://www.frailers.net/articles/8-plugin-de-la-semaine-rails-widgets-2</guid>
    </item>
    <item>
      <title>Plugin de la semaine: Rails Widgets (1)</title>
      <description>&lt;p&gt;Le plugin &lt;strong&gt;Widgets&lt;/strong&gt; rassemble plusieurs helpers qui permettent d&amp;#8217;ajouter facilement des éléments d&amp;#8217;interface graphique à vos pages.
Aujourd&amp;#8217;hui, 7 éléments sont disponibles :&lt;/p&gt;


	&lt;ul&gt;
	&lt;li&gt;Les onglets (Tabnav)&lt;/li&gt;
		&lt;li&gt;Les liens de navigation (Navigation)&lt;/li&gt;
		&lt;li&gt;Le gestionnaire de visibilité (Show/Hide)&lt;/li&gt;
		&lt;li&gt;La présentation en table (Tableizer)&lt;/li&gt;
		&lt;li&gt;Les icônes info (Tooltips)&lt;/li&gt;
		&lt;li&gt;La mise en page en colonne (ColumnLayout)&lt;/li&gt;
		&lt;li&gt;Les menus contextuels (Nubbins)&lt;/li&gt;
	&lt;/ul&gt;


	&lt;p&gt;&lt;strong&gt;Pourquoi ce projet est-il tellement prometteur?&lt;/strong&gt;&lt;/p&gt;


	&lt;p&gt;Aujourd&amp;#8217;hui, les technologies web  permettent de concevoir des contrôles graphiques (widgets) de manière tout à fait différente grâce au couple &lt;span class="caps"&gt;HTML&lt;/span&gt;-Javascript. (voir &lt;a href="http://www.fredcavazza.net/2007/11/16/songza-experimente-linterface-transparente/"&gt;le billet à propos de Songza&lt;/a&gt; chez Fred Cavazza).
Le &lt;strong&gt;projet Widget&lt;/strong&gt; permet non seulement de &amp;#8220;webiser&amp;#8221; (j&amp;#8217;entends par là transformer en html/javascript) les contrôles graphiques &amp;#8220;traditionnels&amp;#8221; (TabNav, Tooltip) mais aussi d&amp;#8217;en créer des nouveaux (Nubbins, Navigation) propres au web, le tout de manière très &lt;span class="caps"&gt;DRY&lt;/span&gt;.&lt;/p&gt;


	&lt;p&gt;Ce projet est maintenu par &lt;a href="http://paolodona.blogspot.com/"&gt;Paolo Dona&lt;/a&gt;, de la société italienne &lt;a href="http://blog.seesaw.it/"&gt;Seesaw&lt;/a&gt;.&lt;/p&gt;


	&lt;p&gt;Trêve de discussions, passons à la pratique.&lt;/p&gt;


	&lt;h2&gt;Installation du plugin&lt;/h2&gt;


	&lt;p&gt;Comme d&amp;#8217;habitude :&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;
ruby script/plugin install svn://svn.seesaw.it/widgets/trunk
&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;ou&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;
piston import svn://svn.seesaw.it/widgets/trunk vendor/plugins/widgets
&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;si vous utilisez piston.&lt;/p&gt;


	&lt;h2&gt;Installer TabNav:&lt;/h2&gt;


	&lt;p&gt;Le widget TabNav permet de créer en quelques secondes de magnifiques onglets pour votre site.
Pour commencer, il faut générer le &lt;code&gt;partial&lt;/code&gt; qui représentera les onglets:&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;
ruby script/generate tabnav nom_de_la_bar_donglets
&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Cette commande crée le partial &lt;code&gt;_nom_de_la_bar_donglets_tabnav.rhtml&lt;/code&gt; dans &lt;code&gt;app/views/widgets&lt;/code&gt;.
Il ne reste plus qu&amp;#8217;à ajouter les onglets dans vos vues:&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;
&amp;lt;% tabnav :nom_de_la_bar_donglets do %&amp;gt;
 # Placez le contenu ici
&amp;lt;% end %&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;On ajoutera généralement ce code dans &lt;code&gt;application.html.erb&lt;/code&gt; ou plus généralement dans un layout.  Le contenu sera alors simplement &lt;code&gt;&amp;lt;%= yield %&amp;gt;&lt;/code&gt;.&lt;/p&gt;


	&lt;p&gt;A ce stade, vous pouvez lancer votre application et voir apparaitre les onglets dont les noms correspondent à ceux de vos différents contrôleurs.&lt;/p&gt;


	&lt;h2&gt;Personnaliser ses onglets&lt;/h2&gt;


	&lt;p&gt;Les noms que vous donnerez à vos contrôleurs ne sont pas ceux  que vous souhaitez donner à vos onglets? Pas de problèmes. Il suffit d&amp;#8217;éditer le partial  &lt;code&gt;_nom_de_la_bar_donglets_tabnav.rhtml&lt;/code&gt; qui doit ressembler à ceci:&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;
&amp;lt;%  
render_tabnav :nom_de_la_bar_donglets_tabnav, 
              :generate_css =&amp;gt; false, 
              :html =&amp;gt; {:class=&amp;gt; 'myCssClass', :id=&amp;gt;'myCssId'} do  

  add_tab do |t|
    t.named 'Accueil'
    t.titled 'Home Page'
    t.links_to :controller=&amp;gt;'static', :action=&amp;gt;'index'
    t.highlights_on :controller=&amp;gt;'users', :action=&amp;gt;'new'
    t.highlights_on :controller=&amp;gt;'account'
  end 
end
%&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Les arguments de &lt;code&gt;render_tabnav&lt;/code&gt; sont évidents :&lt;/p&gt;


	&lt;ul&gt;
	&lt;li&gt;Le premier est le nom de la bar d&amp;#8217;onglets. &lt;/li&gt;
		&lt;li&gt;&lt;code&gt;:generate_css&lt;/code&gt; détermine si les feuilles de style doivent être &amp;#8220;inline&amp;#8221; ou non (par défaut). &lt;/li&gt;
		&lt;li&gt;&lt;code&gt;:html&lt;/code&gt; est un hash de toutes les options &lt;span class="caps"&gt;HTML&lt;/span&gt; à passer à la barre d&amp;#8217;onglets.&lt;/li&gt;
	&lt;/ul&gt;


	&lt;p&gt;Les différentes méthodes de l&amp;#8217;onglet vont permettre de définir son comportement.  La méthode &lt;code&gt;named&lt;/code&gt; définit le nom qui apparaitra sur l&amp;#8217;onglet. La méthode &lt;code&gt;titled&lt;/code&gt; définit la valeur de l&amp;#8217;option &lt;span class="caps"&gt;HTML&lt;/span&gt; &lt;code&gt;alt&lt;/code&gt;. La méthode links_to est un lien vers la méthode correspondante dans ActionView et définit la cible de l&amp;#8217;onglet.&lt;/p&gt;


	&lt;p&gt;Enfin, la méthode &lt;code&gt;highlights_on&lt;/code&gt; permet de définir quand un onglet sera affiché comme &amp;#8220;actif&amp;#8221;. Dans l&amp;#8217;exemple, l&amp;#8217;onglet sera &amp;#8220;activé&amp;#8221; lorsque le contrôleur est &lt;code&gt;static&lt;/code&gt; et l&amp;#8217;action &lt;code&gt;index&lt;/code&gt;, lorsque le contrôleur est &lt;code&gt;users&lt;/code&gt; et l&amp;#8217;action &lt;code&gt;new&lt;/code&gt; ou encore lorsque le contrôleur est &lt;code&gt;account&lt;/code&gt;.&lt;/p&gt;


	&lt;h2&gt;La barre d&amp;#8217;onglets sans cadre&lt;/h2&gt;


	&lt;p&gt;Par défaut, &lt;strong&gt;Tabnav&lt;/strong&gt; affiche un cadre autour du contenu de l&amp;#8217;onglet. Si vous désirez que vos onglets n&amp;#8217;encadrent pas leur contenu, il suffit de modifier la manière dont vous insérez les onglets:&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;
&amp;lt;% tabnav :nom_de_la_bar_donglets %&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;au lieu de&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;
&amp;lt;% tabnav :nom_de_la_bar_donglets do %&amp;gt;
 # Placez le contenu ici
&amp;lt;% end %&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

	&lt;h2&gt;Conclusion&lt;/h2&gt;


	&lt;p&gt;Voilà, j&amp;#8217;espère que ces petites astuces vous auront fait gagner pas mal de temps de développement.
La semaine prochaine, je vous ferai découvrir d&amp;#8217;autres widgets.
Avez-vous des idées d&amp;#8217;autres widgets que vous utilisez tous les jours?&lt;/p&gt;</description>
      <pubDate>Tue, 04 Dec 2007 00:00:00 +0100</pubDate>
      <link>http://www.frailers.net/articles/7-plugin-de-la-semaine-rails-widgets-1</link>
      <guid>http://www.frailers.net/articles/7-plugin-de-la-semaine-rails-widgets-1</guid>
    </item>
    <item>
      <title>Jointures multiples dans ActiveRecord grâce à include</title>
      <description>&lt;p&gt;Rails est génial. Mais quand les choses se compliquent, ses détracteurs disent que le framework est limité. J&amp;#8217;y ai cru un instant lorsque j&amp;#8217;ai rencontré le problème que je vous décris ci-dessous. J&amp;#8217;ai finalement constaté que Rails était génial même dans les situations compliquées.&lt;/p&gt;


	&lt;p&gt;Pour exposer le problème, rien de tel qu&amp;#8217;un petit exemple:&lt;/p&gt;


	&lt;p&gt;L&amp;#8217;application qui me pose problème est destinée à gérer un ensemble de bibliothèques (&lt;code&gt;Library&lt;/code&gt;) contentant plusieurs livres (&lt;code&gt;Book&lt;/code&gt;) qui eux-même ont un ou plusieurs auteurs (&lt;code&gt;Author&lt;/code&gt;). Un auteur peut bien entendu avoir écrit plusieurs livres et un livre peut se trouver dans plusieurs bibliothèques (le lecteur attentif aura compris que nous ne parlons pas de l&amp;#8217;exemplaire du livre mais bien de son édition).&lt;/p&gt;


	&lt;p&gt;Pour mettre en avant la cardinalité multiple, nous allons utiliser has_many :through. Nous créons donc deux tables de jointure : &amp;#8220;propriété&amp;#8221; (&lt;code&gt;Ownership&lt;/code&gt;) pour joindre bibliothèque et livre et &amp;#8220;autorat&amp;#8221; (&lt;code&gt;Authorship&lt;/code&gt;) pour joindre livre et auteur.&lt;/p&gt;


	&lt;p&gt;Le modèle est le suivant :&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;
class Library &amp;lt; ActiveRecord::Base
  has_many :ownerships
  has_many :books, :through =&amp;gt; :ownerships
end

class Book &amp;lt; ActiveRecord::Base
  has_many :ownerships
  has_many :libraries, :through =&amp;gt; :ownerships

  has_many :authorships
  has_many :authors, :through =&amp;gt; :authorships
end

class Author &amp;lt; ActiveRecord::Base
  has_many :authorships
  has_many :books, :through =&amp;gt; :authorships
end
&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Et les tables de jointure:&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;
class Ownership &amp;lt; ActiveRecord::Base
  belongs_to :library
  belongs_to :book
end

class Authorship &amp;lt; ActiveRecord::Base
  belongs_to :book
  belongs_to :author
end
&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Dans notre exemple, nous voulons simplement récupérer la liste de tous les auteurs d&amp;#8217;une bibliothèque.&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;
class Library &amp;lt; ActiveRecord::Base
  has_many :ownerships
  has_many :books, :through =&amp;gt; :ownerships

  def find_all_authors
    books.inject([]){|authors,book| authors + book.authors}.uniq
  end
end
&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;L&amp;#8217;opération que nous faisons ici est potentiellement très lourde. En effet, elle va générer autant de requêtes &lt;span class="caps"&gt;SQL&lt;/span&gt; qu&amp;#8217;il y a de livres dans la bibliothèque (lors de l&amp;#8217;appel à &lt;code&gt;book.authors&lt;/code&gt;).&lt;/p&gt;


	&lt;p&gt;En &lt;span class="caps"&gt;SQL&lt;/span&gt;, nous aurions fait une jointure multiple pour récupérer l&amp;#8217;information recherchée. Allons-nous devoir utiliser &lt;code&gt;find_by_sql&lt;/code&gt;?
Lorsque je me suis retrouvé confronté à ce problème, j&amp;#8217;ai bien pensé que j&amp;#8217;allais devoir y passer. Mais, comme je le disais, Rails est génial.&lt;/p&gt;


	&lt;p&gt;L&amp;#8217;option Activerecord utilisée ici est &lt;code&gt;:include&lt;/code&gt;. D&amp;#8217;habitude, &lt;code&gt;:include&lt;/code&gt; est utilisée pour précharger les objets associé à un objet donné. Ce que réalise cette option est en réalité une &lt;em&gt;jointure externe à droite&lt;/em&gt;. Il ne reste alors plus qu&amp;#8217;à poser les bonnes &lt;code&gt;:conditions&lt;/code&gt; pour obtenir le résultat désiré.&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;
class Library &amp;lt; ActiveRecord::Base
  has_many :ownerships
  has_many :books, :through =&amp;gt; :ownerships

  def find_all_authors
    Author.find(:all, :include =&amp;gt; [:books =&amp;gt; :libraries], 
                      :conditions =&amp;gt; ["libraries.id = ?", self.id])
  end
end
&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Plusieurs remarques peuvent être faites à propos de ce exemple:&lt;/p&gt;


	&lt;ul&gt;
	&lt;li&gt;Nous utilisons la version imbriquée de &lt;code&gt;include&lt;/code&gt;. En effet, la table Author sur laquelle nous faisons la requête ne contient aucune référence vers libraries.&lt;/li&gt;
	&lt;/ul&gt;


	&lt;ul&gt;
	&lt;li&gt;Nous n&amp;#8217;avons pas besoin de mentionner les classes d&amp;#8217;associations (ownership et authorship) dans &lt;code&gt;include&lt;/code&gt;, elle seront automatiquement ajoutées par rails.&lt;/li&gt;
	&lt;/ul&gt;


	&lt;ul&gt;
	&lt;li&gt;Dans la condition, &lt;code&gt;"libraries"&lt;/code&gt; est écrit au pluriel pour désigner le nom de la table.&lt;/li&gt;
	&lt;/ul&gt;


	&lt;ul&gt;
	&lt;li&gt;Les imbrications du &lt;code&gt;include&lt;/code&gt; peuvent être réalisées autant de fois que désiré et peuvent être combinées. Cependant, bien que cette technique permette de réaliser un nombre important de requêtes en une seule, il ne faut pas oublier que l&amp;#8217;opération &lt;span class="caps"&gt;JOIN&lt;/span&gt; en &lt;span class="caps"&gt;SQL&lt;/span&gt; est lourde et qu&amp;#8217;il faut donc essayer de l&amp;#8217;éviter tant que possible.&lt;/li&gt;
	&lt;/ul&gt;


	&lt;p&gt;Pour cloturer ce billet, je préciserai que je n&amp;#8217;ai trouvé que très peu d&amp;#8217;informations sur &lt;code&gt;:include&lt;/code&gt; tant au niveau de la communauté anglophone que francophone. Ai-je raté un point important? Y a-t-il une solution plus élégante? Et vous, comment faites-vous?&lt;/p&gt;</description>
      <pubDate>Thu, 22 Nov 2007 00:00:00 +0100</pubDate>
      <link>http://www.frailers.net/articles/6-jointures-multiples-dans-activerecord-grace-a-include</link>
      <guid>http://www.frailers.net/articles/6-jointures-multiples-dans-activerecord-grace-a-include</guid>
    </item>
    <item>
      <title>Gabarits imbriqués avec le plugin nested_layouts</title>
      <description>&lt;h2&gt;Fonctionnement des gabarits dans Rails&lt;/h2&gt;


	&lt;p&gt;Pour rappel, Rails fournit un système astucieux de gabarits de pages (templates). Si vous nommez une vue &amp;#8220;application.html.erb&amp;#8221; dans le dossier &amp;#8220;app/views/layouts&amp;#8221;, celle-ci sera utilisée comme gabarit de page pour l&amp;#8217;ensemble des vues présentes dans votre site. Pour spécifier dans ce gabarit l&amp;#8217;endroit où la vue particulière doit intervenir, vous faites usage du mot-clef &lt;code&gt;yield&lt;/code&gt;. Dans l&amp;#8217;exemple qui suit, la phrase &amp;#8220;Bonjour!&amp;#8221; propre à l&amp;#8217;action index du contrôleur &amp;#8220;MonControleur&amp;#8221; suivra le titre &amp;#8220;Bievenue sur mon site&amp;#8221; présent dans le gabarit général de l&amp;#8217;application:&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;
# app/views/layouts/application.html.erb
&amp;lt;html&amp;gt;
  &amp;lt;body&amp;gt;
    &amp;lt;h1&amp;gt;Bienvenue sur mon site&amp;lt;/h1&amp;gt;
    &amp;lt;%= yield %&amp;gt;
  &amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;

# app/views/mon_controleur/index.html.erb
Bonjour!
&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;De plus, si vous souhaitez utiliser un gabarit différent d&amp;#8217;un contrôleur à l&amp;#8217;autre, il est possible de créer une vue du nom de contrôleur dans ce même dossier &amp;#8220;app/views/layouts&amp;#8221; et toutes les actions de ce contrôleur utiliseront par défaut ce gabarit. Cela permet d&amp;#8217;avoir un gabarit particulier pour chaque partie de votre application, ce qui s&amp;#8217;avère souvent utile pour afficher des sous-menus (comme un menu &amp;#8220;catégories&amp;#8221; dans un contrôleur &amp;#8220;produits&amp;#8221;), par exemple.&lt;/p&gt;


	&lt;p&gt;Le problème est que, dans ce cas, Rails utilise ce gabarit &lt;i&gt;au lieu&lt;/i&gt; du gabarit général (qui est alors simplement ignoré), ce qui peut-être embêtant étant donné que la plupart du temps, l&amp;#8217;ensemble de votre application garde malgré tout un design commun (logo, menu général, footer, etc.).&lt;/p&gt;


	&lt;p&gt;On voudrait donc pouvoir garder ce gabarit commun, tout en permettant l&amp;#8217;usage d&amp;#8217;un sous-gabarit propre. C&amp;#8217;est là qu&amp;#8217;intervient le plugin &lt;a href="http://nested-layouts.rubyforge.org/"&gt;Nested Layouts&lt;/a&gt;.&lt;/p&gt;


	&lt;h2&gt;Le plugin Nested Layouts&lt;/h2&gt;


	&lt;p&gt;Ce plugin est très simple (il ne fait pas 30 lignes de code). Commencez tout d&amp;#8217;abord par l&amp;#8217;installer (et n&amp;#8217;oubliez pas de redémarrer votre serveur ensuite, pour le charger):&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;
script/plugin install svn://rubyforge.org/var/svn/nested-layouts/trunk/nested_layouts
&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Vous pouvez maintenant spécifier des sous-gabarits. Votre &lt;code&gt;application.html.erb&lt;/code&gt; reste identique à auparavant:&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;
# app/views/layouts/application.html.erb
&amp;lt;html&amp;gt;
  &amp;lt;body&amp;gt;
    &amp;lt;h1&amp;gt;Bienvenue sur mon site&amp;lt;/h1&amp;gt;
    &amp;lt;%= yield %&amp;gt;
  &amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;De même que vos vues propre à chaque action:&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;
# app/views/mon_controleur/index.html.erb
Bonjour!
&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;La différence est que maintenant, vous pouvez appeler le gabarit général à partir d&amp;#8217;un sous-gabarit, dans notre exemple celui propre au contrôleur &amp;#8220;mon_controleur&amp;#8221; :&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;
# app/views/layouts/mon_controleur.html.erb
&amp;lt;% inside_layout 'application' do -%&amp;gt;
  &amp;lt;h2&amp;gt;Mon sous-menu&amp;lt;/h2&amp;gt;
  &amp;lt;ul&amp;gt;
    &amp;lt;li&amp;gt;Element 1&amp;lt;/li&amp;gt;
    &amp;lt;li&amp;gt;Element 2&amp;lt;/li&amp;gt;
  &amp;lt;/ul&amp;gt;
  &amp;lt;%= yield %&amp;gt;
&amp;lt;% end -%&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Votre action index affichera dès lors &amp;#8220;Bonjour!&amp;#8221; dans le sous-gabarit de &amp;#8220;mon_controleur&amp;#8221;, lui même inclus dans le gabarit général, ce qui donnera ceci en sortie:&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;
&amp;lt;html&amp;gt;
  &amp;lt;body&amp;gt;
    &amp;lt;h1&amp;gt;Bienvenue sur mon site&amp;lt;/h1&amp;gt;
    &amp;lt;h2&amp;gt;Mon sous-menu&amp;lt;/h2&amp;gt;
    &amp;lt;ul&amp;gt;
      &amp;lt;li&amp;gt;Element 1&amp;lt;/li&amp;gt;
      &amp;lt;li&amp;gt;Element 2&amp;lt;/li&amp;gt;
    &amp;lt;/ul&amp;gt;
    Bonjour!
  &amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;En bonus, il est même possible de passer des données du sous-gabarit vers le gabarit général, et ce au moyen de la variable &lt;code&gt;@other_data_for_outer_layout&lt;/code&gt;:&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;
# app/views/layouts/mon_controleur.html.erb
&amp;lt;% inside_layout 'application' do -%&amp;gt;
  &amp;lt;% @other_data_for_outer_layout = 'coucou' -%&amp;gt;
  &amp;lt;%= yield %&amp;gt;
&amp;lt;% end -%&amp;gt;

# app/views/layouts/application.html.erb
&amp;lt;html&amp;gt;
  &amp;lt;body&amp;gt;
    &amp;lt;h1&amp;gt;Bienvenue sur mon site&amp;lt;/h1&amp;gt;
    &amp;lt;p&amp;gt;Message du contrôleur : &amp;lt;%= @other_data_for_outer_layout %&amp;gt;&amp;lt;/p&amp;gt;
    &amp;lt;%= yield %&amp;gt;
  &amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

	&lt;h2&gt;Références&lt;/h2&gt;


	&lt;ul&gt;
	&lt;li&gt;&lt;a href="http://nested-layouts.rubyforge.org/"&gt;NestedLayouts&lt;/a&gt;&lt;/li&gt;
	&lt;/ul&gt;</description>
      <pubDate>Mon, 19 Nov 2007 00:00:00 +0100</pubDate>
      <link>http://www.frailers.net/articles/5-gabarits-imbriques-avec-le-plugin-nested-layouts</link>
      <guid>http://www.frailers.net/articles/5-gabarits-imbriques-avec-le-plugin-nested-layouts</guid>
    </item>
  </channel>
</rss>
