Login Logout

Howto Rails

Ruby On Rails est un framework web libre écrit en Ruby appliquant le principe MVC (Modèle-Vue-Contrôleur). Nous l’utilisons notamment dans le logiciel Chexpire.

Installation

Installation avec rbenv

rbenv permet d’avoir un environnement compilé par utilisateur. C’est donc le développeur qui gère sa version de Ruby, ses Gems, etc… on ne lui installe même pas Ruby !

Note : vous devez mettre les droits exec sur la partition /home pour cette installation

# apt install rbenv build-essential libssl-dev libreadline-dev zlib1g-dev
# apt install liblzma-dev libmariadbclient-dev

$ eval "$(rbenv init -)"
$ mkdir ~/.rbenv/plugins
$ git clone git://github.com/sstephenson/ruby-build.git ~/.rbenv/plugins/ruby-build
$ rbenv install --list
$ TMPDIR=~/tmp rbenv install 2.5.1
$ rbenv global 2.5.1
$ gem install bundler rails
$ echo 'eval "$(rbenv init -)"' >> ~/.bashrc

$ ruby -v
ruby 2.5.1p57 (2018-03-29 revision 63029) [x86_64-linux]

$ gem list

*** LOCAL GEMS ***

actioncable (5.2.1)
actionmailer (5.2.1)
actionpack (5.2.1)
actionview (5.2.1)
activejob (5.2.1)
activemodel (5.2.1)
activerecord (5.2.1)
activestorage (5.2.1)
activesupport (5.2.1)
arel (9.0.0)
bigdecimal (default: 1.3.4)
builder (3.2.3)
bundle (0.0.1)
bundler (1.16.3)
[…]

Installation avec ruby système

Cela permet de bénéficier des mises à jour de sécurité de Ruby, tout en gérant les Gems par utilisateur.

# apt install ruby ruby-dev ruby-bundler
# apt install liblzma-dev libmariadbclient-dev

$ export PATH="$HOME/.gem/ruby/2.3.0/bin:$PATH"
$ gem install bundler
$ echo 'PATH="$HOME/.gem/ruby/2.3.0/bin:$PATH"' >> ~/.bashrc

$ ruby -v
ruby 2.3.3p222 (2016-11-21) [x86_64-linux-gnu]

$ gem list

*** LOCAL GEMS ***

actionmailer (4.2.7.1)
actionpack (4.2.7.1)
actionview (4.2.7.1)
activejob (4.2.7.1)
activemodel (4.2.7.1)
activerecord (4.2.7.1)
activesupport (4.2.7.1)
arel (6.0.3)
atomic (1.1.16)
bigdecimal (1.2.8)
binding_of_caller (0.7.2)
blankslate (3.1.3)
builder (3.2.2)
bundle (0.0.1)
bundler (1.16.3, 1.13.6)
[…]

Utilisation

Démarrer un projet Rails

https://guides.rubyonrails.org/getting_started.html

$ rails --version
Rails 4.2.7.1

$ rails new foo
$ cd foo

On peut alors ajuster la configuration (routes, base de données, etc.), coder son projet, le stocker dans un repository Git, etc.

Pour voir en local le résultat :

$ cd foo
$ ./bin/rails server
=> Booting WEBrick
=> Rails 4.2.7.1 application starting in development on http://localhost:3000
=> Run `rails server -h` for more startup options
=> Ctrl-C to shutdown server
[2018-08-12 11:43:15] INFO  WEBrick 1.3.1
[2018-08-12 11:43:15] INFO  ruby 2.3.3 (2016-11-21) [x86_64-linux-gnu]
[2018-08-12 11:43:15] INFO  WEBrick::HTTPServer#start: pid=12383 port=3000

On peut alors le visualiser sur http://127.0.0.1:3000

Les environnements de Rails

Rails propose trois environnements d’exécution distincts·: production, development et test.

Chacun a un but précis facilement devinable depuis son nom.

Pour lancer dans un certain environnement les commandes qui agissent avec l’application (par exemple les tâches Rake), il suffit de définir la variable d’environnement RAILS_ENV, par exemple·:

$ RAILS_ENV=production rake db:migrate

Redémarrage optimisé

Pour redémarrer une application Rails de façon optimisée, il suffit de créer ou de mettre à jour le timestamp du fichier tmp/restart.txt (avec la commande touch par exemple). À la prochaîne requête, l’application sera redémarrée et tout l’environement chargé de nouveau.

Pour que l’application redémarre à chaque requête on peut aussi créer un fichier tmp/always_restart.txt et le supprimer une fois qu’on ne souhaite plus ce comportement.

Unité systemd

TODO, cf https://wiki.evolix.org/HowtoSystemd#systemd-par-utilisateur

Les Gems et Bundler

Les Gems sont des paquets contentant des librairies et/ou des applications écrites en Ruby. Elles sont souvent utilisées, notamment dans Rails.

$ gem -v
2.5.2.1

$ gem list

$ gem env
RubyGems Environment:
  - RUBYGEMS VERSION: 2.5.2.1
  - RUBY VERSION: 2.3.3 (2016-11-21 patchlevel 222) [x86_64-linux-gnu]
[…]

Les Gems peuvent se trouver à plusieurs endroits :

  • installée par un paquet Debian (/usr/lib/ruby/2.3.0/)
  • installée en temps que Gem système (/var/lib/gems/2.3.0/)
  • installée en temps que Gem utilisateur (~/.gem/ruby/2.3.0/)

Une application Rails contient un fichier Gemfile qui précise les Gems nécessaires et leurs versions :

source 'https://rubygems.org'

# Bundle edge Rails instead: gem 'rails', github: 'rails/rails'
gem 'rails', '4.2.7.1'
# Use sqlite3 as the database for Active Record
gem 'sqlite3'
# Use SCSS for stylesheets
gem 'sass-rails', '~> 5.0'
# Use Uglifier as compressor for JavaScript assets
gem 'uglifier', '>= 1.3.0'
[…]

Bundler est l’outil de prédilection pour installer les Gems nécessaires.

Avec la présence d’un fichier Gemfile, il suffit de lancer la commande :

$ bundle install

Un snapshot des Gems installées est aussi gardé dans un fichier Gemfile.lock permettant d’accélérer la résolution des dépendances.

En général, on inclut les fichiers Gemfile et Gemfile.lock dans le repository du projet.

Capistrano

Capistrano est un outil de déploiement particulièrement adapté aux développements en Ruby (dont Rails) mais parfaitement compatible avec d’autres langages ou frameworks (PHP, Java…).

Il est généralement exécuté depuis un poste de développement ou d’intégration. Il se connecte alors en SSH à un ou plusieurs serveurs (via SSH) pour y exécuter des tâches selon les rôles du serveur (application, base de données…).

Il est recommandé d’installer Capistrano via Bundler (dans le cadre d’un projet), mais il est évidemment possible de l’utiliser indépendamment (# gem install capistrano). Sa commande principale est cap.

À l’initialisation, Capistrano créé plusieurs fichiers, dont ceux nécessaires à gérer plusieurs envvironnements (production, staging…) :

├── Capfile
├── config
│   ├── deploy
│   │   ├── production.rb
│   │   └── staging.rb
│   └── deploy.rb
└── lib
    └── capistrano
            └── tasks
  • Capfile est lu par l’exécutable au chargement pour déterminer les modules à charger ;
  • config/deploy.rb contient la configuration générale ;
  • config/deploy/*.rb contiennent les particularités de chaque environnement ;
  • lib/capistrano/tasks/* permet de créer ses propres tâches à exécuter lors du déploiement.

Il existe de nombreux modules additionnels pour Capistrano afin d’apporter le support de frameworks ou bibliothèques : rails, rbenv, sidekiq, whenever… Il s’agit de gems à installer manuellement ou via Bundler.

Capistrano s’appuie massivement sur Rake, qui est une implémentation en Ruby du principe de Make (et des Makefile). Tout se passe donc sous forme de taches exécutées dans un ordre défini par un arbre de dépendance. De fait toutes les tâches peuvent être surchargées pour en personnaliser l’exécution.

Dans la plupart des cas (surtout avec Rails ou d’autres frameworks supportés) le déploiement en production se fait via la commande [bundle exec] cap production deploy. Un déploiement classique d’application Rails va faire : * mise à jour du code source (via Git) * création d’une “release” avec copie du code, liaison de fichiers/dossiers clés… * pré-compilation des assets (images, JS, CSS…) * migration de la base de données * activation de la release * relance du serveur d’application

Serveur web

Pour une utilisation en production d’une application Rails, on peut utiliser plusieurs solutions : Puma, Unicorn, Passenger, etc.

Puma

Puma est un serveur web pour Ruby orienté pour la performance et le traitement en parallèle. Il peut s’installer par package (apt install puma) ou par Gem.

$ gem install puma

$ cd projet
$ puma -S puma.state -b tcp://127.0.0.1:3042 -b unix:///tmp/puma.sock
Puma starting in single mode...
* Version 3.6.0 (ruby 2.3.3-p222), codename: Sleepy Sunday Serenity
* Min threads: 5, max threads: 5
* Environment: development
* Listening on tcp://127.0.0.1:3042
* Listening on unix:///tmp/puma.sock
Use Ctrl-C to stop

^C- Gracefully stopping, waiting for requests to finish
=== puma shutdown: 2018-08-25 23:15:36 +0200 ===
- Goodbye!

On peut également créer un fichier de paramètres puma.rb que l’on indiquera via -F puma.rb :

#!/usr/bin/env puma

directory '/home/foo/project'
environment 'production'
bind 'unix:///tmp/puma.sock'
port  ENV.fetch("PORT") { 3042 }
[…]

On peut créer des unités systemd pour gérer cela : https://github.com/puma/puma/blob/master/docs/systemd.md

Unicorn

Unicorn est un serveur web pour applications Rack conçu pour les clients rapides et optimisé pour Unix. Il peut s’installer par package (apt install unicorn) ou par Gem.

$ gem install unicorn

$ cd projet
$ unicorn -l 127.0.0.1:3042
I, [2018-08-26T00:05:09.967114 #2133]  INFO -- : listening on addr=127.0.0.1:3042 fd=9
I, [2018-08-26T00:05:09.967275 #2133]  INFO -- : worker=0 spawning...
I, [2018-08-26T00:05:09.967786 #2133]  INFO -- : master process ready
I, [2018-08-26T00:05:09.968015 #2135]  INFO -- : worker=0 spawned pid=2135
I, [2018-08-26T00:05:09.968129 #2135]  INFO -- : Refreshing Gem list
[…]

Passenger

Passenger est un serveur d’application qui propose des fonctionnalités avancées.

On peut l’installer sous forme de Gem pour le développement :

$ gem install passenger

$ cd projet
$ passenger start
=============== Phusion Passenger Standalone web server started ===============
Environment: development
Accessible via: http://0.0.0.0:3000/
You can stop Phusion Passenger Standalone by pressing Ctrl-C.

On peut l’installer pour Apache ainsi :

# apt install libapache2-mod-passenger

Par défaut, Passenger est activé pour tous les sites d’Apache et propose une auto-détection des environnements Rails et Rack, on commence par désactiver ce comportement dans /etc/apache2/mods-available/passenger.conf ainsi que d’autres ajustements :

<IfModule mod_passenger.c>
  PassengerRoot /usr/lib/ruby/vendor_ruby/phusion_passenger/locations.ini
  PassengerDefaultRuby /usr/bin/ruby

  # On ajoute les lignes suivantes:
  PassengerEnabled off
  RailsAutoDetect off
  RackAutoDetect off
  PassengerFriendlyErrorPages off

  PassengerTempDir /var/tmp/
  PassengerUploadBufferDir /var/tmp
  # S'assurer que les permissions sur le dossier permettent à Apache d'écrire dedans
  # cf. http://modrails.com/documentation/Users%20guide%20Apache.html#PassengerUploadBufferDir
  # C'est surtout important avec Apache ITK !
</IfModule>

Note : Passenger stocke tous ses fichiers temporaires dans le répertoire /tmp/ par défaut. Pour diverses raisons (de place, de droits voire de performance), il peut être intéressant d’en définir un autre. Cela ce fait via la directive Apache du module Passenger PassengerTempDir.

Et voici un VirtualHost minimal pour Apache :

<VirtualHost>
  ServerName foo.example.com
  PassengerEnabled on
  RailsAutoDetect on
  #RailsEnv development

  DocumentRoot /home/foo/www/current
  <Directory /home/redmine/www/current>
    Allow from all
    Options -MultiViews
  </Directory>

  # Pour Apache ITK
  AssignUserID foo foo
</VirtualHost>

Note : Passenger détermine sous quel utilisateur il va lancer l’application en se basant sur le propriétaire du fichier config/environment.rb de l’application Rails. Pour Apache ITK, il faut donc y placer un propriétaire identique à celui utilisé dans AssignUserID.

Note : par défaut, Passenger fait tourner l’application en mode production. On peut forcer un certain environnement en ajustant la directive RailsEnv dans le VirtualHost.

FAQ

GEM_HOME

On peut forcer l’environnement des Gems (pour ignorer /var/lib/gems/2.3.0 par exemple) :

$ export GEM_HOME=/$HOME/.gem/ruby/2.3.0

rbenv via Github

Si l’on souhaite installer rbenv sans utiliser le paquet Debian, il suffit de commencer la procédure ainsi :

$ git clone git://github.com/sstephenson/rbenv.git .rbenv
$ git clone git://github.com/sstephenson/ruby-build.git ~/.rbenv/plugins/ruby-build
$ eval "$(rbenv init -)"
$ rbenv install --list

puis de suivre les instructions décrites plus haut

Ruby Enterprise Edition (REE)

http://rubyenterpriseedition.com/documentation.html

REE est une version patchée de Ruby optimisée pour les applications Web et créée par les mêmes développeurs que Passenger. On peut l’installer en le compilant à la main (par défaut il s’installera dans e dossier /opt en totale isolation du reste du système) Il suffit de récupérer les sources, de la décompresser et de lancer le script ./installer --no-dev-docs en tant que root. Le reste de la procédure est indiqué par l’installateur. Les dépendances classiques de compilations seront nécessaires (apt install build-essential libssl-dev libreadline-dev zlib1g-dev).

Si l’on utilise avec Passenger, on pourra forcer l’utilisation de REE ainsi :

<IfModule passenger_module>
    PassengerRoot /opt/ruby-enterprise-<version>/lib/ruby/gems/1.8/gems/passenger-3.0.0
    PassengerRuby /opt/ruby-enterprise-<version>/bin/ruby  
</IfModule>

Lister les Gems

Il n’existe pas de moyen de lister les Gems installées uniquement sur le système, la commande gem cherche à la fois dans le dossier .gem de l’utilisateur et le dossier système. La solution est d’utiliser un script spécialisé qui fait cette recherche (un script list_gems doit traîner dans un coin…).

Économiser un peu d’espace

Par défaut, gem installe la documentation aux formats RDoc (documentation html) et RI (documentation console) pour les Gems installées. Pour éviter celà, créer un fichier .gemrc dans la $HOME de l’utilisateur avec le contenu suivant :

gem: --no-rdoc --no-ri

rails_env

rails_env = `head -1 $(HOME}/www/current/config/database.yml | tr ':' ' '`

Rails 2.3.2->2.3.5 & Passenger & les logs

Une petite erreur en environnement de production affecte les versions 2.3.2 à 2.3.5 (incluse) de Rails. Les logs de l’application ne sont pas écrits dans le fichier log/production.log. Pour pallier cette erreur, il faut appliquer le patch qu’on trouve ici (deuxième fichier).