Howto Rails
- Documentation : https://guides.rubyonrails.org/
- YAML Cookbook for Ruby : http://www.yaml.org/YAML_for_ruby.html
- Rôle Ansible : https://forge.evolix.org/projects/ansible-roles/repository/show/rbenv
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 !
Pour l’installation de Rbenv, voir notre HowtoRbenv.
$ gem install bundler rails
$ 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>
Require all granted
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é dansAssignUserID
.
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).