Difference between revisions of "Ruby on Rails"

From ArchWiki
Jump to: navigation, search
m (Option A: via RubyGems)
m (Database Access Configuration)
 
(62 intermediate revisions by 23 users not shown)
Line 1: Line 1:
[[Category:Web Server]]
+
[[Category:Web frameworks]]
[[zh-CN:Ruby on Rails]]
+
[[ja:Ruby on Rails]]
[http://rubyonrails.org/ Ruby on Rails], often shortened to Rails or RoR, is an open source web application framework for the Ruby programming language. It is intended to be used with an Agile development methodology that is used by web developers for rapid development.
+
[[zh-hans:Ruby on Rails]]
 +
[http://rubyonrails.org/ Ruby on Rails], often shortened to Rails or RoR, is an open source web application framework for the [[Ruby]] programming language. It is intended to be used with an Agile development methodology that is used by web developers for rapid development.
  
 
This document describes how to set up the Ruby on Rails Framework on an Arch Linux system.
 
This document describes how to set up the Ruby on Rails Framework on an Arch Linux system.
Line 7: Line 8:
 
== Installation ==
 
== Installation ==
  
Ruby on Rails requires [[Ruby]] to be installed, so read that article first for installation instructions. The {{pkg|nodejs}} package is also required.
+
Ruby on Rails requires [[Ruby]] to be installed, so read that article first for installation instructions. The {{pkg|nodejs}} package is also required if using uglifier (Ruby wrapper for [https://github.com/mishoo/UglifyJS2 UglifyJS JavaScript compressor], optional)
 +
The Rails framework is linked to a version of Ruby (or the system Ruby installation).
 +
Ruby version(s) installed can be from system or from rbenv or from rvm (Ruby Version Manager).  
  
Ruby on Rails itself can be installed multiple ways:
+
=== RubyGems ===
 
 
=== Option A: via RubyGems ===
 
  
 
{{Note|You can also install Rails system-wide using Gems. To do this, run the following commands as root and append them with {{ic|--no-user-install}}. Please read [[Ruby#Installing gems per-user or system-wide]] for possible dangers of using RubyGem in this way.}}
 
{{Note|You can also install Rails system-wide using Gems. To do this, run the following commands as root and append them with {{ic|--no-user-install}}. Please read [[Ruby#Installing gems per-user or system-wide]] for possible dangers of using RubyGem in this way.}}
  
 
The following command will install Rails for the current user:
 
The following command will install Rails for the current user:
 +
 
  $ gem install rails
 
  $ gem install rails
  
 
Building the documentation takes a while. If you want to skip it, append {{ic|--no-document}} to the install command.
 
Building the documentation takes a while. If you want to skip it, append {{ic|--no-document}} to the install command.
 +
 
  $ gem install rails --no-document
 
  $ gem install rails --no-document
  
 
gem is a package manager for Ruby modules, somewhat like pacman is to Arch Linux. To update your gems, simply run:
 
gem is a package manager for Ruby modules, somewhat like pacman is to Arch Linux. To update your gems, simply run:
 +
 
  $ gem update
 
  $ gem update
  
=== Option B: via pacgem ===
+
=== Pacman ===
  
You can install Rails using {{AUR|pacgem}} from the [[AUR]]. Pacgem automatically creates PKGBUILDs and Arch packages for each of the gems. These packages will then be installed using pacman.
+
[[Install]] the {{AUR|ruby-rails}} package. Alternatively, see [[Ruby#Managing RubyGems using pacman]].
# pacgem rails
 
  
The gem packages can be updated with
+
=== Quarry binary repository ===
# pacgem -u
 
  
=== Option C: from the AUR ===
+
Install ''ruby-rails'' from the unofficial [[Unofficial user repositories#quarry|quarry]] repository.
 
 
{{Warning|This is not recommended, as this might not include the latest Rails version, and additional dependencies may be introduced that may require you to run {{Ic|gem install}} anyway.}}
 
 
 
There is a {{AUR|rails}} package available in the [[AUR]].
 
  
 
== Configuration ==
 
== Configuration ==
Line 45: Line 43:
  
 
{{Note|If you get an error like {{ic|Errno::ENOENT: No such file or directory (...) An error occurred while installing x, and Bundler cannot continue.}}, you might have to configure [[Ruby#Bundler|Bundler]] so that it installs gems per-user and not system-wide. Alternatively, run {{ic|# rails new testapp_name}} once as root. If it has completed successfully, delete {{ic|testapp_name/}} and run {{ic|$ rails new testapp_name}} again as a regular user.}}
 
{{Note|If you get an error like {{ic|Errno::ENOENT: No such file or directory (...) An error occurred while installing x, and Bundler cannot continue.}}, you might have to configure [[Ruby#Bundler|Bundler]] so that it installs gems per-user and not system-wide. Alternatively, run {{ic|# rails new testapp_name}} once as root. If it has completed successfully, delete {{ic|testapp_name/}} and run {{ic|$ rails new testapp_name}} again as a regular user.}}
{{Note|If you get an error message like this:
 
{{ic|... FetchError: SSL_connect returned=1 errno= 0 state=SSLv2/v3 read server hello A: sslv3 alert handshake
 
failure (https://s3.amazonaws.com/ production.s3.rubygems.org/gems/rake-10.0.3.gem) }}
 
install {{Pkg|nodejs}} and try again.}}
 
  
 
This creates a new folder inside your current working directory.  
 
This creates a new folder inside your current working directory.  
Line 58: Line 52:
 
  $ rails server
 
  $ rails server
  
Now visit the testapp_name website on your local machine by opening http://localhost:3000 in your browser
+
Now visit the testapp_name website on your local machine by opening <nowiki>http://localhost:3000</nowiki> in your browser
 
{{Note|If Ruby complains about not being able to find a JavaScript runtime, install {{Pkg|nodejs}}.}}
 
{{Note|If Ruby complains about not being able to find a JavaScript runtime, install {{Pkg|nodejs}}.}}
  
A test-page should shown greeting you "Welcome aboard".
+
A test-page should be shown greeting you "Welcome aboard".
  
 
== Application servers ==
 
== Application servers ==
  
While the default Ruby On Rails HTTP server (WeBrick) is convenient for basic development it is not recommended for production use. Generally, you should choose between installing the Phusion Passenger module for your webserver ([[Apache]] or [[Nginx]]), or use a dedicated application-server (such as Mongrel or Unicorn) combined with a separate web-server acting as a reverse proxy.
+
The built-in Ruby On Rails HTTP server (WeBrick for version 4.X of Rails, and Puma for version 5.X) is convenient for basic development, but it is not recommended for production use. Instead, you should use an application server such as [[#Thin]], [[#Unicorn]] or [[#Apache/Nginx (using Phusion Passenger)|Phusion Passenger]].
  
=== Mongrel ===
+
=== Thin ===
Mongrel is a drop-in replacement for WeBrick, that can be run in precisely the same way, but offers better performance.
 
  
First install the Mongrel gem:
+
[http://code.macournoyer.com/thin/ Thin] is a fast and very simple Ruby web server.
  # gem install mongrel
+
 
 +
First install thin gem:
 +
  $ gem install thin
  
 
Then start it using:
 
Then start it using:
  # mongrel_rails start
+
  $ thin start
  
Alternatively, you can just run "ruby script/server" again, as it replaces WeBrick by default.
+
=== Unicorn ===
  
=== Unicorn ===
+
[http://unicorn.bogomips.org/ Unicorn] is an application server that cannot talk directly to clients. Instead, a web server must sit between clients and Unicorn, proxying requests as needed. Unicorn is loosely based on Mongrel. It is used by Github, and it uses an architecture that tries hard to find the best child for handling a request. [https://github.com/blog/517-unicorn Explanation of differences between Unicorn and Mongrel].
[http://unicorn.bogomips.org/ Unicorn] is loosely based on Mongrel, and is used by Github. It uses a different architecture that tries harder to find the best child for handling a request. [https://github.com/blog/517-unicorn Explanation of differences between Unicorn and Mongrel].
 
  
 
Install the Unicorn gem:
 
Install the Unicorn gem:
Line 110: Line 104:
  
 
Start it using:
 
Start it using:
  # usr/bin/unicorn -D -E production -c /etc/unicorn/redmine.ru
+
  # /usr/bin/unicorn -D -E production -c /etc/unicorn/redmine.ru
  
 
==== Systemd service ====
 
==== Systemd service ====
 +
 
Put the following contents in {{ic|/etc/systemd/system/unicorn.service}}:
 
Put the following contents in {{ic|/etc/systemd/system/unicorn.service}}:
 
{{hc|/etc/systemd/system/unicorn.service|2=
 
{{hc|/etc/systemd/system/unicorn.service|2=
Line 131: Line 126:
  
 
==== Nginx Configuration ====
 
==== Nginx Configuration ====
After setting up [[Nginx]], configure unicorn as an upstream server using something like this (Warning: this is a stripped example. It probably doesn't work without additional configuration):
+
 
 +
After setting up [[Nginx]], configure unicorn as an upstream server using something like this (Warning: this is a stripped example. It probably does not work without additional configuration):
 
{{bc|1=
 
{{bc|1=
 
http {
 
http {
Line 160: Line 156:
 
[http://www.modrails.com/ Passenger] also known as {{ic|mod_rails}} is a module available for [[Nginx]] and [[Apache]], that greatly simplifies setting up a Rails server environment. Nginx does not support modules as Apache and has to be compiled with {{ic|mod_rails}} in order to support Passenger; let Passenger compile it for you. As for Apache, let Passenger set up the module for you.
 
[http://www.modrails.com/ Passenger] also known as {{ic|mod_rails}} is a module available for [[Nginx]] and [[Apache]], that greatly simplifies setting up a Rails server environment. Nginx does not support modules as Apache and has to be compiled with {{ic|mod_rails}} in order to support Passenger; let Passenger compile it for you. As for Apache, let Passenger set up the module for you.
  
{{note|The current Nginx package in the official repositories actually is compiled with the Passenger module, so you can install it via pacman. The configuration files are stored in {{ic|/etc/nginx/conf/}}.}}
+
Two differents choices (one or the other, not both in same time):
{{note|As of 2013-10-07 this doesn't seem to be the casy any longer and you will have to follow the remaining steps here}}
+
 
 +
1/ Archlinux now has packages officialy support server modules to be compiled with passenger:
 +
  # pacman -Syu passenger
  
Start by installing the 'passenger' gem:
+
2/ Start by installing the 'passenger' gem from any version of ruby (user setting):
 
  # gem install passenger
 
  # gem install passenger
  
 
If you are aiming to use [[Apache]], run:
 
If you are aiming to use [[Apache]], run:
 +
# pacman -Syu mod_passenger (if passenger is not installed from gem)
 
  # passenger-install-apache2-module
 
  # passenger-install-apache2-module
  
Line 172: Line 171:
  
 
For [[Nginx]]:
 
For [[Nginx]]:
 +
# pacman -Syu nginx-mod-passenger (if passenger is not installed from gem)
 
  # passenger-install-nginx-module
 
  # passenger-install-nginx-module
  
Line 185: Line 185:
 
}
 
}
 
</pre>
 
</pre>
 +
 +
=== Puma (with Nginx as reverse proxy server) ===
 +
 +
[http://puma.io/ Puma] ([https://github.com/puma/puma Github Page]) is a simple, fast, threaded, and highly concurrent HTTP 1.1 server for Ruby/Rack applications, and is considered the replacement for Webrick and Mongrel. It was designed to be the go-to server for Rubinius, but also works well with JRuby and MRI. While reverse proxy server would acts as a load balancer that routes all external requests to a pool of web apps.
 +
 +
For a webserver it is better to use a server user and group, check [[Users and groups#Example adding a user]], below use {{ic|rails}} as user name and {{ic|server}} as group name, also {{ic|my_app}} as rails app name.
 +
 +
Start by copying your app to /var/www/my_app. And set new ownership with
 +
# cd /var/www/
 +
# chown -R rails:server my_app
 +
 +
and permission for user with
 +
# chmod -R 775 my_app
 +
 +
Then add {{ic|puma gem}} in the Gemfile and install with
 +
$ cd my_app
 +
$ bundle install
 +
 +
Also install {{ic|nginx}} by pacman.
 +
 +
Under your app folder, create sockets, pid and log folder with
 +
$ mkdir -p shared/pids shared/sockets shared/log
 +
 +
Backup nginx.conf with
 +
# cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.backup
 +
 +
Then create a new nginx.conf file with your favorite editor, copy codes below and modify as you like:
 +
<pre>
 +
#user html;
 +
worker_processes  1; # this may connect with the worker numbers puma can use.
 +
 +
#error_log  logs/error.log;
 +
#error_log  logs/error.log  notice;
 +
#error_log  logs/error.log  info;
 +
 +
#pid        logs/nginx.pid;
 +
 +
 +
events {
 +
    worker_connections  1024;
 +
}
 +
 +
http {
 +
upstream app {
 +
    # Path to Puma SOCK file, as defined previously
 +
    server unix:/var/www/my_app/shared/sockets/puma.sock;
 +
}
 +
 +
server {
 +
    listen 80;
 +
    server_name localhost; # or your server name
 +
 +
    root /var/www/my_app/public;
 +
 +
    try_files $uri/index.html $uri @app;
 +
 +
    location @app {
 +
proxy_pass http://app;
 +
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
 +
proxy_set_header Host $http_host;
 +
proxy_redirect off;
 +
    }
 +
 +
    error_page 500 502 503 504 /500.html;
 +
    client_max_body_size 4G;
 +
    keepalive_timeout 10;
 +
}
 +
}</pre>
 +
 +
[[Start]] the {{ic|nginx}} service.
 +
 +
There are several ways to start puma server, two ways are recommended below:
 +
 +
In common create file {{ic|config/puma.rb}}, copy codes below and modify as you like:
 +
<pre>
 +
# Change to match your CPU core count
 +
# You can check available worker numbers with $ grep -c processor /proc/cpuinfo
 +
# also see the comment in the nginx.conf
 +
workers 2
 +
 +
# Min and Max threads per worker
 +
#threads 1, 6
 +
 +
app_dir = File.expand_path("../..", __FILE__)
 +
shared_dir = "#{app_dir}/shared"
 +
 +
# Default to production
 +
#rails_env = ENV['RAILS_ENV'] || "production"
 +
#environment rails_env
 +
 +
# Set up socket location
 +
bind "unix://#{shared_dir}/sockets/puma.sock"
 +
 +
# Logging
 +
#stdout_redirect "#{shared_dir}/log/puma.stdout.log", "#{shared_dir}/log/puma.stderr.log", true
 +
 +
# Set master PID and state locations
 +
pidfile "#{shared_dir}/pids/puma.pid"
 +
#state_path "#{shared_dir}/pids/puma.state"
 +
#activate_control_app
 +
 +
#on_worker_boot do
 +
#  require "active_record"
 +
#  ActiveRecord::Base.connection.disconnect! rescue ActiveRecord::ConnectionNotEstablished
 +
#  ActiveRecord::Base.establish_connection(YAML.load_file("#{app_dir}/config/database.yml")[rails_env])
 +
#end</pre>
 +
 +
==== Option A: With config file ====
 +
 +
Start server with
 +
$ bundle exec puma -C config/puma.rb
 +
 +
You can also run it in background with parameter {{ic|-d}} and check with
 +
$ pgrep puma
 +
when you want to {{ic|kill}} it.
 +
 +
If you want to keep it after you log out, you can use
 +
$ nohup bundle exec puma -C config/puma.rb &
 +
But if the system reboot, the process will still get lost.
 +
 +
==== Option 2: by systemd ====
 +
 +
Create a new systemd unit {{ic|puma.service}} under ~/.config/systemd/user/ and copy codes below
 +
<pre>
 +
[Unit]
 +
Description=Puma application server
 +
After=network.target
 +
 +
[Service]
 +
WorkingDirectory=/var/www/my_app
 +
#Environment=RAILS_ENV=production
 +
PIDFile=/var/www/my_app/shared/pids/puma.pid
 +
ExecStart=/home/rails/.gem/ruby/2.2.0/bin/bundle exec \
 +
/home/rails/.gem/ruby/2.2.0/bin/puma \
 +
-C /var/www/my_app/config/puma.rb
 +
 +
[Install]
 +
WantedBy=default.target</pre>
 +
 +
Hint: For ExecStart, if you've installed gem globally, you can change routes to /usr/local/bin/ in ExecStart.
 +
 +
Then start puma with
 +
$ systemctl --user start puma
 +
 +
To enable puma system-widely:
 +
You need to store {{ic|puma.service}} in /etc/systemd/system/ and modify it as below:
 +
<pre>
 +
[Unit]
 +
Description=Puma application server
 +
After=network.target
 +
 +
[Service]
 +
WorkingDirectory=/var/www/my_app
 +
#Environment=RAILS_ENV=production
 +
User=rails
 +
PIDFile=/var/www/my_app/shared/pids/puma.pid
 +
ExecStart=/home/rails/.gem/ruby/2.2.0/bin/bundle exec \
 +
/home/rails/.gem/ruby/2.2.0/bin/puma \
 +
-C /var/www/my_app/config/puma.rb
 +
 +
[Install]
 +
WantedBy=multi-user.target</pre>
 +
 +
 +
For further reading take a look at [[#References]]. Also, for easily deploying app in production mode, you can try [https://github.com/capistrano/capistrano capistrano]
  
 
== Databases ==
 
== Databases ==
  
 
Most web applications will need to interact with some sort of database. ActiveRecord (the ORM used by Rails to provide database abstraction) supports several database vendors, the most popular of which are MySQL, SQLite, and PostgreSQL.
 
Most web applications will need to interact with some sort of database. ActiveRecord (the ORM used by Rails to provide database abstraction) supports several database vendors, the most popular of which are MySQL, SQLite, and PostgreSQL.
 +
And then you will have next to configure the file "config/database.yml" for Rails application web site able to connect on your database.
  
 
=== SQLite ===
 
=== SQLite ===
  
SQLite is the default lightweight database for Ruby on Rails. To enable SQLite, simply install {{Pkg|sqlite3}}.
+
SQLite is the default lightweight database for Ruby on Rails. To enable SQLite, simply install {{Pkg|sqlite}}.
  
 
=== PostgreSQL ===
 
=== PostgreSQL ===
  
 
Install {{Pkg|postgresql}}.
 
Install {{Pkg|postgresql}}.
 +
 +
Install for Rails:
 +
# gem install pg
 +
 +
Or add the gem inside your Gemfile of your project, then use bundle.
 +
 +
create a new Rails web site:
 +
# rails new my_web_site -d postgresql
  
 
=== MySQL ===
 
=== MySQL ===
Line 208: Line 382:
 
  $ rails new testapp_name -d mysql
 
  $ rails new testapp_name -d mysql
  
You then need to edit {{ic|config/database.yml}}. Rails uses different databases for development, testing, production and other environments. Here is an example development configuration for MySQL running on localhost:
+
=== Database Access Configuration ===
  
   development:
+
What ever Database (MySQL or Postgresql or SQlite (the default one) you use, you then need to edit {{ic|config/database.yml}}. Rails uses different databases for development, testing, production and other environments. Here is an example development configuration for MySQL running on localhost:
     adapter: mysql
+
 
    database: my_application_database
+
   default:
     username: development
+
     adapter: mysql (or postgresql or sqlite)
 +
     username: my_user_name_access
 
     password: my_secret_password
 
     password: my_secret_password
  
Note that you do not have to actually create the database using MySQL, as this can be done via Rails with:
+
For safety reasons, it is a good practice to not directly put password (who will be no more secret) as clear text in a text file.
 +
Instead you can replace "my_secret_password' by "'<%= ENV["MYSQL_PASSWD"] %>'" where MYSQL_PASSWD can be an environment variable exported from the user environment the server use (~/.profile or ~/.bashrc or ~/.zshrc depend of your choice and utility). Surrounding <%= ENV.... %> by "'" searve in case of your password has some special chars like # or !, etc...
 +
 
 +
=== Create the databases from Rails ===
 +
 
 +
Note that you do not have to actually create the database using MySQL or Postgresql or Sqlite, as this can be done via Rails directly with:
 +
 
 +
For rails-4.X version:
 
  # rake db:create
 
  # rake db:create
 +
 +
For rails-5.X version:
 +
# rails db:create (for version of Rails-5.X)
  
 
If no errors are shown, then your database has been created and Rails can talk to your MySQL database.
 
If no errors are shown, then your database has been created and Rails can talk to your MySQL database.
  
 
== The Perfect Rails Setup ==
 
== The Perfect Rails Setup ==
 +
 +
{{Style|Bloggish title, content mostly just reiterates the things mentioned above.}}
  
 
''Phusion Passenger running multiple Ruby versions.''
 
''Phusion Passenger running multiple Ruby versions.''
Line 279: Line 466:
 
   ...
 
   ...
 
  }
 
  }
 +
 +
{{Note|This step is currently being done automatically by the installer script.}}
  
 
=== Step 4: Gemsets and Apps ===
 
=== Step 4: Gemsets and Apps ===
Line 318: Line 507:
  
 
The strategy is to combine Passenger for Nginx with Passenger Standalone. One must first identify the Ruby environment (interpreter plus gemset) that one uses the most; in this setup the Ruby interpreter and the default gemset were selected. One then proceeds with setting up Passenger for Nginx to use that environment (step 3).
 
The strategy is to combine Passenger for Nginx with Passenger Standalone. One must first identify the Ruby environment (interpreter plus gemset) that one uses the most; in this setup the Ruby interpreter and the default gemset were selected. One then proceeds with setting up Passenger for Nginx to use that environment (step 3).
* Applications within the chosen environment can be served as in [[Ruby_on_Rails#Apache.2FNginx_.28using_Phusion_Passenger.29|Apache/Nginx (using Phusion Passenger)]], page up in this article.
+
* Applications within the chosen environment can be served as in [[#Apache.2FNginx .28using Phusion Passenger.29|Apache/Nginx (using Phusion Passenger)]], page up in this article.
 
* All applications that are to use a different Ruby version and/or gemset can be served separately through Passenger Standalone and hook into the main web server via a reverse proxy configuration (step 6).
 
* All applications that are to use a different Ruby version and/or gemset can be served separately through Passenger Standalone and hook into the main web server via a reverse proxy configuration (step 6).
  
Line 358: Line 547:
 
''Do you have a script? Please post it here.''
 
''Do you have a script? Please post it here.''
  
The systemd script below was made for a Typo blog I host at /srv/http/typo. It's located at /etc/systemd/system/passenger_typo.service. I set the Environment= tags (see "man systemd.exec") from the output of "rvm env". The only exception was PATH=, which I had to combine from my regular PATH and the output of rvm env.
+
The systemd script below was made for a Typo blog I host at /srv/http/typo. It is located at /etc/systemd/system/passenger_typo.service. I set the Environment= tags (see "man systemd.exec") from the output of "rvm env". The only exception was PATH=, which I had to combine from my regular PATH and the output of rvm env.
  
Note: If you don't set the "WorkingDirectory=" variable to your application folder, passenger will fail to find your app and will subsequently shut itself down.
+
Note: If you do not set the "WorkingDirectory=" variable to your application folder, passenger will fail to find your app and will subsequently shut itself down.
  
 
<pre>
 
<pre>
Line 425: Line 614:
 
==== Without subdomains ====
 
==== Without subdomains ====
  
If you for some reason don't want to host each application on it's own subdomain but rather in a url like: {{ic|site.com/railsapp}} then you could do something like this in your config:
+
If you for some reason do not want to host each application on its own subdomain but rather in a url like: {{ic|site.com/railsapp}} then you could do something like this in your config:
  
 
<pre>
 
<pre>
Line 438: Line 627:
 
         #you may need to change passenger_base_uri to be the uri you want to point at, ie:
 
         #you may need to change passenger_base_uri to be the uri you want to point at, ie:
 
         #passenger_base_uri /railsapp;
 
         #passenger_base_uri /railsapp;
         #but probably only if you're using the other solution with passenger phusion
+
         #but probably only if you are using the other solution with passenger phusion
 
         proxy_pass http://unix:/srv/http/railsapp/tmp/sockets/passenger.socket;
 
         proxy_pass http://unix:/srv/http/railsapp/tmp/sockets/passenger.socket;
 
         proxy_set_header Host $host;
 
         proxy_set_header Host $host;
Line 453: Line 642:
 
</pre>
 
</pre>
  
At this point you are in conditions to run Nginx with:
+
At this point you are in conditions to [[start]] the {{ic|nginx}} service and to access both CMSs through ''refinery.domain.com'' and ''browser.domain.com''.
 
 
# systemctl start nginx
 
 
 
and to access both CMSs through ''refinery.domain.com'' and ''browser.domain.com''.
 
  
 
=== References ===
 
=== References ===
Line 463: Line 648:
 
* http://beginrescueend.com/integration/passenger
 
* http://beginrescueend.com/integration/passenger
 
* http://blog.phusion.nl/2010/09/21/phusion-passenger-running-multiple-ruby-versions
 
* http://blog.phusion.nl/2010/09/21/phusion-passenger-running-multiple-ruby-versions
 +
* http://www.ruby-journal.com/how-to-setup-rails-app-with-puma-and-nginx/
 +
* https://www.digitalocean.com/community/tutorials/how-to-deploy-a-rails-app-with-puma-and-nginx-on-ubuntu-14-04
  
 
== See also ==
 
== See also ==

Latest revision as of 13:28, 24 July 2018

Ruby on Rails, often shortened to Rails or RoR, is an open source web application framework for the Ruby programming language. It is intended to be used with an Agile development methodology that is used by web developers for rapid development.

This document describes how to set up the Ruby on Rails Framework on an Arch Linux system.

Installation

Ruby on Rails requires Ruby to be installed, so read that article first for installation instructions. The nodejs package is also required if using uglifier (Ruby wrapper for UglifyJS JavaScript compressor, optional) The Rails framework is linked to a version of Ruby (or the system Ruby installation). Ruby version(s) installed can be from system or from rbenv or from rvm (Ruby Version Manager).

RubyGems

Note: You can also install Rails system-wide using Gems. To do this, run the following commands as root and append them with --no-user-install. Please read Ruby#Installing gems per-user or system-wide for possible dangers of using RubyGem in this way.

The following command will install Rails for the current user:

$ gem install rails

Building the documentation takes a while. If you want to skip it, append --no-document to the install command.

$ gem install rails --no-document

gem is a package manager for Ruby modules, somewhat like pacman is to Arch Linux. To update your gems, simply run:

$ gem update

Pacman

Install the ruby-railsAUR package. Alternatively, see Ruby#Managing RubyGems using pacman.

Quarry binary repository

Install ruby-rails from the unofficial quarry repository.

Configuration

Rails is bundled with a basic HTTP server called WeBrick. You can create a test application to test it. First, create an application with the rails command:

$ rails new testapp_name
Note: If you get an error like Errno::ENOENT: No such file or directory (...) An error occurred while installing x, and Bundler cannot continue., you might have to configure Bundler so that it installs gems per-user and not system-wide. Alternatively, run # rails new testapp_name once as root. If it has completed successfully, delete testapp_name/ and run $ rails new testapp_name again as a regular user.

This creates a new folder inside your current working directory.

$ cd testapp_name

Next start the web server. It listens on port 3000 by default:

$ rails server

Now visit the testapp_name website on your local machine by opening http://localhost:3000 in your browser

Note: If Ruby complains about not being able to find a JavaScript runtime, install nodejs.

A test-page should be shown greeting you "Welcome aboard".

Application servers

The built-in Ruby On Rails HTTP server (WeBrick for version 4.X of Rails, and Puma for version 5.X) is convenient for basic development, but it is not recommended for production use. Instead, you should use an application server such as #Thin, #Unicorn or Phusion Passenger.

Thin

Thin is a fast and very simple Ruby web server.

First install thin gem:

$ gem install thin

Then start it using:

$ thin start

Unicorn

Unicorn is an application server that cannot talk directly to clients. Instead, a web server must sit between clients and Unicorn, proxying requests as needed. Unicorn is loosely based on Mongrel. It is used by Github, and it uses an architecture that tries hard to find the best child for handling a request. Explanation of differences between Unicorn and Mongrel.

Install the Unicorn gem:

# gem install unicorn

Then create a configuration file for your application in /etc/unicorn/. For example; here is a configuration example (Based on [1]) for Redmine:

/etc/unicorn/redmine.ru
working_directory "/srv/http/redmine"
pid "/tmp/redmine.pid"

preload_app true
timeout 60
worker_processes 4
listen 4000
stderr_path('/var/log/unicorn.log')

GC.respond_to?(:copy_on_write_friendly=) and GC.copy_on_write_friendly = true

after_fork do |server, worker|
	#start the worker on port 4000, 4001, 4002 etc...
	addr = "0.0.0.0:#{4000 + worker.nr}"
	# infinite tries to start the worker
	server.listen(addr, :tries => -1, :delay => -1, :backlog => 128)

	#Drop privileges if running as root
	worker.user('nobody', 'nobody') if Process.euid == 0
end

Start it using:

# /usr/bin/unicorn -D -E production -c /etc/unicorn/redmine.ru

Systemd service

Put the following contents in /etc/systemd/system/unicorn.service:

/etc/systemd/system/unicorn.service
[Unit]
Description=Unicorn application server
After=network.target

[Service]
Type=forking
User=redmine
ExecStart=/usr/bin/unicorn -D -E production -c /etc/unicorn/redmine.ru

[Install]
WantedBy=multi-user.target

You can now easily start and stop unicorn using systemctl

Nginx Configuration

After setting up Nginx, configure unicorn as an upstream server using something like this (Warning: this is a stripped example. It probably does not work without additional configuration):

http {
	upstream unicorn {
		server 127.0.0.1:4000 fail_timeout=0;
		server 127.0.0.1:4001 fail_timeout=0;
		server 127.0.0.1:4002 fail_timeout=0;
		server 127.0.0.1:4003 fail_timeout=0;
	}

	server {
		listen		80 default;
		server_name	YOURHOSTNAMEHERE;

		location / {
			root			/srv/http/redmine/public;
			proxy_set_header	X-Forwarded-For $proxy_add_x_forwarded_for;
			proxy_set_header Host   $http_host;
			proxy_redirect		off;
			proxy_pass		http://unicorn;
		}
	}
}

Apache/Nginx (using Phusion Passenger)

Passenger also known as mod_rails is a module available for Nginx and Apache, that greatly simplifies setting up a Rails server environment. Nginx does not support modules as Apache and has to be compiled with mod_rails in order to support Passenger; let Passenger compile it for you. As for Apache, let Passenger set up the module for you.

Two differents choices (one or the other, not both in same time):

1/ Archlinux now has packages officialy support server modules to be compiled with passenger:

 # pacman -Syu passenger

2/ Start by installing the 'passenger' gem from any version of ruby (user setting):

# gem install passenger

If you are aiming to use Apache, run:

# pacman -Syu mod_passenger (if passenger is not installed from gem)
# passenger-install-apache2-module

In case a rails application is deployed with a sub-URI, like http://example.com/yourapplication, some additional configuration is required, see the modrails documentation

For Nginx:

# pacman -Syu nginx-mod-passenger (if passenger is not installed from gem)
# passenger-install-nginx-module

The installer will provide you with any additional information regarding the installation (such as installing additional libraries).

To serve an application with Nginx, configure it as follows:

server {
    server_name app.example.org;
    root path_to_app/public; # Be sure to point to 'public' folder!
    passenger_enabled on;
    rails_env development; # Rails environment.
}

Puma (with Nginx as reverse proxy server)

Puma (Github Page) is a simple, fast, threaded, and highly concurrent HTTP 1.1 server for Ruby/Rack applications, and is considered the replacement for Webrick and Mongrel. It was designed to be the go-to server for Rubinius, but also works well with JRuby and MRI. While reverse proxy server would acts as a load balancer that routes all external requests to a pool of web apps.

For a webserver it is better to use a server user and group, check Users and groups#Example adding a user, below use rails as user name and server as group name, also my_app as rails app name.

Start by copying your app to /var/www/my_app. And set new ownership with

# cd /var/www/
# chown -R rails:server my_app

and permission for user with

# chmod -R 775 my_app

Then add puma gem in the Gemfile and install with

$ cd my_app 
$ bundle install

Also install nginx by pacman.

Under your app folder, create sockets, pid and log folder with

$ mkdir -p shared/pids shared/sockets shared/log

Backup nginx.conf with

# cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.backup

Then create a new nginx.conf file with your favorite editor, copy codes below and modify as you like:

#user html;
worker_processes  1; # this may connect with the worker numbers puma can use.

#error_log  logs/error.log;
#error_log  logs/error.log  notice;
#error_log  logs/error.log  info;

#pid        logs/nginx.pid;


events {
    worker_connections  1024;
}

http {
	upstream app {
	    # Path to Puma SOCK file, as defined previously
 	    server unix:/var/www/my_app/shared/sockets/puma.sock;
	}

	server {
	    listen 80;
	    server_name localhost; # or your server name

	    root /var/www/my_app/public;

	    try_files $uri/index.html $uri @app;

	    location @app {
		proxy_pass http://app;
		proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
		proxy_set_header Host $http_host;
		proxy_redirect off;
	    }

	    error_page 500 502 503 504 /500.html;
	    client_max_body_size 4G;
	    keepalive_timeout 10;
	}
}

Start the nginx service.

There are several ways to start puma server, two ways are recommended below:

In common create file config/puma.rb, copy codes below and modify as you like:

# Change to match your CPU core count
# You can check available worker numbers with $ grep -c processor /proc/cpuinfo
# also see the comment in the nginx.conf
workers 2

# Min and Max threads per worker
#threads 1, 6

app_dir = File.expand_path("../..", __FILE__)
shared_dir = "#{app_dir}/shared"

# Default to production
#rails_env = ENV['RAILS_ENV'] || "production"
#environment rails_env

# Set up socket location
bind "unix://#{shared_dir}/sockets/puma.sock"

# Logging
#stdout_redirect "#{shared_dir}/log/puma.stdout.log", "#{shared_dir}/log/puma.stderr.log", true

# Set master PID and state locations
pidfile "#{shared_dir}/pids/puma.pid"
#state_path "#{shared_dir}/pids/puma.state"
#activate_control_app

#on_worker_boot do
#  require "active_record"
#  ActiveRecord::Base.connection.disconnect! rescue ActiveRecord::ConnectionNotEstablished
#  ActiveRecord::Base.establish_connection(YAML.load_file("#{app_dir}/config/database.yml")[rails_env])
#end

Option A: With config file

Start server with

$ bundle exec puma -C config/puma.rb

You can also run it in background with parameter -d and check with

$ pgrep puma

when you want to kill it.

If you want to keep it after you log out, you can use

$ nohup bundle exec puma -C config/puma.rb &

But if the system reboot, the process will still get lost.

Option 2: by systemd

Create a new systemd unit puma.service under ~/.config/systemd/user/ and copy codes below

[Unit]
Description=Puma application server
After=network.target

[Service]
WorkingDirectory=/var/www/my_app
#Environment=RAILS_ENV=production
PIDFile=/var/www/my_app/shared/pids/puma.pid
ExecStart=/home/rails/.gem/ruby/2.2.0/bin/bundle exec \
	 /home/rails/.gem/ruby/2.2.0/bin/puma \
	 -C /var/www/my_app/config/puma.rb

[Install]
WantedBy=default.target

Hint: For ExecStart, if you've installed gem globally, you can change routes to /usr/local/bin/ in ExecStart.

Then start puma with

$ systemctl --user start puma

To enable puma system-widely: You need to store puma.service in /etc/systemd/system/ and modify it as below:

[Unit]
Description=Puma application server
After=network.target

[Service]
WorkingDirectory=/var/www/my_app
#Environment=RAILS_ENV=production
User=rails
PIDFile=/var/www/my_app/shared/pids/puma.pid
ExecStart=/home/rails/.gem/ruby/2.2.0/bin/bundle exec \
	 /home/rails/.gem/ruby/2.2.0/bin/puma \
	 -C /var/www/my_app/config/puma.rb

[Install]
WantedBy=multi-user.target


For further reading take a look at #References. Also, for easily deploying app in production mode, you can try capistrano

Databases

Most web applications will need to interact with some sort of database. ActiveRecord (the ORM used by Rails to provide database abstraction) supports several database vendors, the most popular of which are MySQL, SQLite, and PostgreSQL. And then you will have next to configure the file "config/database.yml" for Rails application web site able to connect on your database.

SQLite

SQLite is the default lightweight database for Ruby on Rails. To enable SQLite, simply install sqlite.

PostgreSQL

Install postgresql.

Install for Rails:

# gem install pg

Or add the gem inside your Gemfile of your project, then use bundle.

create a new Rails web site:

# rails new my_web_site -d postgresql

MySQL

First, install and configure a MySQL server. Please refer to MySQL on how to do this.

A gem with some native extensions is required, probably best installed as root:

# gem install mysql

You can generate a rails application configured for MySQL by using the -d parameter:

$ rails new testapp_name -d mysql

Database Access Configuration

What ever Database (MySQL or Postgresql or SQlite (the default one) you use, you then need to edit config/database.yml. Rails uses different databases for development, testing, production and other environments. Here is an example development configuration for MySQL running on localhost:

 default:
   adapter: mysql (or postgresql or sqlite)
   username: my_user_name_access
   password: my_secret_password

For safety reasons, it is a good practice to not directly put password (who will be no more secret) as clear text in a text file. Instead you can replace "my_secret_password' by "'<%= ENV["MYSQL_PASSWD"] %>'" where MYSQL_PASSWD can be an environment variable exported from the user environment the server use (~/.profile or ~/.bashrc or ~/.zshrc depend of your choice and utility). Surrounding <%= ENV.... %> by "'" searve in case of your password has some special chars like # or !, etc...

Create the databases from Rails

Note that you do not have to actually create the database using MySQL or Postgresql or Sqlite, as this can be done via Rails directly with:

For rails-4.X version:

# rake db:create

For rails-5.X version:

# rails db:create (for version of Rails-5.X)

If no errors are shown, then your database has been created and Rails can talk to your MySQL database.

The Perfect Rails Setup

Tango-edit-clear.pngThis article or section needs language, wiki syntax or style improvements. See Help:Style for reference.Tango-edit-clear.png

Reason: Bloggish title, content mostly just reiterates the things mentioned above. (Discuss in Talk:Ruby on Rails#)

Phusion Passenger running multiple Ruby versions.

  • Arch Linux: A simple, lightweight distribution. ;)
  • Nginx: A fast and lightweight web server with a strong focus on high concurrency, performance and low memory usage.
  • Passenger (a.k.a. mod_rails or mod_rack): Supports both Apache and Nginx web servers. It makes deployment of Ruby web applications, such as those built on Ruby on Rails web framework, a breeze.
  • Ruby Version Manager (RVM): A command-line tool which allows you to easily install, manage, and work with multiple Ruby environments from interpreters to sets of gems. RVM lets you deploy each project with its own completely self-contained and dedicated environment —from the specific version of ruby, all the way down to the precise set of required gems to run your application—.
  • SQLite: The default lightweight database for Ruby on Rails.

Step 0: SQLite

Install sqlite.

Note: Of course SQLite is not critical in this setup, you can use MySQL and PostgreSQL as well.

Step 1: RVM

Make a multi-user RVM installation as specified here.

In the 'adding users to the rvm group' step, do

# usermod -a -G rvm http
# usermod -a -G rvm nobody

http and nobody are the users related to Nginx and Passenger, respectively.

Note: Maybe adding the 'nobody' user to the 'rvm' group is not necessary.

Step 2: Rubies

Once you have a working RVM installation in your hands, it is time to install the latest Ruby interpreter

Note: During the installation of Ruby patches will be applied. Consider installing the base-devel group beforehand.
$ rvm install 2.0.0
Note: It may be useful to delete the 'global' gemsets of the environments that have web applications. Their gems might somehow interfere with Passenger. In that case, a rvm 2.0.0 do gemset delete global is sufficient.

Step 3: Nginx with Passenger support

Run the following to allow passenger install nginx:

$ rvm use 2.0.0 
$ gem install passenger
$ rvmsudo passenger-install-nginx-module

The passenger gem will be put into the default gemset.

This will download the sources of Nginx, compile and install it for you. It will guide you through all the process. Note that the default location for Nginx will be /opt/nginx.

Note: If you encounter a compilation error regarding Boost threads, see this article.

After completion, add the following two lines into the 'http block' at /opt/nginx/conf/nginx.conf that look like:

http { 
  ...
  passenger_root /usr/local/rvm/gems/ruby-2.0.0-p353/gems/passenger-3.0.9;
  passenger_ruby /usr/local/rvm/wrappers/ruby-2.0.0-p353/ruby;
  ...
}
Note: This step is currently being done automatically by the installer script.

Step 4: Gemsets and Apps

For each Rails application you should have a gemset. Suppose that you want to try RefineryCMS against BrowserCMS, two open-source Content Management Systems based on Rails.

Install RefineryCMS first:

$ rvm use 2.0.0@refinery --create
$ gem install rails -v 4.0.1
$ gem install passenger
$ gem install refinerycms refinerycms-i18n sqlite3

Deploy a RefineryCMS instance called refineria:

$ cd /srv/http/
$ rvmsudo refinerycms refineria

Install BrowserCMS in a different gemset:

$ rvm use 2.0.0@browser --create
$ gem install rails -v 4.0.1
$ gem install passenger
$ gem install browsercms sqlite3

Deploy a BrowserCMS instance called navegador:

$ cd /srv/http/
$ rvmsudo browsercms demo navegador
$ cd /srv/http/navegador
$ rvmsudo rake db:install

Passenger for Nginx and Passenger Standalone

Observe that the passenger gem was installed three times and with different intentions; in the environments

  • 2.0.0 => for Nginx,
  • 2.0.0@refinery => Standalone
  • 2.0.0@browser => Standalone

The strategy is to combine Passenger for Nginx with Passenger Standalone. One must first identify the Ruby environment (interpreter plus gemset) that one uses the most; in this setup the Ruby interpreter and the default gemset were selected. One then proceeds with setting up Passenger for Nginx to use that environment (step 3).

  • Applications within the chosen environment can be served as in Apache/Nginx (using Phusion Passenger), page up in this article.
  • All applications that are to use a different Ruby version and/or gemset can be served separately through Passenger Standalone and hook into the main web server via a reverse proxy configuration (step 6).

Step 5: .rvmrc files and ownerships

This step is crucial for the correct behaviour of the setup. RVM seeks for .rvmrc files when changing folders; if it finds one, it reads it. In these files normally one stores a line like

rvm <ruby_version>@<gemset_name>

so the specified environment is set at the entrance of applications' root folder.

Create /srv/http/refineria/.rvmrc doing

# echo "rvm ree@refinery" > /srv/http/refineria/.rvmrc

, and /srv/http/navegador/.rvmrc with

# echo "rvm 2.0.0@browser" > /srv/http/navegador/.rvmrc

You have to enter to both application root folders now, because every first time that RVM finds a .rvmrc it asks you if you trust the given file, consequently you must validate the two files you have just created.

These files aid the programs involved to find the correct gems.

Apart, if applications' files and folders are not owned by the right user you will face database write-access problems. The use of rvmsudo produces root-owned archives when generated by Rails; in the other hand, nobody is the user for Passenger —if you have not changed it—: who will use and should posses them. Fix this doing

# chown -R nobody.nobody /srv/http/refineria /srv/http/navegador

Step 6: Reverse proxies

You have to start the Passenger Standalone web servers for your applications. So, do

$ cd /srv/http/refineria
$ rvmsudo passenger start --socket tmp/sockets/passenger.socket -d

and

$ cd /srv/http/navegador
$ rvmsudo passenger start --socket tmp/sockets/passenger.socket -d

. The first time that you run a Passenger Standalone it will perform a minor installation.

Note that you are using unix domain sockets instead of the commonly-used TCP sockets; it turns out that unix domain are significantly faster than TCP sockets.

Note: If you are experimenting trouble with unix sockets, changing to TCP should work:
rvmsudo passenger start -a 127.0.0.1 -p 3000 -d

Launch Passenger Standalone daemons at system start-up

Do you have a script? Please post it here.

The systemd script below was made for a Typo blog I host at /srv/http/typo. It is located at /etc/systemd/system/passenger_typo.service. I set the Environment= tags (see "man systemd.exec") from the output of "rvm env". The only exception was PATH=, which I had to combine from my regular PATH and the output of rvm env.

Note: If you do not set the "WorkingDirectory=" variable to your application folder, passenger will fail to find your app and will subsequently shut itself down.

[Unit]
Description=Passenger Standalone Script for Typo
After=network.target

[Service]
Type=forking
WorkingDirectory=/srv/http/typo
PIDFile=/srv/http/typo/tmp/pids/passenger.pid

Environment=PATH=/usr/local/rvm/gems/ruby-2.0.0-p0@typo/bin:/usr/local/rvm/gems/ruby-2.0.0-p0@global/bin:/usr/local/rvm/rubies/ruby-2.0.0-p0/bin:/usr/local/rvm/bin:/usr/local/bin:/usr/bin:/bin:/usr/local/sbin:/usr/sbin:/sbin:/usr/bin/core_perl
Environment=rvm_env_string=ruby-2.0.0-p0@typo
Environment=rvm_path=/usr/local/rvm
Environment=rvm_ruby_string=ruby-2.0.0-p0
Environment=rvm_gemset_name=typo
Environment=RUBY_VERSION=ruby-2.0.0-p0
Environment=GEM_HOME=/usr/local/rvm/gems/ruby-2.0.0-p0@typo
Environment=GEM_PATH=/usr/local/rvm/gems/ruby-2.0.0-p0@typo:/usr/local/rvm/gems/ruby-2.0.0-p0@global
Environment=MY_RUBY_HOME=/usr/local/rvm/rubies/ruby-2.0.0-p0
Environment=IRBRC=/usr/local/rvm/rubies/ruby-2.0.0-p0/.irbrc

ExecStart=/bin/bash -c "rvmsudo passenger start --socket /srv/http/typo/tmp/sockets/passenger.socket -d"

[Install]
WantedBy=multi-user.target

Step 7: Deployment

With subdomains

Once again edit /opt/nginx/conf/nginx.conf to include some vital instructions:

## RefineryCMS ##

server {
    server_name refinery.domain.com;
    root /srv/http/refineria/public;
    location / {
        proxy_pass http://unix:/srv/http/refineria/tmp/sockets/passenger.socket;
        proxy_set_header Host $host;
    }
}

## BrowserCMS ##

server {
    server_name browser.domain.com;
    root /srv/http/navegador/public;
    location / {
        proxy_pass http://unix:/srv/http/navegador/tmp/sockets/passenger.socket;
        proxy_set_header Host $host;
    }
}
Note: Or if using TCP sockets, configure the proxy_pass directive like
proxy_pass http://127.0.0.1:3000;

Without subdomains

If you for some reason do not want to host each application on its own subdomain but rather in a url like: site.com/railsapp then you could do something like this in your config:

server {
    server_name site.com;
    #Base for the html files etc
    root /srv/http/;

    #First application you want hosted under domain site.com/railsapp
    location /railsapp {
        root /srv/http/railsapp/public;
        #you may need to change passenger_base_uri to be the uri you want to point at, ie:
        #passenger_base_uri /railsapp;
        #but probably only if you are using the other solution with passenger phusion
        proxy_pass http://unix:/srv/http/railsapp/tmp/sockets/passenger.socket;
        proxy_set_header Host $host;
    }

    #Second applicatino you want hosted under domain site.com/anotherapp
    location /anotherapp {
        root /srv/http/anotherapp/public;
        #same thing about the passenger_base_uri here, but with value /anotherapp instead
        proxy_pass http://unix:/srv/http/anotherapp/tmp/sockets/passenger.socket;
        proxy_set_header Host $host;
    }
}

At this point you are in conditions to start the nginx service and to access both CMSs through refinery.domain.com and browser.domain.com.

References

See also

References