Il arrive régulièrement, sur divers projets, que l’on ait besoin de gérer des tags. Que ce soit pour un catalogue d’articles, son blog personnel ou une plateforme de photoblog, ceux-ci peuvent toujours avoir une utilité.
Le plugin rails « act_as_taggable_on_steroids » permet cela de manière on ne peut plus simple.
Mise en application et exemple (cet article est une traduction plus ou moins libre de la documentation du plugin).

Pour commencer, installons le plugin.

script/plugin install http://svn.viney.net.nz/things/rails/plugins/acts_as_taggable_on_steroids

Puis mettons en place les deux bases nécessaires à l’exécution de notre plugin : tags et taggings.

script/generate acts_as_taggable_migration

Et créons les.

rake db:migrate

Ne créez pas de modèle pour votre base « tags ». Celui-ci est déjà présent dans le plugin et est nécessaire à son bon fonctionnement.

Notez qu’il est nécessaire de redémarrer le serveur (même dans un environnement de développement tel que aptana) pour que le plugin soit réellement installé.
Voila, le plugin est en place. Maintenans, ajoutons des tags à notre modèle « Post ».

class Post < ActiveRecord::Base
acts_as_taggable

end

Ajouter « act_as_taggable » permet de déclarer le modèle comme ayant un tag. Les bases utilisées seront toujours tags et taggings. Même si vous avez plusieurs modèles utilisant des tags (mais les tags ne sont pas mélangés).
Vous pouvez maintenant mettre à jour la liste des tags pour un uplet :

p = Post.find(params[:id])

p.tag_list = ‘kazhar,blog,ruby,rails’

Plusieurs autres fonctionnalités sont également disponibles, pour ajouter ou supprimer manuellement des tags.
Ajouter un (ou plusieurs) tag(s) :

p.tag_list.add('développement', 'rubyonrails')

Supprimer un ou plusieurs tags :

p.tag_list.remove('rubyonrails')

Obtenir les données des tags

Après avoir définir nos tags, on peut bien evidemment en récupérer le contenu. La méthode find_tagged_with permet d’obtenir tous les billets possédant un ou plusieurs tags.

Post.find_tagged_with('kazhar')

Par défaut,si un élément contient au moins un des tags présents dans la liste. Si vous désirez chercher tous les tags présents dans la liste, il faut ajouter l’option match_all.

Post.find_tagged_with('kazhar,ruby', :match_all => true)

Nuage de tags

L’intéret principal d’avoir des tags est de créer un nuage. Bien evidemment, ce plugin permet cela de manière très aisée. Commençons, dans notre contrôleur, par récupérer la liste des tags pour tous nos billets.

@tags = Post.tag_counts

Puis dans notre vue, nous affichons tous nos tags en leur attribuant une classe spécifique en fonction de leur taille.

<% tag_cloud @tags, %w(tag1 tag2 tag3 tag4) do |tag, css_class| %>
<%= link_to tag.name, { :action => :tag, :id => tag.name }, :class => css_class %>
<% end %>

Et nous définissons ces tailles dans notre feuille de style.

.tag1 { font-size: 1.0em; }
.tag2 { font-size: 1.2em; }
.tag3 { font-size: 1.4em; }
.tag4 { font-size: 1.6em; }

Et voila, vous avez maintenant un beau nuage de tags ! Le tout en moins d’une heure si tout s’est passé correctement ! :-)

Quelques petites options supplémentaires :

  • Délimiteur : par défaut, les divers tags sont séparés par une virgule (« , »). Mais il est possible de modifier cela avec TagList.delimiter.
    Définissez le dans environnment.rb. Par exemple : TagList.delimiter = ‘.’
  • Suppression des tags inutilisés : par défaut, le plugin ne supprime pas les tags inutilisés. Cependant, il est possible de modifier cela.
    Toujours dans environnment.rb : TagList.unused = true

Supposons le cas d’un site multilingue, qu’il soit architecturé en sous-répertoires ou sous-domaines.
Lorsque vous arrivez sur la base du site (/ ou www), aucune langue n’est définie. Et vous n’avez aucun contenu à afficher.

Il vous faut donc rediriger l’utilisateur vers une autre page qui correspondra à la langue qu’il est le plus susceptible de désirer.
De nombreux sites, corporate y compris, ne s’embêtent pas et proposent simplement une liste de liens vers les diverses langues.

Ceci est à ne surtout pas faire. Cela avait notemment été dit par Elie Sloïm lors des ateliers Paris Web de l’an dernier (d’ailleurs les dates du prochain Paris Web ont été divulguées !)
Suite à une discussion sur le forum seosphere, je publie ici le code que j’utilise sur RefStats pour détecter la langue préférée de l’utilisateur et le rediriger vers le répertoire approprié. Si vous utilisez des sous-domaines, il suffit de déplacer /fr en fr.
Note : le code ici est adapté afin d’enleve la dépendance à CakePHP.

$langs = array('en' => array('title' => 'English', 'visible' => 0) , 'fr' => array('title' => 'Français', 'visible' => 1));
$defaultLang = 'fr';

$_d = split (‘[,;]‘, $_SERVER['HTTP_ACCEPT_LANGUAGE']);
$f = false;
$selected = null;
foreach($_d as $l) {
if (isset($langs[$l]) && $langs[$l]['visible'] == 1 && $f == false) {
$selected = $l;
$f = true;
}
}
if ($f == false) $selected = $defaultLang;

header(‘location: /’.selected, true, 301);
die();

Quelques explications.
Ce code doit être placé sur votre page /index.php. la variable $langs contient toutes les langues disponibles. Ici, j’ai mis un élément ‘nom’ car dans le cas de RefStats, cette variable sert également à mettre le nom de la langue en haut de page.
Le ‘visible’ n’est pas non plus utile ici.

Nous regardons donc le contenu de HTTP_ACCEPT_LANGUAGE, qui contient les langues préférées de l’utilisateur, par ordre de préférence.
On prends la première que l’on connaisse. Si il n’y en a aucune, on prends la valeur de $defaultLang.
Et on redirige vers le répertoire de la langue.

Il est totalement inutile de placer la langue dans la session. En effet, vu que vous serez ensuite dans le répertoire de la langue, vous aurez toujours l’information de celle-ci.
Et si vous placez l’information en session et forcez toujours cette langue, vous courrez le risque d’avoir un utilisateur qui aurait une configuration inappropriée (cela peut arriver lors de vacances à l’étranger par exemple) qui ne pourra pas voir votre site dans sa langue maternelle.

Pour finir, voici le code non modifié pour ceux qui utiliseraient CakePHP.

Dans app_controller.php, avant la déclaration de classe :
uses('L10n');

Dans app_controller.php, en dehors de toute méthode :
var $langs = array('en' => array('title' => 'English', 'id' => 'eng', 'visible' => 0) , 'fr' => array('title' => 'Francais', 'id' => 'fre', 'visible' => 1, 'wp_cat' => 3));
var $defaultLang = 'fr';

Dans app_controller.php, fonction beforeFilter :
if (!isset($this->params['lang']) && !empty($this->params)) {
$_d = split ('[,;]', env('HTTP_ACCEPT_LANGUAGE'));
$f = false;
$selected = null;
foreach($_d as $l) {
if (isset($this->langs[$l]) && $this->langs[$l]['visible'] == 1 && $f == false) {
$selected = $l;
$f = true;
}
}
if ($f == false) $selected = $this->defaultLang;

$this->redirect(‘/’.$selected, 301);
die();
} elseif (!empty($this->params['lang']) && isset($this->langs[$this->params['lang']])) {
Configure::write(‘Config.language’, $this->langs[$this->params['lang']]['id']);
} elseif (!empty($this->params)) {
$this->cakeError(‘error404′, array(array(‘action’ => $this->action)));
} else {
$url = env(‘argv’);
$url = $url[0];
$url = ‘/’.str_replace(‘url=’,  », $url);

$l = explode(‘/’, $url);
$l = $l[1];

if (!isset($this->langs[$l]) && Configure::read(‘debug’) == 0) {
$this->cakeError(‘error404′, array(array(‘action’ => $this->action)));
}
}
$this->params['langs'] = $this->langs;

Et enfin dans routes.php, pour permettre l’ajout du paramètre de langue avant le contrôleur et l’action :
Supprimer la ligne suivante :
Router::connect('/', array('controller' => 'pages', 'action' => 'display', 'home'));
Et ajouter à la place les deux lignes suivantes :
Router::connect('/:lang/', array('controller' => 'pages', 'action' => 'display', 'home'));
Router::connect('/:lang/:controller/:action/*');

Ceci définira la langue dans la configuration de CakePHP, vous permettant par la suite d’utiliser les outils d’internationalisation du framework.

Comme tout framework qui se respecte, Ruby on Rails ne possède aucun système d’identification en natif. Chose naturelle vu que ce genre de choses est trop dépendant de vos besoins en fonction de l’application et est difficilement réalisable de manière générique (quoi que …)

Il existe cependant divers plugins permettant de mettre en place un système d’identification de manière aisée. Je vais ici vous présenter Restful Authentication.
Pour l’installation, je vous invite à lire ce tutoriel sur railforum.

Une fois que c’est mis en place, c’est très simple ! Vos pages d’inscription, d’identification, de déconnexion, de rappel de mot de passe et de mise à jour des informations sont faites. Il n’y a plus qu’à les personnaliser. Vous les trouverez :

  • contrôleur « users », action « new » : page d’inscription
  • contrôleur « sessions », action « new » : page d’identification
  • contrôleur « passwords », action « new » : rappel de mot de passe
  • contrôleur « users », action « edit » : modification des informations de l’utilisateur

Maintenant, tentons de personnaliser un peu cela :

Ajouter un rôle

Par défaut, seul le rôle « administrateur » existe. Mais vous pouvez avoir besoin de créer d’autres rôles. Supposons ici « redactor ».

Ouvrir le fichier /lib/authenticated_system.rb

Aux alentours de la ligne 70, vous verrez :

def check_administrator_role
check_role('administrator')
end

Ajoutez une fonction pour chacun des rôles que vous désirez en la nommant « check_xx_role » et en remplacant « admin » par le nom de votre rôle dans la base de donénes.
Si vous désirez forcer un utilisateur à avoir le rôle redactor pour visualiser l’action « publish » du contrôleur « edit », placez, en haut de votre contrôleur :

before_filter :check_redactor_role, :o nly => [:publish]

Il peut cependant vous arrivez d’avoir à manipuler les données de l’utilisateur dans votre contrôleur. Ou à vérifier le niveau de l’utilisateur dans celui-ci. Pour n’autoriser un rédacteur que à mettre des articles en brouillon mais l’empêcher de les publier.
Pour permettre cela, vous avez accès à l’objet current_user dans toute votre application. Il s’agit d’une instanciation du modèle User. Toutes les fonctions définies dans ce modèle y sont donc disponibles.
Vérifions donc que notre utilisateur est bien administrateur pour l’autoriser à mettre un article en état « publié ». Sinon, laissons-le en état « brouillon »

if !current_user.has_role?('administrator')
@billet.published = false
end

Ainsi, si l’utilisateur n’est pas administrateur, il pourra modifier un billet. Mais celui-ci se retrouvera alors remis hors ligne.

Restful Authentication peut permettre énormément de personnalisations, que ce soit avec des rôles ou non. La seule limite est votre imagination ! :-)

 
Fork me on GitHub