Passenger/DataMapper/Sinatra: Ruby наносит ответный удар

Всемирная сеть полна всевозможных мануалов, как для php поднять на %operation_system% связку Apache + php + MySQL и сделать работающий «It Works!»/«<? phpinfo() ?>».
Логотип: Passenger for nginx, DataMapper, Sinatra
Почему для ruby поднять сервер не сложнее и пример простого веб-приложения, развернутого на Linux-сервере, под катом.

Введение

Итак, что у нас есть:
  • Ruby 1.9.2 (у меня он есть в репозиториях ArchLinux) — советую воспользоваться rvm, если у вас нет желания «одной командой make превращать систему в слаку»© при отсутствии такового
  • желание написать/развернуть веб-приложение
Приступим.

nginx

nginx — http-сервер, не нуждающийся в представлении. Наша задача — установить его вместе с модулем Phusion Passenger™ (так же mod_rack или mod_rails), позволяющим запускать приложения на Ruby:

<pre>sudo gem install passenger # качаем гем-установщик
sudo passenger-install-module-nginx # устанавливаем модуль
# Далее оставляем стандартные опции (1) или обращаемся к местным гуру флагов nginx
# и выбираем, куда установить nginx (/opt/nginx по умолчанию)
</pre>

Теперь файл настроек nginx.conf лежит в /opt/nginx/conf/nginx.conf.

Он практически готов к запуску, только изменим секцию server на свою — пусть наше приложение будет лежать в /opt/www/hello (кстати, советую для пущего удобства сделать символическую ссылку в /opt/www или /www из вашей папки с проектами — например, ln -s /home/username/coding/projects/web/ /opt/www):

<pre>server {
    listen 80;
    server_name localhost;
        
    passenger_enabled on;
    rails_env development;

    root /opt/www/hello/;
}
</pre>

Также, пропишите user root; на месте закомменченной #user nobody; — так делать не очень хорошо, но для тестирования пока, так как сильно хочется, можно.

После написания приложения, сервер можно запускать.

DataMapper

DataMapper — это ORM для Ruby, а значит мы, абстрагируясь от представления данных в базе оных, можем создать модель в языке (Ruby-класс) для управления ими.

Например:

<pre>class Post
  include DataMapper::Resource

  property :id,    Serial
  property :by,    String
  property :text,  Text
end
</pre>

При инициализации (миграции) БД выльется в следующий sql-запрос:

<pre>CREATE TABLE "posts" ("id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, "by" VARCHAR(50), "text" VARCHAR(50))
</pre>

Sinatra

Sinatra — расширение (DSL, если быть точнее) над Ruby для написания веб-приложений. Простейшее приложение поражает своей лаконичностью:

<pre>require 'sinatra'
get '/hi' do
  "Hello World!"
end
</pre>

При запуске последнего по адресу %siteurl%/hi мы увидим всеми любимый «Hello World!».

Но остановиться на таком было бы глупо, поэтому мы напишем сколь-нибудь поноценное

Веб-приложение

Для примера создадим какой-нибудь простенький чат с выводом последних 10 сообщений. Для рендеринга страницы воспользуемся шаблонизатором erb.

Для начала, установите необходимые гемы (sudo gem install %gemname%): dm-core, dm-migrations, sinatra.

Шапка
Подключаем необходимые заголовки:

<pre>#! /usr/bin/env ruby
#coding: UTF-8

require 'dm-core' # DataMapper
require 'dm-migrations' # Управление БД
require 'dm-sqlite-adapter' # sqlite3
require 'erb' # Шаблонизатор
require 'sinatra' # Веб-фреймворк
</pre>

Данные
Создаем модель:

<pre># Для примера можно хранить БД в папке с приложением
DataMapper.setup(:default, "sqlite://#{Dir.pwd}/chat.db")

# Модель сообщения
class Post
  include DataMapper::Resource

  property :id,    Serial
  property :by,    String
  property :text,  String
end

# Мы закончили модели
DataMapper.finalize

# При запуске создаем чистую БД
DataMapper.auto_migrate!
</pre>

Шаблон страницы
Фактически, чистый html, лишь для последних 10 сообщений создаем новый <p>-тег с ними.

<pre>index_template = %{
  <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
  <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ru" lang="ru">
    <head>
      <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
      <title>Ruby Chat</title>
      <link rel="stylesheet" type="text/css" media="screen" href="style.css"/>
    </head>
    <body>
      <div class="page">
        <h1>iConversation 2.7.1828b Diamond Edition</h1>
        <% Post.slice(0,9).each do |post| %>
          <p><b><%= post.by %>: </b><%= post.text %></p>
        <% end %>
        <form action="/" method="post">
          Nick:
          <input type="text" name="by"   size="10" maxlength="10" />
          Message:
          <input type="text" name="text" size="40" maxlength="60" />
          <input type="submit" value="Send" />
        </form>
      </div>
    </body>
  </html>
}.gsub(/^  /, '')

index = ERB.new(index_template)
</pre>

Веб-ядро
Обрабатываем переход на сайт (get-запрос) и отправку формы (post-запрос):

<pre>get '/' do
  # Показываем страницу по шаблону
  index.result
end

post '/' do
  # Новое сообщение
  @post = Post.first_or_create(
    :by => params[:by],
    # Осторожно — неэкранированные строки!
    :text => params[:text]
  )
  # Показываем страницу по шаблону
  index.result
end
</pre>

Сохраним приложение как app.rb.

Развертывание

Само приложение готово. Для готовности к развертыванию на каких-нибудь виртуальных серверах в будущем необходимо в директорию с приложением добавить пару конфигурационных файлов:

config.ru
<pre>require './app.rb'

run Sinatra::Application
</pre>

Rakefile
<pre>require './app.rb'

desc 'Migrate DataMapper database'
task :migrate do
  DataMapper.auto_migrate!
end
</pre>

.gems
<pre>dm-core --version 1.0.2
dm-migrations --version 1.0.2
dm-sqlite-adapter --version 1.0.2
sinatra --version 1.1.0
</pre>

Осталось выполнить sudo /opt/nginx/sbin/nginx, чтобы запустить сервер, и перейти по адресу http://localhost/.

Результат



1 комментарий

avatar
попробовала.переход на http:/localhost/ отзывается шибкой 403 -Forbidden
какая самая возможная причина?
первый раз пытаюсь поднять какой бы то ни было сервер с веб-приложением, вроде все сделала четко — хотя что-то могла и упустить.
спасибо.
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.