Sunfox

Le journal de Sunny Ripert


Journal

Derniers articles de mon blog

EasouSpider le robot qui ne sait pas parler l’utf8

Il y a 56 minutes de bonne matinée.

Photo de Mathieu mangeant une araignée

Ces derniers jours je recevait une trentaine d’emails par jour m’indiquant qu’une erreur avait éclatée sur cults3d.com. Ces exceptions provenaient toutes d’un robot chinois, EasouSpider, qui parcoure le Web pour remplir son moteur de recherche.

Ce robot ne sait pas parler l’unicode comme tout le monde et envoie dans les formulaires des valeurs mal encodées, ce qui fâche Ruby on Rails. Le problème est surtout que Rails ne traite l’erreur que bien trop tard, lorsqu’on essaie de lire les paramètres de la requête. Et là l’erreur est une incompréhensible ArgumentError :

invalid %-encoding (Q/B0*ÜHܘ0ÅÅ1 0 U GB1 0 U.…

La solution est de créer un middleware Rack qui va déclencher et traiter cette erreur avant que le reste de l’application ne reçoive la requête. Rails est fait de tas de petits modules comme celui-ci qui s’empilent et qui préparent la requête.

Pour ajouter facilement ce middleware à mon application j’ai créé une gemme Ruby, avec un nom particulièrement court. Pour régler ce problème dorénavant, il suffit d’ajouter à son Gemfile :

gem "handle_invalid_percent_encoding_requests"

Depuis, plus aucun message d’erreur. Je dors beaucoup mieux la nuit.

Retrouver les clefs de localisation facilement avec Rails

Il y a 5 jours, 20 heures en début d'après-midi.

Photo de Drapeaux Lego

J’utilise Locale avec Ruby on Rails pour permettre à n’importe qui dans l’équipe de modifier les textes d’un site quelle que soit la langue.

Néanmoins, ce n’est pas évident pour celui qui n’a pas le code sous les yeux de retrouver quel texte correspond à quelle clef.

L’Astuce

Une petite astuce est d’ajouter à son ApplicationController la méthode suivante :

# Print out the keys if you add `?_locale_keys=1` in your params
def t(key, options = {})
  if !Rails.env.production? and request and params[:_locale_keys]
    scope_key_by_partial(key)
  else
    super
  end
end

Cela vous permet d’afficher toutes les clefs d’une page en ajoutant le paramètre _locale_keys à vos URLs, par exemple : http://example.com/?_locale_keys=1.

Voici un exemple sur cults3d.com où chaque texte est remplacé par sa clef :

Le site web Cults3D avec Locale Keys allumé

Sécurité

Il n’y a pas de risque de permettre à tout le monde d’afficher les clefs de localisation. Néanmoins par pudeur et pour éviter que ces pages disgracieuses n’apparaissent dans un moteur de recherche, on teste que l’environnement soit celui de production.

Vous pouvez également remplacer ce test par un test qui vérifie que l’utilisateur est un administrateur, par exemple.

ActionMailer n’aime pas vos URLs (par défaut)

Il y a 1 semaine, 1 jour à l'heure du goûter.

Faire un lien dans un email dans une application Ruby on Rails devrait être aussi simple que de faire un lien dans le reste de l’application, non ?

Photo of a miniature train, by Sunny

Problème

Mais voilà, un simple link_to root_url renvoie une exception car il faut un nom de domaine pour faire une URL. Pour ça il faut configurer un nom de domaine par défaut pour chaque environnement.

En développement un site varie beaucoup selon les configurations et les tests. Par exemple foo.dev, localhost, sunny.local et 192.168.1.42.foo.xip.io, sont des noms de domaines possibles et utiles pour mon application en développement. Le port (80, 3000, 8080) et le protocole (http ou https) sont également des paramètres qui peuvent changer lors des différents tests.

En production votre nom de domaine peut également varier. Par exemple en.cults3d.com et fr.cults3d.com sont deux noms de domaines utilisés par la même application, en même temps. Il est donc impossible de trouver un nom de domaine par défaut à utiliser sur chaque lien.

C’est pénible de devoir spécifier le domaine à chaque fois, c’est source de bugs.

Solution

Pour éviter cette configuration « en dur » il existe une manipulation simple qui consiste à modifier l’URL par défaut à chaque requête.

En ajoutant à son application_controller.rb :

before_filter :make_action_mailer_use_request_host_and_protocol
def make_action_mailer_use_request_host_and_protocol
  ActionMailer::Base.default_url_options[:protocol] = request.protocol
  ActionMailer::Base.default_url_options[:host] = request.host_with_port
end

Sécurité

Attention, cette solution ne vous prémunit pas contre le host injection exploit.

Si votre site déclenche un email (demande de mot de passe par exemple) et qu’un méchant indique comme hôte « evil.com » alors vous allez envoyer des emails ayant des liens en « evil.com ».

Si votre site utilise du cache ces attaques touchent sans doute déjà votre application ! Pour s’en prémunir, ajoutez donc un filtre des noms de domaines autorisés en production.

Thread Safety

Cette solution (corrigez-moi si je me trompe) souffre d’un problème de race condition. Non, ce n’est pas un problème de racisme envers certains noms de domaines qu’elle ne peut pas blairer.

Le problème est plutôt qu’une requête plus lente peut modifier sans le vouloir le domaine d’une autre requête. Une meilleure solution thread-safe existe sans doute. Si vous avez une piste élégante je suis preneur.

Gem ça

Et parce qu’une ligne de code testée dans une librairie dédiée vaut mieux que 2 lignes copié-collées dans votre projet, vous pouvez également ajouter ce code grâce à ma petite gemme :
action_mailer_auto_url_options.

Photo of a miniature train, by Sunny

Liens de partage sans JavaScript vers Facebook, Twitter, Google Plus, Pinterest et email

Il y a 5 mois, 2 semaines le soir, 1 commentaire.

Exemple de boutons de partage de Cults3d.com

Parce que vous voulez inclure des liens de partage sans que ça ne vienne importer 1 Mo de JavaScript sur votre page, voici des liens de partages. Sans balise script. Rien que des liens. Simple.

Ne pas oublier d’URL-encoder chaque paramètre, comme dans les exemples.

Facebook

URL : https://www.facebook.com/sharer/sharer.php?u={u}

Paramètres :

  • u : URL à partager

Exemple : https://www.facebook.com/sharer/sharer.php?u=http%3A%2F%2F…

Facebook dialog

Une boîte de dialogue avec plus d’options que le partage « simple » mais qui a pour inconvénient de devoir créer une application au préalable.

URL : https://www.facebook.com/dialog/feed?app_id={app_id}&link={link}&picture={picture}&name={name}&caption={caption}&description={description}&redirect_uri={redirect_uri}

Paramètres :

  • app_id : numéro unique d’application Facebook
  • link : URL de la page en cours
  • picture : URL d’une image
  • name : nom de la page
  • caption : sous-titre de la page
  • description : description de la page
  • redirect_uri : URL pour revenir vers votre page, celle de la page en cours par exemple

Exemple : https://www.facebook.com/dialog/feed?link=http%3A%2F%2Fsu…

Twitter

URL : http://twitter.com/intent/tweet/?url={url}&text={text}&via={via}

Paramètres :

  • url : URL à partager
  • text : message par défaut du tweet
  • via : compte Twitter pour ajouter un « via @sunfox » par exemple à la fin (optionnel)

Exemple : http://twitter.com/intent/tweet/?url=http%3A%2F%2Fsunfox.…

Google Plus

URL : https://plus.google.com/share?url={url}&hl={hl}

Paramètres :

  • url : URL à partager
  • hl : Code langue pour la page de partage (optionnel)

Exemple : https://plus.google.com/share?url=http%3A%2F%2Fsunfox.org%…

Pinterest

URL : http://pinterest.com/pin/create/button/?url={url}&media={media}&description={description}

Paramètres :

  • url : URL à partager
  • media : URL de l’image à partager
  • description : description par défaut

Exemple : http://pinterest.com/pin/create/button/?url=http%3A%2F%2Fs…

Email

URL : mailto:?subject={subject}&body={body}

Paramètres :

  • subject : Sujet par défaut de l’email
  • body : Message par défaut de l’email

Exemple : mailto:?subject=Liens%20de%20partage%20sans%20JavaScript%…

Favicon dynamique

Il y a 1 an, 1 mois le soir.

Capture d'écran de favicônes toutes identiques
Sites sans favicon : Boo!

Le favicon est un endroit assez délaissé dans une page Web alors que c’est parfois la seule indication visuelle permettant aux utilisateurs de de se retrouver dans ses onglets.

Edith

Sur Edith j’ai choisi de représenter la page en cours directement dans le favicon, en le mettant à jour à chaque caractère tapé.

Capture d'écran montrant la modification en temps réel de la favicon
favicon qui change à la volée sur Edith

JavaScript

Trop facile.

  1. Créer un canvas de 16×16 et colorier ses pixels via JavaScript
  2. Appeler sa méthode toDataURL() pour transformer le canvas en data:image/png;base64,iVBORw0…
  3. Placer dans le DOM dans le <link rel="icon" href="…" /> de la page en cours.

Noter que pour qu’il soit mis à jour instantanément Firefox a besoin qu’on supprime et qu’on recréer la balise link.

Exemple dans le CoffeeScript utilisé sur Edith.

Can I Use?

Fonctionne là où canvas et les datauri fonctionnent, soit IE9+.

Erreurs 404 dynamiques dans Rails 3

Il y a 1 an, 8 mois de bonne matinée.

Utiliser un fichier statique public/404.html dans Rails est très vite limitant. Si on veut utiliser le layout normal de l’application, des informations dynamiques comme des menus, le nom de l’utilisateur courant ou un formulaire de recherche il faut rendre ces erreurs dynamiques.

Pour ça il faut intercepter deux erreurs qui produisent des 404 : les infos nos trouvées dans la base via ActiveRecord::RecordNotFound et les routes qui n’existent pas avec ActionController::RoutingError.

RecordNotFound

Pour que les exceptions levées par ActiveRecord qui retournent une 404 soient gérées de façon dynamique il faut ajouter un gestionnaire d’exception :

# app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
  rescue_from ActiveRecord::RecordNotFound, with: :error_404

  private
    def error_404
      respond_to do |type|
        type.html { render status: 404, template: "errors/404" }
        type.all  { render status: 404, nothing: true }
      end
    end
end

On peut maintenant ajouter tout ce qu'on veut dans views/errors/404.html.erb. Sauvés !

RoutingError

Pas moyen de les intercepter au niveau du contrôleur ces erreurs là. Il faut donc créer une route générique à la main tout en bas du config/routes.rb :

match "*path", to: "errors#not_found"

Et un contrôleur qui va gérer cette nouvelle route :

# app/controllers/errors_controller.rb
class ErrorsController < ApplicationController
  def not_found
    error_404
  end
end

Erreurs 500 ?

N'utilisez pas ça pour les erreurs 500, contentez-vous d'un public/500.html ou votre application et Internet avec risquent d'imploser. Si vous voulez quelquechose de simili-dynamique vous pouvez utiliser un générateur de pages statiques comme snow.

May the fourth be with you

Il y a 3 ans, 2 mois en début d'après-midi, 1 commentaire.

Pour continuer de célébrer le jour de Star Wars voici de gros boutons de sons en HTML5 grâce à bigbuttons :


Et ce week-end pour moi c’est marathon :

DVDS de la sixlogie Star Wars

Quand ne faut-il pas mettre en ligne un site Web ?

Il y a 3 ans, 7 mois en début d'après-midi, 18 commentaires.

Sur votre calendrier, remplacez mise en ligne les vendredi à 19:00 par sodomie
Il y a mieux à faire
les vendredis…

  • Le vendredi
  • Le soir
  • À un pic de fréquentation

Merci.

Calendriers de l’avent pour artisans du Web

Il y a 3 ans, 7 mois à l'heure du goûter, 3 commentaires.

Casier en bois numéro 24
Un mois à 24 jours

Ça y est, décembre est lancé. Et avec les premières neiges on a envie de rester au chaud et de lire des bons articles qui parlent du Web, n’est ce pas ?

4 calendriers avec des perles à découvrir chaque jour de décembre :

  • 24ways remets ça pour la sixième année : des articles de haute qualité qu’on attends toute l’année. Ils contribuent à rendre l’hiver moins dur.
  • HTML5 Advent : des démos HTML5 pour en avoir plein les yeux.
  • Adfont Calendar : mateurs de typographie, sous chaque case se cache une police d’écriture proposée par FontDec.k
  • Performance Calendar : et oui, même les performances Web ont leur calendrier.

Typographie, HTML5 et performances : les sujets chaud du Web de cette année sont là pour se tenir au chaud cet hiver jusqu’à Noël.

Raccourcis clavier pour changer d’onglet dans TextMate

Il y a 3 ans, 8 mois en fin de matinée.

Logo TextMate

La mise à jour 1.5.10 de TextMate change les raccourcis pour aller à l’onglet précédent et suivant. À la place de ⌥⌘← et ⌥⌘→. Ils sont maintenant ⌘⇧⌥5 and ⌘⇧⌥° sur un clavier français.

La raison pour ce changement est que c’est la façon de changer d’onglet dans Safari. Je sais pas vous mais je préfère les raccourcis précédents et ceux de Firefox…

Changez les raccourcis en allant dans Préférences Système, Clavier, Raccourcis clavier, Raccourcis d’applications et ajoutez vos raccourcis. Choisissez l’application Textmate et entrez les titres de menu « Next File Tab » et « Previous File Tab ».

Et pour couronner le tout, désindenter un bloc de code avec ⌥⇧↦ ne fonctionne plus pour les claviers français à cause d’un bug. Pour le réparer avant d’attendre la prochaine mise à jour ajouter "~$\t" = "shiftLeft:"; dans /Applications/TextMate.app/Contents/Resources/KeyBindings.dict

Après cette mise à jour les développeurs de Textmate se sont « rendus compte que tout le monde n’utilisait pas un clavier US » et ont donc remis les raccourci précédents ainsi que réparé le second bug d’indentation. Sigh.


:D Sunny Ripert

est un développeur web vivant à Paris.

CV, me contacter


Textes et contenus sous licence Creative Commons.
Site crée par mes soins et propulsé par WordPress.