**Cette page a été importée automatiquement de notre ancien wiki mais n'a pas encore été révisée.**

# Howto Rails

<http://blog.phusion.nl/2012/09/21/the-right-way-to-deal-with-frozen-processes-on-unix/>

Mettre en place un environnement de production "Ruby On Rails" exige de trouver les bons compromis
entre les composants système - stable et robuste par nature - et l'environnement de développement
"Ruby On Rails" très volatile et changeant. Voici comment nous mettons cela en oeuvre.

## Cas 1 : utilisation avec Passenger

* [Documentation de Passenger pour Apache](http://modrails.com/documentation/Users%20guide%20Apache.html)
* [Documentation de Ruby Enterprise Edition](http://www.rubyenterpriseedition.com/documentation.html)
* [Un howto pour Yaml](http://www.yaml.org/YAML_for_ruby.html) (en parallèle avec Ruby, mais simple à comprendre)

### Installation

On installe d'abord Ruby 1.8 et ses dépendances utiles (`irb`, `rdoc`, `ri`, …).

~~~
# aptitude install ruby-full irb rubygems rails libactionpack-ruby1.8 libactionmailer-ruby1.8
~~~

Installer les bindings MySQL et OpenSSL (voir [#les-gems Les gems]) :

~~~
# aptitude install libmysql-ruby libopenssl-ruby libmysqlclient15-dev
~~~

### Les gems #les-gems

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

Par défaut, aucune librairie n'est installée sous forme de gem à part les bindings MySQL et Rack (qui est une dépendance de Passenger)
Il est préférable d'installer les bindings MySQL à la main (`libmysql-ruby`) car ils nécessitent la compilation  d'extensions en C et
risquent d'être utilisés par tous les utilisateurs.

OpenSSL fait normalement partie de la librairie standard Ruby, mais n'est pas inclus dans Debian. Rails en a besoin pour fonctionner, il convient
donc d'installer `libopenssl-ruby` manuellement.

### Ruby Enterprise Edition (REE)

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.
REE est donc censé s'intégrer parfaitement avec Passenger.

Des paquets (ubuntu) existent pour REE, mais le plus simple est de le compiler à la main.
Par défaut il s'installera dans le dossier `/opt`, en totale isolation du reste du système.
Rubygems est livré avec REE, et est placé dans le dossier de ce dernier.

Il suffit de récupérer une [archive des sources sur le site de REE](http://rubyenterpriseedition.com),
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.

À noter qu'il faut avoir installé les paquets `libreadline-dev`, `libz-dev`, `libssl-dev` et avoir une suite de
compilation fonctionnelle (gcc, g++, make, patch, …)

### Utilisation avec Passenger

Passenger est livré avec REE sous forme de gem, on peut donc l'installer juste après REE. Le mode d'installation est alors quelque peu différent :

Avant tout on installe toutes les librairies nécessaires : celles de REE listées précédemment, plus les libs de développement d'Apache

~~~
# aptitude install libreadline-dev libz-dev libssl-dev apache2-prefork-dev libcurl4-openssl-dev
~~~

On installe ensuite REE selon la procédure définie ci-dessus, et une fois cette installation terminée, on lance la commande :

~~~
/opt/ruby-enterprise-<version>/bin/passenger-install-apache2-module
~~~

L'installateur nous guide dans la procédure. Dans le cas ou le MPM d'Apache est ITK, il préviendra :

~~~
WARNING: Apache doesn't seem to be compiled with the 'prefork' or 'worker' MPM
~~~

On peut cependant continuer l'installation en ignorant l'avertissement. Une fois terminée, l'installateur donne la configuration pour Apache

Dans `/etc/apache2/mods-available/passenger.load` on mettra la ligne :

~~~
LoadModule passenger_module /opt/ruby-enterprise-1.8.7-2010.02/lib/ruby/gems/1.8/gems/passenger-3.0.0/ext/apache2/mod_passenger.so
~~~

et dans `/etc/apache2/mods-available/passenger.conf` :

~~~
<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  

    PassengerEnabled off
    #RailsAutoDetect off
    #RackAutoDetect off
    PassengerFriendlyErrorPages off

</IfModule>
~~~

Puis : `a2enmod passenger`

Une fois REE installé il reste un dernier soucis, les binaires sont dans `/opt/ruby-enterprise-<version>/bin`,
et pour que les utilisateurs puissent les utiliser il y a deux options possibles :

1. Rajouter ce chemin dans le PATH par défaut de tous les utilisateurs.
1. Créer des liens symboliques dans `/usr/bin`.

Pour la deuxième solution, le script suivant permet d'automatiser la tâche :

~~~
#!/bin/bash
cd /usr/bin
for i in `ls -1d /opt/ruby-enterprise-*/bin/*`; do
    ln -s $i
done
~~~


### Configuration de Passenger/mod_rails

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` :

~~~
<IfModule mod_passenger.c>
  PassengerRoot /usr
  PassengerRuby /usr/bin/ruby1.8

  # On ajoute les lignes suivantes:
  PassengerEnabled off
  RailsAutoDetect off
  RackAutoDetect 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>
~~~

### Exemple de VirtualHost pour Rails

~~~
<VirtualHost *:80>
  ServerName redmine.evolix.net
  PassengerEnabled on
  RailsAutoDetect on

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

  # Pour Apache 2 ITK
  AssignUserID {user} {group}
</VirtualHost>
~~~

* [#apache-itk-users Information complémentaire sur Apache ITK]
* [Script de génération de VHost](http://forge.evolix.org/scm/viewvc.php/trunk/scripts/create_rails_vhost?view=markup&root=packweb)

### Trucs, astuces et détails

#### Apache ITK #apache-itk-users

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.

Il faut donc y placer un propriétaire identique à celui utilisé dans AssignUserID

#### 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.

Par défaut, Passenger fait tourner l'application en mode production. On peut forcer un certain environnement
en plaçant la directive `RailsEnv <env>` dans le fichier de configuration du VHost.

Pour lancer dans un certain environnement les commandes qui agissent avec l'application (par exemple les
tâches [Rake](http://guides.rubyonrails.org/command_line.html#rake-is-ruby-make)), il suffit de définir la
variable d'environnement RAILS_ENV, par exemple :

~~~
$ RAILS_ENV=production rake db:migrate
~~~

#### Redémarrage de l'application

Pour redémarrer une application Rails, 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.

#### `umask`s spéciaux

Sur certains système, l'umask par défaut rend les fichiers installés par root non lisibles par le commun des utilisateurs.
Si celà est une bonne idée, combinée avec Rubygems et Apache ITK, celà devient moins évident, et il faut veiller
à `chmod`er correctement le dossier de Ruby pour que tous les utilisateurs puissent l'utiliser.

Un exemple avec REE :

~~~
# chmod -R u=rwX,g=rX,o=rX /opt/ruby-enterprise-1.8.7-2010.02/
~~~

#### Priorités de chargement

Par défaut, même lorsque `rubygems` est activé, Ruby utilisera en priorité les librairies système
(celles installées par les paquets) plutôt que les gems. On peut cependant forcer l'utilisation d'une gem,
et même fixer la version désirée (sinon c'est la plus récente qui est automatiquement utilisée).

Cette gestion des versions doit être faite par le développeur, qui peut installer les librairies qu'il souhaite indépendamment du système.
L'important est de savoir qu'il y a trois endroits ou on peut trouver une librairie Ruby :

* Installée par un paquet (`/usr/lib/ruby/1.8/`)
* Installée en temps que gem système (`/var/lib/gems/1.8/`)
* Installée en temps que gem utilisateur (`~/.gem/ruby/1.8/`)

#### 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.

Le script est disponible dans le dépôt Subversion du Pack Web Evolix, dans
[trunk/scripts/list_gems](http://forge.evolix.org/scm/viewvc.php/trunk/scripts/list_gems?view=markup&root=packweb).

#### É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
~~~

À mettre aussi dans la `$HOME` de `root` si c'est lui qui installe les gems.

#### 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](https://rails.lighthouseapp.com/projects/8994/tickets/3577-failsafe-middleware-should-flush-the-logger)
(deuxième fichier).

#### Répertoire temporaire de Passenger

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_. Par exemple, nous mettons :

~~~
PassengerTempDir /var/tmp/
~~~

### Mise à jour de Passenger

Passenger est installé en tant que gem dans _/opt/ruby-enterprise-<version-ree>/lib/ruby/gems/1.8/gems/_.
Voici la procédure pour le mettre à jour :

~~~
gem update passenger
~~~

~~~
/opt/ruby-enterprise-<version-ree>/lib/ruby/gems/1.8/gems/passenger-<nouvelle-version-passenger>/bin/passenger-install-apache2-module

~~~
Puis modifier les chemins vers mod_passenger dans la conf d'Apache _/etc/apache2/mod-available/passenger_.{conf,load} pour pointer vers la nouvelle version (notamment les directives _LoadModule_ et _PassengerRoot_).
Enfin, redémarrer Apache pour prendre en compte le nouveau module.

### Mise à jour de REE

Pour mettre à jour REE, il suffit de recommencer la procédure d'installation, la nouvelle version sera installé dans /opt/ruby-enterprise-<nouvelle-version> et ne perturbera donc pas la prod existante.

Pour prendre en compte la nouvelle installation de REE, il faut modifier les chemins vers REE dans la configuration d'Apache.

*Important :* pour la migration de REE 1.8.7-2010.02 vers 1.8.7-2011.01, il faut ajouter cette directive dans la configuration d'Apache :

~~~
RackBaseURI /
~~~

Et enlever les éventuelles directives `RailkBaseURI`.


## Cas 2 : utilisation avec rbenv + Unicorn

*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 préalable : mettre les droits _exec_ sur la partition /home

~~~
# aptitude install build-essential curl mg
~~~

~~~
# aptitude install python-pygments zlib1g-dev libxml2-dev \
 libxslt1-dev libmysqlclient-dev libcurl4-openssl-dev \
 libmagickcore-dev libmagickwand-dev libreadline-dev imagemagick
~~~

~~~
$ git clone git://github.com/sstephenson/rbenv.git .rbenv
$ git clone git://github.com/sstephenson/ruby-build.git .rbenv/plugins/ruby-build
$ echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bash_profile
$ echo 'eval "$(rbenv init -)"' >> ~/.bash_profile
$ . .bash_profile
$ rbenv install 1.9.2-p290
$ rbenv global 1.9.2-p290
~~~

Astuces diverses :

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

### Debian 9

~~~
# apt install rbenv ruby-build libssl-dev

$ eval "$(rbenv init -)"
$ rbenv install 2.4.0
$ rbenv global 2.4.0
$ gem install bundle

$ ruby -v
ruby 2.4.0p0 (2016-12-24 revision 57164) [x86_64-linux]
$ gem list
*** LOCAL GEMS ***

bigdecimal (default: 1.3.0)
bundle (0.0.1)
bundler (1.16.2)
did_you_mean (1.1.0)
io-console (default: 0.4.6)
json (default: 2.0.2)
minitest (5.10.1)
net-telnet (0.1.1)
openssl (default: 2.0.2)
power_assert (0.4.1)
psych (default: 2.2.2)
rake (12.0.0)
rdoc (default: 5.0.0)
test-unit (3.2.3)
xmlrpc (0.2.1)
~~~
