Ruby on Rails
Ruby on Rails,通常缩写为 Rails 或 RoR,是一个用于 Ruby 编程语言的开源 Web 应用程序框架。它旨在与敏捷开发方法一起使用,Web 开发人员使用该方法进行快速开发。
安装
Ruby on Rails 需要安装 Ruby,因此请先阅读该文章以获取安装说明。如果使用 uglifier(UglifyJS JavaScript 压缩器 的 Ruby 封装,可选),则还需要 nodejs 软件包。Rails 框架链接到 Ruby 的某个版本(或系统 Ruby 安装)。安装的 Ruby 版本可以来自系统,也可以来自 rbenv 或 rvm (Ruby 版本管理器)。
RubyGems
--no-user-install
。请阅读 Ruby#系统范围安装 gems,了解以这种方式使用 RubyGem 可能存在的危险。以下命令将为当前用户安装 Rails
$ gem install rails
构建文档需要一段时间。如果您想跳过它,请在安装命令后附加 --no-document
。
$ gem install rails --no-document
gem 是 Ruby 模块的包管理器,有点像 pacman 对于 Arch Linux。要更新您的 gems,只需运行
$ gem update
Pacman
安装 ruby-railsAUR 软件包。或者,请参阅 Ruby#使用 pacman 管理 RubyGems。
Quarry 二进制仓库
从非官方的 quarry 仓库安装 ruby-rails。
配置
Rails 捆绑了一个名为 Puma 的基本 HTTP 服务器。您可以创建一个测试应用程序来测试它。首先,使用 rails 命令创建一个应用程序
$ rails new testapp_name
Errno::ENOENT: No such file or directory (...) An error occurred while installing x, and Bundler cannot continue.
的错误,您可能需要配置 Bundler,以便它为每个用户安装 gems 而不是系统范围安装。或者,以 root 身份运行一次 rails new testapp_name
。如果它已成功完成,请删除 testapp_name/
并以普通用户身份再次运行 rails new testapp_name
。这将在您当前的工作目录中创建一个新文件夹。
$ cd testapp_name
接下来启动 Web 服务器。默认情况下,它监听端口 3000
$ rails server
现在通过在浏览器中打开 https://127.0.0.1:3000 访问您本地机器上的 testapp_name 网站
应该显示一个测试页面,向您问候“Welcome aboard”。
应用服务器
内置的 Ruby On Rails HTTP 服务器(称为 Puma)对于基本开发来说很方便,但不建议用于生产环境。相反,您应该使用应用服务器,例如 #Thin、#Unicorn 或 Phusion Passenger。
Thin
Thin 是一个快速且非常简单的 Ruby Web 服务器。
首先安装 thin gem
$ gem install thin
然后使用以下命令启动它
$ thin start
Unicorn
Unicorn 是一个无法直接与客户端通信的应用服务器。相反,Web 服务器必须位于客户端和 Unicorn 之间,并在需要时代理请求。Unicorn 大致基于 Mongrel。Github 正在使用它,它使用的架构努力寻找最佳子进程来处理请求。Unicorn 和 Mongrel 之间差异的解释。
安装 Unicorn gem
# gem install unicorn
然后在 /etc/unicorn/
中为您的应用程序创建一个配置文件。例如;这是一个基于 本教程 的 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
使用以下命令启动它
# /usr/bin/unicorn -D -E production -c /etc/unicorn/redmine.ru
Systemd 服务
将以下内容放入 /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
您现在可以使用 systemctl 轻松启动和停止 unicorn
Nginx 配置
设置 Nginx 后,将 unicorn 配置为上游服务器,使用类似这样的配置(警告:这是一个精简的示例。如果没有其他配置,它可能无法工作)
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 (使用 Phusion Passenger)
Phusion Passenger 是一个可用于 Nginx 和 Apache HTTP Server 的模块,它极大地简化了 Rails 服务器环境的设置。Nginx 不像 Apache 那样支持模块,并且必须使用 mod_rails
编译才能支持 Passenger;让 Passenger 为您编译它。对于 Apache,让 Passenger 为您设置模块。
两种不同的选择(二选一,不能同时使用)
- 安装 passenger 软件包。
- 从任何版本的 ruby (用户设置) 安装 'passenger' gem
# gem install passenger
如果您打算使用 Apache HTTP Server,请安装 mod_passenger 软件包(如果 passenger 不是从 gem 安装的),并运行
# passenger-install-apache2-module
如果 Rails 应用程序部署了子 URI,例如 http://example.com/yourapplication[失效链接 2023-05-06 ⓘ],则需要一些额外的配置,请参阅 Passenger 文档。
对于 Nginx,安装 nginx-mod-passenger 软件包(如果 passenger 不是从 gem 安装的),并运行
# passenger-install-nginx-module
安装程序将为您提供有关安装的任何其他信息(例如安装其他库)。
要使用 Nginx 服务应用程序,请按如下方式配置它
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 (使用 Nginx 作为反向代理服务器)
Puma (Github 页面) 是一个简单、快速、线程化且高度并发的 HTTP 1.1 服务器,用于 Ruby/Rack 应用程序,被认为是 Webrick 和 Mongrel 的替代品。它被设计为 Rubinius 的首选服务器,但也适用于 JRuby 和 MRI。反向代理服务器充当负载均衡器,将所有外部请求路由到 Web 应用程序池。
对于 Web 服务器,最好使用服务器用户和组,请查看 用户和组#添加用户的示例,下面使用 rails
作为用户名,server
作为组名,以及 my_app
作为 rails 应用程序名称。
首先将您的应用程序复制到 /var/www/my_app。并使用以下命令设置新的所有权
# cd /var/www/ # chown -R rails:server my_app
并使用以下命令设置用户权限
# chmod -R 775 my_app
然后在 Gemfile 中添加 puma gem
并使用以下命令安装
$ cd my_app $ bundle install
也通过 pacman 安装 nginx
。
在您的应用程序文件夹下,创建 sockets、pid 和 log 文件夹,使用
$ mkdir -p shared/pids shared/sockets shared/log
备份 nginx.conf,使用
# cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.backup
然后使用您最喜欢的编辑器创建一个新的 nginx.conf 文件,复制以下代码并根据您的喜好进行修改
#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; } }
启动 nginx
服务。
有几种启动 puma 服务器的方法,下面推荐两种方法
通常,创建文件 config/puma.rb
,复制以下代码并根据您的喜好进行修改
# 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
选项 A:使用配置文件
使用以下命令启动服务器
$ bundle exec puma -C config/puma.rb
您也可以使用参数 -d
在后台运行它,并使用以下命令检查
$ pgrep puma
当您想 kill
它时。
如果您想在退出登录后保持它运行,您可以使用
$ nohup bundle exec puma -C config/puma.rb &
但是如果系统重启,该进程仍然会丢失。
选项 2:通过 systemd
创建 一个新的 systemd 单元
~/.config/systemd/user/puma.service
[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
ExecStart
,如果您已全局安装 gem,则可以在 ExecStart
中将路由更改为 /usr/local/bin/
。要系统范围地启用 puma,创建
/etc/systemd/system/puma.service
[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
有关更多阅读,请查看 #参考。此外,为了轻松地在生产模式下部署应用程序,您可以尝试 capistrano
数据库
大多数 Web 应用程序都需要与某种数据库进行交互。ActiveRecord(Rails 使用的 ORM,用于提供数据库抽象)支持多个数据库供应商,其中最受欢迎的是 MySQL、SQLite 和 PostgreSQL。然后您将需要配置文件 "config/database.yml",以便 Rails 应用程序网站能够连接到您的数据库。
SQLite
SQLite 是 Ruby on Rails 的默认轻量级数据库。要启用 SQLite,只需安装 sqlite。
PostgreSQL
安装 postgresql。
为 Rails 安装
# gem install pg
或者在您的项目的 Gemfile 中添加 gem,然后使用 bundle。
创建一个新的 Rails 网站
# rails new my_web_site -d postgresql
MySQL
首先,安装和配置 MySQL 服务器。请参阅 MariaDB 了解如何执行此操作。
需要一个带有某些原生扩展的 gem,最好以 root 身份安装
# gem install mysql
您可以使用 -d
参数生成配置为 MySQL 的 rails 应用程序
$ rails new testapp_name -d mysql
数据库访问配置
无论您使用什么数据库(MySQL 或 Postgresql 或 SQlite(默认数据库)),您都需要编辑 config/database.yml
。Rails 为开发、测试、生产和其他环境使用不同的数据库。以下是本地主机上运行的 MySQL 的开发配置示例
default: adapter: mysql (or postgresql or sqlite) username: my_user_name_access password: my_secret_password
出于安全原因,最好不要将密码(将不再是秘密)直接以明文形式放在文本文件中。相反,您可以将 "my_secret_password' 替换为 "'<%= ENV["MYSQL_PASSWD"] %>'",其中 MYSQL_PASSWD 可以是从服务器使用的用户环境导出的环境变量(~/.profile 或 ~/.bashrc 或 ~/.zshrc,取决于您的选择和实用程序)。用 "'" 包围 <%= ENV.... %> 是为了防止您的密码中包含诸如 # 或 ! 等特殊字符...
从 Rails 创建数据库
请注意,您不必实际使用 MySQL 或 Postgresql 或 Sqlite 创建数据库,因为这可以直接通过 Rails 完成,使用
对于 rails-4.X 版本
# rake db:create
对于 rails-5.X 版本
# rails db:create (for version of Rails-5.X)
如果未显示任何错误,则表示您的数据库已创建,并且 Rails 可以与您的 MySQL 数据库通信。
完美的 Rails 设置
Phusion Passenger 运行多个 Ruby 版本。
- Arch Linux:一个简单、轻量级的发行版。 ;)
- Nginx:一个快速且轻量级的 Web 服务器,专注于高并发、性能和低内存使用。
- Passenger (又名 mod_rails 或 mod_rack):支持 Apache 和 Nginx Web 服务器。它使 Ruby Web 应用程序(例如那些基于 Ruby on Rails Web 框架构建的应用程序)的部署变得轻而易举。
- Ruby 版本管理器 (RVM):一个命令行工具,可让您轻松安装、管理和使用多个 Ruby 环境,从解释器到 gem 集。RVM 允许您使用其自身完全独立的专用环境来部署每个项目——从 Ruby 的特定版本,一直到运行您的应用程序所需的精确 gem 集——。
- SQLite:Ruby on Rails 的默认轻量级 数据库。
步骤 0:SQLite
安装 sqlite。
步骤 1:RVM
在“将用户添加到 rvm 组”步骤中,执行
# usermod -a -G rvm http # usermod -a -G rvm nobody
http
和 nobody
分别是与 Nginx 和 Passenger 相关的用户。
步骤 2:Rubies
一旦您掌握了可用的 RVM 安装,就可以安装最新的 Ruby 解释器了
$ rvm install 2.0.0
rvm 2.0.0 do gemset delete global
就足够了。步骤 3:带有 Passenger 支持的 Nginx
运行以下命令以允许 passenger 安装 nginx
$ rvm use 2.0.0 $ gem install passenger $ rvmsudo passenger-install-nginx-module
passenger gem 将被放入默认 gemset。
这将下载 Nginx 的源代码,为您编译并安装它。它将指导您完成整个过程。请注意,Nginx 的默认位置将是 /opt/nginx
。
完成后,在 /opt/nginx/conf/nginx.conf
的“http block”中添加以下两行,如下所示
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; ... }
步骤 4:Gemsets 和应用
对于每个 Rails 应用程序,您都应该有一个 gemset。假设您想尝试 RefineryCMS 与 BrowserCMS,这两个基于 Rails 的开源内容管理系统。
首先安装 RefineryCMS
$ rvm use 2.0.0@refinery --create $ gem install rails -v 4.0.1 $ gem install passenger $ gem install refinerycms refinerycms-i18n sqlite3
部署一个名为 refineria 的 RefineryCMS 实例
$ cd /srv/http/ $ rvmsudo refinerycms refineria
在不同的 gemset 中安装 BrowserCMS
$ rvm use 2.0.0@browser --create $ gem install rails -v 4.0.1 $ gem install passenger $ gem install browsercms sqlite3
部署一个名为 navegador 的 BrowserCMS 实例
$ cd /srv/http/ $ rvmsudo browsercms demo navegador $ cd /srv/http/navegador $ rvmsudo rake db:install
Nginx 和 Passenger Standalone 的 Passenger
请注意,passenger gem 被安装了三次,并且意图不同;在以下环境中
- 2.0.0 => 用于 Nginx,
- 2.0.0@refinery => Standalone
- 2.0.0@browser => Standalone
策略是将用于 Nginx 的 Passenger 与 Passenger Standalone 结合使用。必须首先确定最常用的 Ruby 环境(解释器加 gemset);在此设置中,选择了 Ruby 解释器和默认 gemset。然后继续设置用于 Nginx 的 Passenger 以使用该环境(步骤 3)。
- 所选环境中的应用程序可以像 Apache/Nginx (使用 Phusion Passenger) 中一样提供服务,请参阅本文的上方。
- 所有要使用不同 Ruby 版本和/或 gemset 的应用程序都可以通过 Passenger Standalone 单独提供服务,并通过反向代理配置挂钩到主 Web 服务器(步骤 6)。
步骤 5:.rvmrc 文件和所有权
此步骤对于设置的正确行为至关重要。RVM 在更改文件夹时查找 .rvmrc 文件;如果找到一个,它会读取它。在这些文件中,通常存储一行如下内容
rvm <ruby_version>@<gemset_name>
因此,指定的环境在应用程序的根文件夹入口处设置。
创建 /srv/http/refineria/.rvmrc,执行
# echo "rvm ree@refinery" > /srv/http/refineria/.rvmrc
,以及 /srv/http/navegador/.rvmrc,使用
# echo "rvm 2.0.0@browser" > /srv/http/navegador/.rvmrc
您现在必须进入两个应用程序的根文件夹,因为每次 RVM 第一次找到 .rvmrc 时,它都会询问您是否信任给定的文件,因此您必须验证刚刚创建的两个文件。
这些文件帮助相关程序找到正确的 gems。
此外,如果应用程序的文件和文件夹不归正确的用户所有,您将面临数据库写入访问问题。rvmsudo 在 Rails 生成时生成 root 拥有的存档;另一方面,nobody 是 Passenger 的用户——如果您没有更改它——:谁将使用并应该拥有它们。通过执行以下操作修复此问题
# chown -R nobody.nobody /srv/http/refineria /srv/http/navegador
步骤 6:反向代理
您必须为您的应用程序启动 Passenger Standalone Web 服务器。所以,执行
$ cd /srv/http/refineria $ rvmsudo passenger start --socket tmp/sockets/passenger.socket -d
和
$ cd /srv/http/navegador $ rvmsudo passenger start --socket tmp/sockets/passenger.socket -d
。您第一次运行 Passenger Standalone 时,它将执行一个小的安装。
请注意,您正在使用unix 域套接字而不是常用的TCP套接字;事实证明,unix 域比 TCP 套接字快得多。
rvmsudo passenger start -a 127.0.0.1 -p 3000 -d
在系统启动时启动 Passenger Standalone 守护进程
您有脚本吗?请在此处发布。
下面的 systemd 脚本是为我托管在 /srv/http/typo 的 Typo 博客制作的。它位于 /etc/systemd/system/passenger_typo.service。我从 "rvm env" 的输出中设置了 Environment= 标签(请参阅 "man systemd.exec")。唯一的例外是 PATH=,我必须从我的常规 PATH 和 rvm env 的输出中组合它。
注意:如果您没有将 "WorkingDirectory=" 变量设置为您的应用程序文件夹,passenger 将无法找到您的应用程序,随后将自行关闭。
[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
步骤 7:部署
使用子域名
再次编辑 /opt/nginx/conf/nginx.conf 以包含一些重要的指令
## 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; } }
proxy_pass http://127.0.0.1:3000;
不使用子域名
如果您出于某种原因不想在自己的子域名上托管每个应用程序,而是希望在类似这样的 URL 中托管:site.com/railsapp
,那么您可以在您的配置中执行类似这样的操作
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; } }
此时,您可以在条件下 启动 nginx
服务,并通过 refinery.domain.com 和 browser.domain.com 访问两个 CMS。
参考
- 将 RVM rubies 与 Phusion Passenger 一起使用
- https://blog.phusion.nl/2010/09/21/phusion-passenger-running-multiple-ruby-versions[失效链接 2023-07-30 ⓘ]
- 如何使用 Puma 和 NGINX 设置 Rails 应用
- https://www.digitalocean.com/community/tutorials/how-to-deploy-a-rails-app-with-puma-and-nginx-on-ubuntu-14-04