Générer une font avec des icônes en rails

Une « fonte-icône » est une police qui utilise des glyphes représentant des icônes vectorielles. Très pratique, car on peut facilement changer la couleur, la taille en css. En plus de leur flexibilité, les polices d’icônes permettent un gain de performance puisqu’il suffit de charger un fichier de police pour avoir accès à beaucoup de caractères.

Nous allons voir comment mettre en œuvre une police d’icônes personnalisée avec Rails.

Nous allons utiliser la gem ‘fontcustom’ de Rails. Cette gem nécessite Ruby 1.9.2+ et FontForge.

1- Installation de fontforge

Si vous avez besoin de Xquartz lors de l’installation de fontforge, vous pouvez le télécharger ici.

2- Ajouter la gem ‘fontcustom’ à votre Gemfile (puis faire un bundle update)

3- Ajouter une tâche rake en créant un fichier /lib/tasks/icons.rake

4- Créer un fichier fontcustom.yml dans config avec les options suivantes :

On va mettre nos icônes svg dans le dossier app/assets/icons. Les fichiers pour la police compilés se mettront dans le dossier app/assets/fonts.

5- Faire la commande suivante pour compiler les icônes :

En regardant votre arborescence, vous verrez que des fichiers ont été créés :

6- Importer le fichier _icons.scss dans votre application.scss

Après l’installation et la compilation, rien de plus simple pour l’utilisation dans vos vues :

Pour connaître les noms des classes, il faut aller voir le fichier _icons.scss qui contient ces noms.

Si on ajoute ou supprime une icône dans le dossier, il suffit de recompiler avec la commande suivante :

Sources :

Rails : bien préparer sa BDD pour stocker des « Emoji »

Dans cet article début d’approche sur la problématique pour stocker des « Emoji » en BDD. Effectivement on pense que cela ne sert à rien de les utiliser mais le problème avec ces icônes est qu’ils sont disponibles nativement sur la plupart des claviers mobiles désormais, et donc … peuvent se retrouver dans le moteur de n’importe quel formulaire de votre site. Si vous ne gérez pas ce cas particulier, cela peut engendrer des erreurs.

La fausse piste « serialize »

Certains optent pour la solution un peu brute et pas forcément de bonne augure de spécifier dans un model que tel champ est à « serializer » (je suis moi aussi un peu tombé dedans ^^)

Alors effectivement ça « marche » mais allez jeter un oeil en BDD et cela vous enchantera moins (d’autant plus qu’il sera difficile de requêter sur ce genre de données avec des conditions par exemple).
 
Serialize sert avant tout à nous aider à sauvegarder des données en tant qu’objet (au passage, en YAML). Passons donc cette alternative.

Un problème d’encodage avant tout

Le problème avec les encodages classiques en utf8 est que ce dernier utilise au maximum 3 octets par caractère. Les Emoji en nécessitent 4 ! Depuis la version MySQL 5.5.3, l’encodage utf8mb4 permet de manipuler tous les caractères unicodes de 4 octets (comprenant donc nos fameux emojis).

L’avantage est qu’il suffit de configurer notre BDD pour lui dire d’utiliser cet encodage précis. Attention toutefois, il vous faut MySQL >= 5.5.3.

Création et configuration de notre projet Rails

Nous allons dans un premier temps créer un projet Rails et le configurer pour mettre par défaut ce nouvel encodage (nous reviendrons dans un autre article sur la manière de procéder pour mettre à jour des colonnes sans perte de données sur un projet existant).

Comme vous pouvez le constater, on précise ici une limite de 191 pour nos types « varchar ». Habituellement on est sur du 255. En utf8 la taille maximum de l’index est de 767 octets, donc on a 767 / 3 octets par caractère = 255 caractères max pour l’utf8 habituel, et pour l’utf8mb4 on obtient 767 / 4 octets par caractère = 191 caractères max.

Lancez votre projet et rendez-vous sur la page de création d’un article, placez-y un titre et du texte avec un emoji dans chaque champ. Vous n’aurez pas de problème lors de la sauvegarde en BDD 😉

Sources : Documentation MySQL utf8mb4

Rails : Problème d’index trop long sur une migration ?

En voulant créer une table de liaison entre deux autres dans un projet, nous avons rencontré un problème avec les index. Petit récap :

En faisant un petit rake db:migrate qui va bien, on obtenait ceci :

Le problème vient du fait qu’en voulant respecter la convention Rails sur le bon nomage de notre table de liaison on se retrouve avec un index ayant un nom très long de 68 caractères. Or la limite autorisé par notre BDD est de 64. Pour contrer cela, on peut forcer un nom d’index différent en le précisant à la fin de notre migration comme ci-dessous :

Et voilà !

#Barcamp : quoi de neuf sur Rails 5 avant sa sortie finale ?

Notre équipe développe sur Ruby on Rails depuis maintenant de nombreuses années, nous surveillons donc en permanence l’évolution du Framework. La version 5 approche à grands pas, ou en sommes-nous ?

  • Actuellement (mars 2016) en Beta 3 (mais déjà mis en production sur le projet Basecamp 3)
  • Ruby 2.2+ exclusivement
  • Nouveauté (« the big one ») : Action Cable qui permet de faire du temps réel en natif sur un projet. Ils ont profité de cette nouveauté pour ajouter un système permettant de réutiliser une vue en dehors de son controller (pour les websockets). Vincent a déjà présenté cette nouveauté hier dans un article.
  • API Mode : ils ont encore améliorer la possibilité de faire d’un projet rails une API en créant le mode –api lors de la création d’un projet. Ex : rails new mon_api –api va nous générer une structure de projet simplifiée nous permettant de ne travailler qu’avec du JSON, et non du HTML. D’autres améliorations seront apportées mais il semble qu’ils se sont beaucoup penchés sur la partie JSON pour le moment.
  • Commandes rails vs. rake : certaines commandes étaient placées dans bin/rails et d’autres dans bin/rake.  Dans Rails 5, tout a été rassemblé dans bin/rails du coup il faudra s’habituer à faire un rails db:migrate au lieu de rake db:migrate (certaines commandes seront encore disponibles sous rake mais autant prendre l’habitude dès le début).
  • Test runner : lorsque l’on exécute des tests les failures sont désormais affichées en live, pas besoin d’attendre la fin des tests pour repérer d’où vient le problème.
  • Turbolinks 3 : Turbolinks permet de rafraichir des pages plus rapidement en rechargeant le contenu du body d’une page depuis le serveur au lieu de rafraichir la page et de recompiler à chaque fois le js et le CSS. Au lieu de faire comme l’ajax il remplace tout le body par défaut mais il est possible de spécifier quel élément rafraichir. Cela semble utile pour les sites one-pages. Les avis sont vraiment partagés, certains trouvent cela révolutionnaire d’autres s’en passeront comme sur Rails 4.
  • « Et ça sort quand ? » : aucune date n’a été donnée (trouvée ?) donc on ne sait pas. Mais la communauté est très active et les betas qui sortent montrent qu’il y a énormément de contributeurs qui sont actifs sur le sujet.

Pour clôturer cette petite présentation, j’ai installé un Rails 5 (beta) et développé une petite démo en utilisant ActionCable, le tout en moins de 2 heures (ce qui s’annonce très prometteur, nous y reviendrons probablement sur d’autres billets). Vivement la suite !

#Barcamp : Les Assets Ruby on Rails

Asset Pipeline

L’asset pipeline est un outil qui concatène et minifie (compresse) les ressources CSS et JavaScript. Il nous permet aussi d’écrire nos assets avec d’autres langages ou pré-processeurs comme ERB, Sass ou CoffeeScript. En Ruby on Rails, Il est gérer par la gem sprockets-rails, dont le code a été extrait du cœur du framework dans la version 4.

Les assets sont placés dans le répertoire /app/assets. En production, Rails les précompile et les place dans le répertoire /public/assets.

Inclusion des assets

Lorsqu’on génère un contrôleur (ou un scaffold), rails crée automatiquement des fichiers CSS et JS (ou SCSS et Coffee, si les gems correspondantes sont installées). Par exemple, si on crée le contrôleur elements_controller.rb, les fichiers app/assets/stylesheets/elements.scss et app/assets/javascripts/elements.js vont être créés. Ces fichiers sont inclus dans l’application si l’instruction require tree . est présente dans le fichier application.css.

Mais il est également possible d’inclure seulement les fichiers d’assets spécifiques au contrôleur courant en utilisant les lignes suivantes dans le layout :

Organisation des assets

Les répertoires images, javascripts et stylesheets présents dans app/assets, lib/assets et vendor/assets sont gérés par l’assets pipeline. Il est possible d’ajouter des chemins au pipeline dans le fichier config/application.rb. Par exemple :

Manifest

Les fichiers app/assets/stylesheets/application.css et app/assets/javascript/application.js sont des fichiers manifest qui déterminent quelles assets inclure et servir.

Un fichier manifest ressemble à ceci :

Ici, les fichiers jquery.js et jquery_ujs présents dans un des chemins connus par l’asset pipeline sont inclus. La directive require_tree inclus tous les fichiers présents dans le répertoire courant, alors que require_directory inclus les fichiers présents dans le répertoire spécifié.

Pour exclure un fichier présent dans le répertoire courant après un require_tree, il faut utiliser la directive stub.

À noter que les assets sont inclus dans l’ordre spécifié par le manifest. Par contre, il n’y a pas d’ordre spécifique d’inclusion des assets avec le require_tree ou le require_directory. Il faut donc inclure un fichier avant le require_tree si on veut qu’il soit inclus le premier (il ne sera alors pas inclus une seconde fois).

On peut utiliser autant de fichiers manifest que le souhaite. Pour cela, il faut les ajouter à la précompilation dans le fichier /config/initializers/assets.rb :

Helpers d’assets

Il existe plusieurs helpers qui nous permettent d’inclure les assets :

Sources :

Lectures complémentaires :

 

#Barcamp : L’organisation du code dans Rails

Concerns & modules

Dans Rails il existe des répertoires « concerns » dans les modèles et les controllers. Cela va nous permettre de mieux organiser notre code et d’éviter parfois de dupliquer des lignes. Un concern est un « module » et non une classe, il faut s’en servir et regrouper cela par fonctionnalité, et non comme un simple endroit ou stocker des méthodes diverses et variées. Petit zoom sur ces deux termes :

  • Concerns : quand nos modèles partagent une information (un sujet/thème/fonctionnalité) on place cette information dans un concern. Ex: sur un site, des commentaires peuvent être ajoutés/affichés depuis un article, un produit, et cela concerne (oO) aussi la table utilisateur. On va donc créer un module commentaire dans un concerns. Si dans mon model utilisateur, commentaire, produit, article je fais un « validates mon_champ » ou un « has_many mon_truc » je vais placer tout cela également au même endroit dans un concern.
  • Module : Un module fournit des méthodes qui seront utilisées dans plusieurs classes. C’est différent d’une classe : une classe est un objet, un module est une fonction. On peut instancier une classe, pas un module. On peut faire de l’héritage avec une classe, pas avec un module. Un module peut s’inclure dans un autre module ou dans une classe (include MonConcern en haut du fichier)

Les classes abstraites

Du fait que les modèles héritent d’Active Record, mettre en commun des méthodes d’instance entre deux modèles via une classe abstraite nécessite une configuration dans cette dernière.

On indiquera ainsi : self.abstract_class = true. La classe abstraire hérite d’Active Record : class Produit < ActiveRecord::Base. Les autres classes héritent de la classe abstraite.

Ruby ne supporte pas l’héritage multiple, ce qui peut être problématique. Il existe d’autres solutions pour pallier ce problème, tels que les mixins ou les interfaces.

Rails supporte les relations polymorphiques entre modèles Active Record : c’est le Multiple Table Inheritance.

Équilibre entre vues, partials et helpers

On hésite souvent sur la manière de suivre le pattern MVC en arrivant dans les vues. Les index sont particulièrement l’endroit d’opérer des boucles contenant des requêtes, des conditions, qui ne semble pas pouvoir être réalisées ailleurs.

Les partials et les helpers peuvent servir le même but : factoriser du code dans une vue devenant trop longue ou nécessitant de la récursivité. La différence réside dans le langage dominant de l’un et l’autre :

  • Les partials sont l’endroit tout indiqué pour écrire du HTML. On peut y utiliser quelques conditions et boucles tant que l’objectif servi est de la présentation.
  • Les helpers sont l’endroit désigné pour écrire du ruby. Une fonction doit enfermer de la logique, comme des conditions, des requêtes, et retourner quelque chose qui est inséré dans la vue. Ce n’est pas l’endroit pour construire des éléments du DOM.

Deux sites entrent plus dans le détails, en français et en anglais.

Rails : association & inverse sur un même objet

Nous venons de rencontrer un cas bien particulier (mais pas tant que ça finalement) lors d’un récent développement. Nous avons un objet Produit et nous souhaitons l’associer à un autre produit en vue de répondre au besoin « tel produit est associé à tel produit« .

Jusque ici rien de compliqué. Cependant si l’on rentre un peu plus dans le détail et dans la demande qui nous a été formulée, on se rend compte que l’on a finalement besoin de : « Si j’associe mon produit A au produit B, est-ce que le produit B sera automatiquement associé au produit A ?« . La réponse est non, mais nous allons faire en sorte d’y répondre favorablement.

On crée nos tables produits et produit_associes, puis les modèles qui vont avec :

Si l’on teste déjà cela dans une console (avec des données en base) on obtient ceci :

On remarque donc que nous avons pu associer le produit 2 à notre produit 1, que lorsque nous interrogeons p1.associes il nous retourne bien le produit 2. Dans le cas inverse (p2.associes) le tableau est vide, et nous voulons qu’automatiquement p2 match avec p1 sur cette association inverse. Pour cela nous allons modifier notre modèle produit_associe et lui indiquer d’enregistrer (ou supprimer) l’inverse de l’association créée/détruite :

Si l’on reteste en console on obtient désormais :

Dès lors que l’on associe un produit à un autre, on crée l’association inverse automatiquement. L’ajout de « dependent: :destroy » dans le modèle Produit nous permettra de faire la même chose lorsque l’on supprimera l’une des deux associations existantes.

Sources : http://collectiveidea.com/blog/archives/2015/07/30/bi-directional-and-self-referential-associations-in-rails/

Rails : la gem did_you_mean pour vous servir !

Aujourd’hui un petit article pour vous présenter rapidement une Gem très sympathique : « Did you mean ». Il est fréquent pour un développeur de faire des fautes de frappes, on peut parfois se tromper d’un caractère s’en forcément s’en rendre compte et perdre du temps … ça se termine souvent par « pfff la loose, j’ai mal écrit ma méthode » ou autre (à remplacer par la phrase qui vous convient ^^).

C’est là que la Gem did_you_mean peut entrer en action :

Un petit bundle install et c’est tout ! Le résultat ? Voici un petit exemple (réalisé pour la démo, donc un peu gros je vous l’accorde) :

Cela me génère une erreur (car j’ai mal tapé ActiveRecord dans mon cas) et did_you_mean entre en jeu et me propose la bonne syntaxe :

screen_didyoumean

Et voilà, cela fonctionne dans beaucoup de cas je vous laisse découvrir plus en détails la Gem sur la page Github github.com/yuki24/did_you_mean.

Rails : utilisation de REGEXP

Petite mise en situation : nous sommes sur un vieux projet Rails 3 avec une table ayant une colonne (genre) qui stocke une ou plusieurs valeurs séparées par une virgule (la conception est faite de la sorte, on va dire que c’est un cas particulier).

On peut donc retrouver certaines lignes de notre table avec pour valeurs des choses comme « mot1 » ou « mot1,mot2,mot3 » ou encore « mot1,mot3 » etc..

Partons du principe que l’on a un formulaire avec des cases à cocher mot1, mot2, mot3, mot4, mot5 et que l’on souhaite récupérer toutes les lignes de notre table contenant dans la colonne « genre » les cases cochées.

La solution en SQL serait de faire un « LIKE » en séparant toutes les possibilités avec un « OR ». Sauf que dans notre cas on ne sait pas combien de OR on devra faire, c’est dynamique.

Pour éviter de faire une boucle sur les cases cochées, nous nous sommes penchés sur l’opérateur « REGEXP » qui va nous permettre de faire notre recherche sur un tableau de valeurs (contenant une ou plusieurs valeurs en fonction du nombre de cases cochées dans le form).

Cela nous permet de matcher les lignes comprenant l’une des valeurs de notre hash. Libre à vous d’utiliser la bonne expression régulière en fonction de votre besoin.

Rails : Utiliser will_paginate sur un tableau d’objets

Il vous est peut-être arrivé, en utilisant la gem will_paginate, de rencontrer l’erreur suivante :

undefined method `paginate' for #<Array:0x00000104f362b8>

En effet, will_paginate ne s’applique qu’aux collections ActiveRecord::Relation par défaut. Pour pouvoir l’utiliser sur les tableaux, il suffit d’ajouter l’inclusion suivante (dans le contrôleur, ou dans un fichier config/initializers/will_paginate.rb par exemple)  :

N’oubliez pas de redémarrer votre serveur.

Problème résolu !

Source : http://stackoverflow.com/questions/4352895/ruby-on-rails-will-paginate-an-array