Blacklight : déploiement avec Ruby On Rails

Du serveur de développement au serveur de production, intéressons-nous maintenant aux grandes étapes de la mise en ligne de Blacklight. Nous avions commencé cette série par une prise en main de ce logiciel, puis par l’ajout des données d’exemplaire et enfin l’activation des services au lecteur. Les développeurs pourront compléter ce billet avec cette procédure détaillée.
Gaivota Bird oiseau Vogel uccello aves 鳥 птица – Sur Flickr par Rodrigo Sá – Licence CC BY 2.0

Déployer Blacklight offre plusieurs avantages. Tout d’abord, son serveur web proposé par défaut n’est pas assez robuste pour une mise en ligne. Nous devons donc en installer un nouveau à même d’assurer un nombre de visites élevé. Ce sera Apache avec le module Passenger.

Apache n’est plus à présenter dans le monde du développement web. Quant à Passenger, il s’agit d’un programme adossé à Apache pour rendre accessible en ligne une application faite avec Ruby On Rails. C’est une architecture complexe.

Si l’on récapitule :

  • Ruby est un langage de programmation.
  • Ruby on Rails est un framework, construit avec Ruby.
  • Blacklight est un moteur de recherche construit avec Ruby On Rails.
  • Apache et Passenger sont un serveur web mettant en ligne un logiciel fait avec Ruby On Rails, en l’occurrence : Blacklight !

Outils pour une maintenance aisée

Ces composants sont obligatoires pour rendre disponible notre nouveau catalogue. Nous utiliserons également Capistrano et Git pour faciliter les mises à jour du serveur de départ au serveur d’arrivée.
En revanche, ces deux derniers programmes ne sont pas nécessaires. Le déploiement peut se faire en copiant simplement les fichiers sur le serveur d’arrivée. Pourtant, même en étant un adepte féru de simplicité, leur relative complexité de prise en main est largement pondérée par ce qu’ils apportent.

Git pour garder un historique

Git, que l’on configure sur le serveur de développement, est un outil désormais prisé pour la gestion de versions. Il va nous permettre d’archiver toutes les étapes des développements ultérieurs. On pourra l’utiliser également pour rétablir une version antérieure de notre catalogue en cas de problèmes de mise à jour par exemple.

Déployer avec Capistrano

Capistrano est un logiciel écrit en Ruby permettant le déploiement automatisé d’une application d’une machine à une autre. Depuis le serveur de travail, il va se charger, avec très peu d’instructions de notre part, de déployer Blacklight en ligne, de passer d’une version à l’autre, ou de le mettre à jour aisément.

Il n’est pas simple dans cette nébuleuse d’utilitaires, modules, applications, serveurs de voir qui fait quoi et à quoi ça sert. Au final, on finit par l’oublier et ses avantages permettent de se concentrer plus profondément sur l’amélioration de Blacklight.

Voilà, notre catalogue est en ligne… Ah non me dit-on ! Il reste encore quelques menus détails à régler, mais bientôt Blacklight sortira en pleine lumière à la BCU…

Blacklight, deuxième partie : les données d’exemplaires

Quand l'eau se fait RUBIS -Par CHRIS230*** - Licence CC BY-NC-SA 2.0 - Sur Flickr
Quand l’eau se fait RUBIS -Par CHRIS230*** – Licence CC BY-NC-SA 2.0 – Sur Flickr

Suite de notre série de billets sur Blacklight, commencée par une présentation générale.
La question qui nous intéresse désormais est de savoir comment connecter Blacklight à un SIGB. À priori, les nouvelles sont peu réjouissantes car Blacklight ne connait ni le z3950, ni OAI-PMH, ni aucun autre protocole pour interroger directement un catalogue. On peut l’alimenter d’une seule manière par défaut : en lisant des données au format Marc en XML ou ISO2709. Cependant, on peut le faire communiquer avec un catalogue, via z3950 notamment, sans devoir reprogrammer entièrement un client dédié. Si z3950 ne peut pas servir a récupérer un catalogue entier il peut être utile en revanche pour récupérer des informations en direct, comme les données d’exemplaires.

Nous allons utiliser ruby-zoom, une bibliothèque écrite en ruby et interrogeant ZOOM, une API disponible pour développer des services autour de z3950 (ce composant existe aussi pour PHP et C).
Pour l’installer sur un serveur Debian disposant d’un environnement Ruby, cette commande suffit :

[sourcecode language= »bash » gutter= »false »]$ apt-get install yaz libyaz4-dev[/sourcecode]

Ensuite, dans le fichier Gemfile de BL, ajoutons la ligne :

[sourcecode language= »ruby » gutter= »false »]gem ‘zoom’, :git => ‘https://github.com/bricestacey/ruby-zoom.git'[/sourcecode]

puis, dans le répertoire de BL, exécutons la commande suivante pour terminer l’installation de ruby-zoom (il sera compilé puis installé dans ruby on rails) :

[sourcecode language= »ruby » gutter= »false »]$ bundle install[/sourcecode]

Quelques lignes de code pour finir

À cette étape, il faut mettre la main à la pâte et programmer en Ruby. Le plus simple est de créer un nouveau modèle dans le framework Ruby on rails de BL dédié à la connexion z3950. Voici un exemple utilisant les fonctionnalités de ZOOM.

[sourcecode language= »ruby »]

class Z3950
attr_reader :ip, :base, :port, :url
attr_accessor :keyword

def initialize(ip, base, port)
@ip = ip
@base = base
@port = port
@url = @ip + ‘:’ + @port + ‘/’ + @base
end

def search
resultats =  »
begin
ZOOM::Connection.open(url) do |conn|
rset = conn.search(@keyword)
rset.each_record do |record|
resultats += record.xml
end
end
resultats.force_encoding(« ISO-8859-1 »).encode(« UTF-8″)
rescue
nil
end
end

def get_localisations(resultats= »)
doc = REXML::Document.new(resultats)
resultats = []
root = doc.root

if root.respond_to?(‘elements’)
#parcours des champs 998
root.elements.each(« datafield[@tag=’998′] ») do |element|
resultab = {}
#pour chaque element fils on récupère les informations d’exemplaire (localisation, salle, cote, empruntable ou non)
element.each do |field|
if field.respond_to?(‘elements’)
resultab[:localisation] = field.elements[« [@code=’b’] »].text if !field.elements[« [@code=’b’] »].nil?
resultab[:salle] = field.elements[« [@code=’c’] »].text if !field.elements[« [@code=’c’] »].nil?
resultab[:cote] = field.elements[« [@code=’e’] »].text if !field.elements[« [@code=’e’] »].nil?
if !field.elements[« [@code=’h’] »].nil?
if field.elements[« [@code=’h’] »].text ==  ‘ ‘
resultab[:empruntable] = nil
else
resultab[:empruntable] = field.elements[« [@code=’h’] »].text
end
end
end
end
resultats << resultab
end
end
resultats
end
end

[/sourcecode]

La méthode search définie ici s’occupe de la connexion au serveur z3950 et la méthode get_localisations récupère et traite la réponse XML du serveur pour obtenir les données d’exemplaire.
Il reste à ajouter quelques lignes de code dans le fichier catalog_controller.rb ou  l’on utilise les deux méthodes précédemment créées, puis dans le fichier show.html.erb pour afficher les résultats obtenus. Voici le résultat sur notre serveur de test, suivi des quelques lignes de code adéquates dans la vue et le contrôleur.

Affichage des données d’exemplaire dans BL

Le code à ajouter dans le fichier catalog_controller.rb :

[sourcecode language= »ruby »]
# surcharge de la méthode show du module catalog de blacklight
def show
@response, @document = get_solr_response_for_doc_id
connexion_z3950 = Z3950.new(‘X.X.X.X’, ‘base’, ‘port’)
connexion_z3950.keyword = @document.id
resultats = connexion_z3950.search
@localisations = connexion_z3950.get_localisations(resultats)

respond_to do |format|
format.html {setup_next_and_previous_documents}

# Add all dynamically added (such as by document extensions)
# export formats.
@document.export_formats.each_key do | format_name |
# It’s important that the argument to send be a symbol;
# if it’s a string, it makes Rails unhappy for unclear reasons.
format.send(format_name.to_sym) { render :text => @document.export_as(format_name), :layout => false }
end

end
end
[/sourcecode]

Et dans la vue (le fichier show.html.erb)

[sourcecode language= »html »]<p>
<table>
<tr>
<td>Disponibilité</td>
<td>Localisation</td>
<td>Salle</td>
<td>Cote</td>
</tr>
<% @localisations.each do |loc| %>
<tr>
<td><%= render_bouton_empruntable loc[:empruntable] %></td>
<td><%= loc[:localisation]%></td>
<td><%= loc[:salle]%></td>
<td><%= loc[:cote]%></td>
</tr>
<% end %>
</table>
</p>

[/sourcecode]