script/generate directement dans svn

A chaque fois que j'utilisais le script de génération de code de Ruby On Rails, je devais lancer ensuite un ajout des sources dans subversion avec un petit svn add.

Mais voilà, je viens de découvrir que cette commande est tout à fait inutile. En effet, le script de génération comprend une option qui nous permet d'éviter ce genre de manipulation inutile. Il y a l'option -c.

$ ./script/generate migration -c change_type_format
      exists  db/migrate
      create  db/migrate/030_change_type_format.rb
A         db/migrate/030_change_type_format.rb

J'adore l'implémentation de Subversion dans Ruby On Rails

Edge Rails et les routes

Edge Rails et les routes

Un script pour tester votre application pour Rails 2.0

Mislav Marohnic a réalisé un petit script Ruby pour tester si votre application Rails valide 1.2.3 l'est aussi pour la prochaine migration à Rails 2.0 (attendu avec impatience). Ce script fait une vérification de toutes les alertes (warning) que vous avez concernant les méthodes déprécié (deprecated)

Pour tester ce script, il suffit de lancer la commande suivante quand vous êtes dans le dossier de votre application :

wget http://pastie.caboo.se/99900.txt?key=krcevozww61drdeza13e3a -q -O- | ruby -

Sinon vous pouvez aussi regarder les sources

source issue de : Peter Cooper

SOAP::LC 0.0.1

Non, elle n’est pas dispo… Mais j’y aie travaillé, et pour le moment cela fonctionne plutôt bien malgré le fait que je ne gère que les parties de messages type simpleType. Il me reste à ajouter la gestion des types complexes et des éléments. N’étant pas un pro des Schéma XML, je me suis commandé un petit livre sur le sujet… Cela laisse présager de bonnes soirées en perspectives ! Je pense avoir quelque chose de fonctionnel rapidement, mais si je met à disposition une première version avant d’avoir parcouru les 412 pages, j’ai peur que cela soit un peu du bricolage ;)

Je serais à Paris Web 2007

Je serais à Paris Web 2007

Deployer un blog Typo grâce à Capistrano2

Voulant utiliser capistrano2 et mettre en place un blog Typo, j'ai décidé de déployer mon blog Typo grâce à Capistrano2. Je vais indiqué ici toutes les étapes que j'ai effectuées. Ce post aura ainsi un double intérêt.

  • Expliquer comment deployer une application Typo avec Capistrano2
  • Expliquer par l'exemple d'une utilisation de Capistrano2

Pour commencer Capistrano2 est vraiment très dépendant d'un système de versionning. Dans mon cas j'ai utilisé le dépôt subversion de Typo et comme je voulais utiliser leur version 4.1, j'ai récupérer l'url suivante qui est le tag de la version 4.1:

http://svn.typosphere.org/typo/tags/release_4_1/

Préparation de l'application à déployer

Préparation en local

Il faut commencer d'abord par faire un checkout complet de la version que l'on désire déployer. Ca permet surtout d'avoir une sorte de miroir de la version qui sera sur le serveur et ainsi faire des modifications sur cette version pour testé et ensuite les déployer sur le serveur.

On va maintenant commencer à créer un projet capistrano2. Pour cela, il suffit d'aller à la racine du répertoire de checkout et de lancer la commande :

capify

Grâce à cette commande le fichier config/deploy.rb est crée. C'est lui qui nous permettra de définir la configuration de notre application sur le serveur distant. Le fichier Capfile est lui aussi crée à la racine et il permet d'ajouter des tâches. Il suffit de le considérer comme une sorte de fichier de RakeFile.

Voici ce que j'ai mis dans mon fichier deploy.rb. Bien sur, il n'y avait pas ces informations à la base

set :application, "typoblog-dev"
set :repository,  "http://svn.typosphere.org/typo/tags/release_4_1/"

# If you aren't deploying to /u/apps/#{application} on the target
# servers (which is the default), you can specify the actual location
# via the :deploy_to variable:
set :deploy_to, "/var/rails/#{application}"

# If you aren't using Subversion to manage your source code, specify
# your SCM below:
#set :scm, :subversion

role :app, "shingara.fr"
role :web, "shingara.fr"
role :db,  "shingara.fr", :primary => true

Voici une explication de chaque champs

  • set :application => Défini le nom de l'application qu'on va être déployé. C'est surtout utilisé pour le nom du répertoire de déploiement.
  • set :repository => le chemin du dépôt Subversion qui sera récupéré lors du déploiement.
  • set :deploy_to => Défini le répertoire sur le serveur distant où seront placé les sources de l'application
  • set :scm => Le type de système de versionning qui permettra de récupérer les sources. Par défaut il s'agit de subversion.
  • role :xxx => permet de définir les serveur où seront chaques rôles. serveur web, mysql et fichier. Dans mon cas il s'agit du même serveur.

Il ne reste plus qu'à voir pour le fichier Capfile, mais je le ferais dans un second temps.

Préparation sur le serveur

Il faut penser à préparer la base de donnée qui recevra les informations de notre blog. Il faut donc que la base et les accès soient prêt. C'est la seule manipulation réel à effectuer sur le serveur.

Déploiement

On pourrait faire simple pour déployer notre application et faire ainsi :

$cap deploy:setup
$cap deploy:migrations

La première tâche permettant de préparer le terrain en créant les répertoires de base. La deuxième permettant que :

  • les sources soit déposé sur le serveur distant
  • rake db:migrate soit lancé
  • le serveur est lancé en fastcgi

Mais voilà, rien ne fonctionnera, car il n'y a pas de fichier database.yml sur le serveur car il n'existe pas sur le dépôt subversion. Il va donc falloir en ajouter un sur le serveur.

Création de tâches personnalisées

Voici le fichier CapFile que j'ai ainsi créé.

load 'deploy' if respond_to?(:namespace) # cap2 differentiator
load 'config/deploy'


after 'deploy:symlink', 'deploy:upload_database_config'
after 'deploy:symlink', 'deploy:upload_mongrel_cluster'

namespace :deploy do

  desc 'Upload the config database file in release path'
  task :upload_database_config do
    #Define a database file
    database = {'production' => {
            'database' => 'typo',
            'adapter' => 'postgresql',
            'host' => 'localhost',
            'username' => 'typoblog',
            'password' => 'hinohgai'
        }
    }
    #upload
    put database.to_yaml, "#{current_path}/config/database.yml", :mode => 0444
  end

end

Dans ce fichier j'ai ainsi créé une nouvelle tâche. Cette tâche me permettra de créer un fichier database.yml sur le serveur et ainsi en avoir un spécifique à mon serveur. J'ai aussi défini que cette tâche sera toujours lancer après la tâche deploy:symlink. Tâche qui est réalisé lors de la tâche deploy.

Pour créer la tâche d'envoi sur le serveur du fichier database.yml, j'ai utilisé la méthode "put" de Capistrano. Elle se base sur le système de connection au serveur pour envoyer des fichiers dessus. Avec la variable #{current_path}, j'ai pu définir le chemin vers le dossier contenant les sources utilisés pour lancer l'application.

Pour définir que cette tâche se lance après une autre tâche Capistrano, il suffit tout simplement d'appeler la méthode after.

Ca y est maintenant si vous relancez toute la procédure que je vous ai indiqué précédemment avec les tâches Cap vous aurez votre application qui démarrera avec FastCGI.

Et avec Mongrel_Rails et Nginx

Personnellement, je ne passe pas par FastCGHI, j'utilise mongrel_rails et Nginx. Donc voici les modifications que j'ai réalisé pour que tout passe de la même manière.

J'ai tout d'abord ajouté des tâches Cap:


after 'deploy:symlink', 'deploy:upload_mongrel_cluster'
namespace deploy do
  desc 'Upload the mongrel_cluster.yml in release path'
  task :upload_mongrel_cluster do
    mongrel_conf = {'environment' => 'production',
        'port' => 44000,
        'pid_file' => "#{shared_path}/pids/mongrel.pid",
        'servers' => 4,
        'log_file' => "#{shared_path}/log/mongrel.log"}
    put mongrel_conf.to_yaml, "#{current_path}/config/mongrel_cluster.yml"
  end
  
  desc 'Start mongrel_rails'
  task :start do
    run "cd #{current_path} && mongrel_rails cluster::start"
  end
  
  desc 'Stop mongrel_rails'
  task :stop do
    run "cd #{current_path} && mongrel_rails cluster::stop"
  end
  
  desc 'Restart mongrel_rails'
  task :restart do
    run "cd #{current_path} && mongrel_rails cluster::stop && mongrel_rails cluster::start"
  end
end

Une tâche qui permet d'envoyer mon fichier mongrel_cluster.yml sur le serveur. Une tâche qui démarre le serveur avec mongrel_cluster, une tâche qui arrête le serveur et une tâche qui le redémarre. La tâche d'envoi est bien sûr après la tâche de symlink. Par contre, pour les trois autres tâches, elle remplace en faite les originales qui lancaient FastCGI.

Enfin il ne reste plus que la conf de nginx

     upstream mongrel_blog_dev {
        server 127.0.0.1:44000;
        server 127.0.0.1:44001;
        server 127.0.0.1:44002;
        server 127.0.0.1:44003;
    }

    server {
        listen      80; 
        server_name blog.shingara.fr;
            
            
        location /log_typo {  
            alias /var/rails/typoblog-dev/log/;
            autoindex  on; 
        }   
            
        location / { 
            root /var/rails/typoblog-dev/current/public;
            # needed to forward user's IP address to rails
                proxy_set_header  X-Real-IP  $remote_addr;
            
            # needed for HTTPS
            proxy_set_header  X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header Host $http_host;
            proxy_redirect false;
            proxy_max_temp_file_size 0;

            #redirect blog to Feedburner
            if ($http_user_agent !~ FeedBurner) {
                rewrite  ^/xml/rss20/feed.xml$ http://feeds.feedburner.com/ProgDreamShiny;
                rewrite  ^/xml/rss20/comments/feed.xml$ http://feeds.feedburner.com/ProgDreamShinyComments;
            }
    
            # If the file exists as a static file serve it directly without
            # running all the other rewite tests on it
            if (-f $request_filename) {
                break;
            }
            if (!-f $request_filename){
                proxy_pass  http://mongrel_blog_dev;
            }


        }
    } 

SOAP::LC et Rails

Le développement de SOAP::LC avance doucement (il est 0h54 aussi, c’est Ruby time!) Je me suis, pour le moment, beaucoup amusé avec les WebServices Rails. Ils présentent une particularité gênante. En effet une méthode déclarée hello_world sera rendu, via la WSDL générée par Rails, sous le nom HelloWorld. Ceci implique donc d’avoir un appel sous la forme :

s = SOAP::LC.new( ).wsdl( "http://localhost:3000/sample/wsdl" ).HelloWorld( :from => "Greg" )

L’appel à HelloWorld est bien récupéré via method_missing. La preuve :

>> class Test
>>   def method_missing( id, *args )
>>     puts "Appel de #{id.id2name}(#{args.join( ", " )})"
>>   end
>> end
=> nil
>> t = Test::new
=> #<Test:0×598684>
>> t.HelloWorld( "Greg", 2 )
Appel de HelloWorld(Greg, 2)
=> nil

C’est une bonne nouvelle… Surtout pour moi qui aie toujours pensé qu’il n’était pas possible de déclarer de méthode dont le nom commence par une majuscule :

>> class Test2
>>   def HelloWorld( from )
>>     puts "Hello World par #{from}"
>>   end
>> end
=> nil
>> t2=Test2.new
=> #<Test2:0×58fdf4>
>> t2.HelloWorld( "Greg" )
Hello World par Greg

Ha ben si ! En effet la méthode HelloWorld a bien été référencé au niveau de la classe comme méthode publique d’instance :

>> Test2.public_instance_methods
=> ["inspect", "clone", "method", "public_methods", "instance_variable_defined?", "equal?", "freeze", "to_yaml_style", "methods", "respond_to?", "dup", "to_yaml", "instance_variables", "__id__", "object_id", "eql?", "to_yaml_properties", "require", "id", "singleton_methods", "send", "taint", "frozen?", "instance_variable_get", "require_gem", "__send__", "instance_of?", "taguri", "to_a", "type", "taguri=", "protected_methods", "gem", "instance_eval", "==", "display", "===", "instance_variable_set", "kind_of?", "extend", "to_s", "HelloWorld", "hash", "class", "private_methods", "tainted?", "=~", "untaint", "nil?", "is_a?"]

Mais que se passe-t-il ?
- Mais que se passe-t-il ?
- Mais qu’est-ce qui se passe ?

J’en était resté à la sacro-sainte règle de Ruby in a Nutshell disant que si un identifiant commence par une majuscule, c’est une constante. Puis j’ai relu un peu de documentation et j’ai compris que j’avais tout faux. Et c’est logique en fait : un nom de méthode c’ets bien constant. Cela dit cette permissivité du langage est dangereuse. J’ai donc ajouté une méthode call à la classe SOAP::LC::Request permettant de faire le même appel sous la forme :

s = SOAP::LC.new( ).wsdl( "http://localhost:3000/sample/wsdl" ).call( "HelloWorld", :from => "Greg" )

Au moins cela permet de conserver les conventions. et puis j’ai appris quelque chose…

Moi qui avais placé en priorité basse la relecture approfondie de Programming Ruby, je vais immédiatement la remettre en priorité 1… Enfin si Monsieur est d’accord !

Un nouveau Logger dans Rails Edge

Depuis 2 jours le logger de RubyOnRails dans la version Edge a changé à partir de la révision r7626. En effet avant il y avait une classe logger qui a été remplacé par un BufferLogger.

Ce nouveau Logger est inspiré des travaux de Ezra Zygmuntowicz, qui a réalisé le framework web merb. Ce nouveau logger devrait améliorer les performances de log.

Je trouve que c'est une très bonne chose que la CoreTeam de Rails regarde aussi un peu à coté vers les nombreux framework Web en Ruby pour en prendre le meilleur.