RailsEngines 2.3 (suite)

La solution dans l’article précédent ne me plaisait pas, alors j’ai fais ma solution … bon j’avoue j’ai pas cherché s’il existe déjà une solution prête à l’emploi.

Personnellement, je préfère que config. reload_plugins soit à false. Mais je ne veux pas mettre dans mes plugins un bout de code qui dépend plus de l’application et du contexte (development/production) que du plugin lui même.

Je pourrais mettre reload_plugin à true, oui mais je n’ai pas forcément envie de recharger toute la masse de plugin à chaque requête.

Dans un premier temps, on va ajouter une directive de configuration à savoir reloadable_plugins, et on va la traiter au moment du chargement des plugins. Voici le code :

Rails::Configuration.class_eval do
  attr_accessor :reloadable_plugins

  def initialize_with_reloadable_plugins
    initialize_without_reloadable_plugins
    self.reloadable_plugins = default_reloadable_plugins
  end

  def default_reloadable_plugins
    []
  end

  alias_method_chain :initialize, :reloadable_plugins
end

Rails::Plugin::Loader.class_eval do
  def add_plugin_load_paths_with_reloadable_plugins
    load_path = add_plugin_load_paths_without_reloadable_plugins
    plugins.each do |plugin|
      if configuration.reloadable_plugins.include?(plugin.name.to_sym)
        ActiveSupport::Dependencies.load_once_paths -= plugin.load_paths
      end
    end
    load_path
  end
  alias_method_chain :add_plugin_load_paths, :reloadable_plugins
end

qu’on va mettre dans lib/configuration_reloadable_plugins.rb par exemple.

Ensuite ajouter dans le fichier config/environnement.rb, juste après le boot.rb (l’ordre est important)

  ...
require File.join(File.dirname(__FILE__), 'boot')
require File.join(File.dirname(__FILE__), '../vendor/plugins/engines/boot')
require 'lib/configuration_reloadable_plugins'
  ...


Et toujours dans <strong>config/environnement.rb</strong> on indique les plugins à recharger :

...
Rails::Initializer.run do |config|
  config.reloadable_plugins = [ :foo, :bar ]
  config.reload_plugins = false
  ...
end
...

Et pour vérifier que c’est bon :

$ script/console
>> ActiveSupport::Dependencies.load_once_paths.select{ |p| p =~ /foo/ }
=> []
Publié dans Rails, Web Dev | Commentaires fermés sur RailsEngines 2.3 (suite)

RailsEngines 2.3

Les problèmes avec rails 2.3 continuent.

J’utilise depuis longtemps le plugin rails-engines qui permet de transformer une application en un plugin.

Et nouveauté de la version 2.3 de rails, RailsEngine y a été incorporé. Mais comme certains plugins qui ont été incorporé (has_finder, globalize, …) à chaque fois ce n’est pas complètement, bref il faut quand compléter les fonctionnalités en installant le plugin engine expurgé du code commun avec rails.

Mais bon ça bug encore, on obtient un :

A copy of X has been removed from the module tree but is still active!

ou bien un

can’t dup NilClass

uniquement en mode dev … grrr

Alors heureusement, d’autres sont passé par là et certains ont déjà résolu le problème en ajoutant un unloadable dans la classe concernée

class Toto
  unloadable
end

That’s it !

UPDATE :

En lisant les commentaires en fait ce n’est pas la bonne solution. En fait il faut lire la doc, enfin la doc dans le code 🙂 dans railties/lib/initializer.rb :

    # Enables or disables plugin reloading.  You can get around this setting per plugin.
    # If reload_plugins? is false, add this to your plugin's init.rb
    # to make it reloadable:
    #
    #   ActiveSupport::Dependencies.load_once_paths.delete lib_path
    #
    # If reload_plugins? is true, add this to your plugin's init.rb
    # to only load it once:
    #
    #   ActiveSupport::Dependencies.load_once_paths << lib_path
    #

C’est clair ! soit d’office vous ne voulez pas du tout recharger les plugins (reload_plugin à false), et seulement certains (ceux que vous développez par exemple) alors il faut mettre dans le init.rb :

# config/environments/development.rb
config.reload_plugins = false

# plugin's init.rb : remove plugin from unloadable list
ActiveSupport::Dependencies.load_once_paths -= load_paths

soit l’inverse vous voulez que tous les modules soient rechargeable (reload_plugins à true), sauf certains :

# config/environments/development.rb
config.reload_plugins = true

# plugin's init.rb : add plugin in unloadable list
ActiveSupport::Dependencies.load_once_paths += load_paths
Publié dans Non classé | Commentaires fermés sur RailsEngines 2.3

Divers problèmes avec Rails 2.2+

Ah les joies de se mettre à jour et son code à l’occasion … Oui depuis longtemps je trainais avec rails 1.2.6 (oui je sais ça commence à dater mais j’ai mes raisons). Il me tardait donc de pouvoir utiliser les nouvelles versions de rails avec son lots d’améliorations.

Bon tout d’abord grosse surprise un bug uniquement présent en development, et pour cause il concerne le système de déchargement/rechargement du code de l’application.

ça donne soit un

stack level too deep

ou alors un pénible

vendor/rails/activerecord/lib/active_record/attribute_methods.rb:142:in `create_time_zone_conversion_attribute?'
vendor/rails/activerecord/lib/active_record/attribute_methods.rb:75:in `define_attribute_methods'
vendor/rails/activerecord/lib/active_record/attribute_methods.rb:71:in `each'
vendor/rails/activerecord/lib/active_record/attribute_methods.rb:71:in `define_attribute_methods'
vendor/rails/activerecord/lib/active_record/attribute_methods.rb:242:in `method_missing'

Le problème semble être valable depuis rails 2.2 et toujours pas corrigé. Il semble que ce ne soit pas une priorité car le problème se pose uniquement en mode development.

Donc la solution est de patcher rails en attendant. Patch qui se trouve dans le ticket chez lighthouseapp :

if ENV['RAILS_ENV'] != 'production'
  class ActiveRecord::Base
    class_eval do
      def self.reset_subclasses
        nonreloadables = []
        subclasses.each do |klass|
          unless ActiveSupport::Dependencies.autoloaded? klass
            nonreloadables << klass
            next
          end
          klass.instance_variables.each { |var| klass.send(:remove_instance_variable, var) }
          klass.instance_methods(false).each { |m| klass.send(:undef_method, m) unless m =~ /^id(=$|\?$|$)/ }

        end
        @@subclasses = {}
        nonreloadables.each { |klass| (@@subclasses[klass.superclass] ||= []) << klass }
      end
    end
  end
end

Voilà et maintenant ça roule on peut développer en paix.

Publié dans Rails, Web Dev | Commentaires fermés sur Divers problèmes avec Rails 2.2+

Synergy client & Mac OS X Leopard

Bon la migration de mon mac-mini sous leopard s’est bien déroulée. Reste une chose : Synergy.

Dans leur doc, les scripts de démarage automatique sont valables pour mac os x10.4. Du coup le client synergy ne se lance plus à l’affichage de l’écran de connexion, un peu génant pour accéder à mon mac-mini depuis mon PC.

Pas de panique, d’après Jan Varwig et la doc d’Apple les StartupItems sont depracated et les scripts sont gérés par lauchnd. Donc nouvelle configuration inspirée de Jan Varwig (sauf que lui c’est pour serveur), :

/Library/LaunchAgents/net.sourceforge.synergy2.plist :

<plist version="1.0">
    <dict>
      <key>Label</key>
      <string>net.sourceforge.syngery2</string>
      <key>LimitLoadToSessionType</key>
      <string>LoginWindow</string>
      <key>OnDemand</key>
      <false>
      <key>ProgramArguments</key>
      <array>
          <string>/usr/local/bin/synergyc</string>
          <string>-1</string>
          <string>-f</string>
          <string>192.168.0.4</string>
        </array>
        <key>RunAtLoad</key>
        <true>
        <key>ServiceDescription</key>
        <string>Synergy Client</string>
      </true>
    </false>
</dict></plist>

Dans les logs, apparaissait :

Untrusted apps are not allowed to connect to or launch Window Server before login.

ok ok la doc d’Apple le dit : il faut le bon niveau de permission : d’où LimitLoadToSessionType affecté à LoginWindow.

donc on a bien l’écran de connexion, mais, car il y a un mais, dans l’espace utilisateur synergy n’a plus la permission. Donc comme indiqué dans la doc j’essaie le array pour spécifier plusieurs niveaux :

<plist version="1.0">
  ...
  <key>LimitLoadToSessionType</key>
   <array>
    <string>LoginWindow</string>
    <string>Background</string>
  </array>
  ...
</plist>

Mais rien n’y fait. La solution la moins propre : créer un 2ième fichier.

/Library/LaunchAgents/net.sourceforge.synergy2-usermode.plist :

 <plist version="1.0">
    <dict>
      <key>Label</key>
      <string>net.sourceforge.syngery2-usermode</string>
      <key>LimitLoadToSessionType</key>
      <string>Background</string>
      <key>OnDemand</key>
      <false>
      <key>ProgramArguments</key>
      <array>
          <string>/usr/local/bin/synergyc</string>
          <string>-1</string>
          <string>-f</string>
          <string>192.168.0.4</string>
        </array>
        <key>RunAtLoad</key>
        <true>
        <key>ServiceDescription</key>
        <string>Synergy Client</string>
      </true>
    </false>
</dict></plist>

And it works ! bon à voir s’il n’y a pas une meilleur solution, car le synergyc qui possède les droits lors de l’écran de connexion continue à s’excuter et se fait refouler lorsqu’on est connecté .. bah … ça fait tourner les log .. hum …

Publié dans Configuration | Marqué avec , | Commentaires fermés sur Synergy client & Mac OS X Leopard

Frameworks Ajax/JS & Google

Une chose à laquelle je pense depuis quelque temps pour mes dev javascript : qu’un acteur majeur du dev et plus particulièrement du dev web prenne l’initiative d’héberger les principales librairies Javascript Protoype, Jquery, Mootools, … Je l’attendais de la part de Yahoo, c’est venu de Google.

Ces librairies sont maintenant énormément utilisées pour animer les pages web, avec plein de widget réalisés à droite à gauche, et donc on retrouve dans le cache des navigateurs plusieurs la même version de la même librairie. Dommage. Perte de place et de bande passante (ok très minime), et surtout perte de temps (téléchargement).

Ensuite l’étape suivante serait la normalisation des ces interfaces de programmation, pour disposer d’appels communs (et surtout ne pas avoir 5 versions du même widget genre lightbox) et de les intégrer soit comme plugin, soit comme dans le coeur du moteur javascript … enfin je doute qu’ on en arrive là … cependant quand j’entends Mozilla annoncer qu’ils vont porter leur attention sur leur moteur javascript …

Et pour les plus curieux un petit tuto … pour l’utilisation avec RubyOnRails of course

Publié dans Web Dev | Commentaires fermés sur Frameworks Ajax/JS & Google