- планировать деплой приложения
- писать приложение с использованием фреймворка и orm
- вам нужно, чтобы ваше приложение стало доступно в интернете. Как это сделать?
- (вспомним) что такое фреймворк
- (вспомним) что такое orm
Прежде, чем попробовать самый популярный ruby-фреймворк Ruby on Rails и ORM ActiveRecord, попробуем поработать с другими.
Это расширит кругозор и позволит лучше понимать, что происходит в веб-приложении.
[Создадим приложение на основе тудулиста, который делали на занятии недели "8. Базы данных".] Также будем использовать ORM Sequel, которая облегчит нам работу с субд.
Если не проходили урок недели 8, но есть опыт с базами данных, также можете сразу проходить этот урок.
Для работы понадобится субд sqlite.
Установите, если не установлена:
sudo apt install sqlite3Создайте отдельную директорию для проекта, в ней создайте Gemfile:
source "https://rubygems.org"
gem "sinatra"
gem "rerun" # для автоматического перезапуска при изменении кода
Добавьте гем для запуска (который использовали в прошлом уроке):
gem "puma"
# либо
gem "thin"
# либо
gem "rackup"
Установите гемы: bundle install
Для начала напишем hello world с использованием фреймворка Sinatra.
# app.rb (в этом файле будем писать код)
require 'sinatra'
get '/' do
'Hello world!'
endСоздайте config.ru (аналогично rack-приложению, к-е делали на прошлом занятии)
require './app'
run Sinatra::Application(c rerun чтобы каждый раз не перезагружать приложение):
# с пумой
bundle exec rerun bundle exec puma
# c thin
bundle exec rerun bundle exec thin
# с rackup
bundle exec rerun bundle exec rackup
# напрямую
bundle exec rerun bundle exec ruby app.rbЧтобы не запускать длинной командой.
Дописать в ~/.bash_aliases - например:
alias rpum="bundle exec rerun bundle exec puma"
Выполнить source ~/.bash_aliases (команда в консоли, чтобы сразу применилось)
Далее при запуске подсистемы алиасы будут сами назначаться из этого файла.
Запускать можно будет: rpum
Название алиаса и команда могут быть любыми
Создадим отдельный эндпоинт, в котором выведем параметры от пользователя:
# app.rb
get '/params' do
# вывод в консоли
puts params.inspect
# вывод в ответе (будет в браузере)
params.inspect
endВ браузере добавьте параметры в строку запроса, например: "http://localhost:9292?user=anna&search=ruby". Параметры будут показаны в консоли + в браузере. Попробуйте с другими параметрами.
Можно также создать отдельный эндпоинт:
# app.rb
get '/env' do
env.inspect
endПараметры и информацию из env мы можем получить в любом эндпоинте (сейчас они описаны в блоках get ... do). Соответственно, вы можете попробовать посмотреть params и env в разных блоках.
(который мы уже пробовали)
Добавим:
gem "erb"
Создадим в проекте папку views и в ней layout.erb , это будет наш шаблон.
Напишем html шаблона layout.
Пример:
<html>
<head>
<meta charset='utf-8' />
<link rel="stylesheet" href="https://cdn.simplecss.org/simple.min.css" />
<title>Список дел</title>
<head>
<body>
<main>
<h1>Список дел</h1>
<%= yield %>
</main>
</body>
</html>Вместо yield фреймворк будет подставлять конкретный view, к-й мы будем рендерить в action (в блоке get .. do).
Чтобы отрендерить конкретный view, нужно написать - erb :название_view (пример - erb :index) (внутри блоков get ... do )
Подробнее про yield (дополнительно)
Создайте тестовый эндпоинт (get '/test' ...), темплейт для него (views/test.erb), в темплейте вывести параметры (params.inspect и env.inspect).
env - это хэш (ассоциативный массив). Например, информацию о методе запроса можно будет получить так: env["REQUEST_METHOD"]
Пример test.erb:
<div>ENV: <%= env.inspect %></div>
<div>Params: <%= params.inspect %></div>
Список запросов, к-е будем принимать:
# главная - тут будет список дел и форма добавления дела
get '/' do
erb :index # рендерим view index
end
# тут будет страница дела
get '/tasks/:id' do
end
# тут создание дела - сюда будем отправлять запрос post, когда будем сабмитить форму
post '/tasks/create' do
end
# здесь будем отмечать дело сделанным/не сделанным
post '/tasks/toggle_done' do
endСоздадим форму для создания дела в файле index.erb
(добавьте поле ввода названия дела и кнопку submit)
Action формы поставим /tasks/create, method - "post"
post '/tasks/create' do
# ... тут будем создавать события
# пока выведем params, к-е приходят от пользователя
params.inspect
endТеперь зайдите на главную и попробуйте создать дело из вашей формы. Вы должны увидеть параметры, которые отправили при сабмите формы. Сохранять пока некуда, займёмся этим на следующем шаге.
Дальше нам нужно написать код для вывода списка дел из бд и создания. Для этого используем базу данных sqlite.
Добавьте гемы в гемфайл:
gem "sqlite3"
gem "sequel"
Установите (bundle install).
(не забудьте перезапустить сервер после установки)
Можно взять бд с прошлого урока и перейти к разделу "Подключим бд к приложению".
Или можно создать базу данных с помощью скрипта:
Создадим файл seeds.rb:
require "sqlite3"
require "sequel"
# подключаемся или создаём бд
DB = Sequel.connect('sqlite://tasks.db')
# создаём таблицу, если её ещё нет
DB.create_table? :tasks do
primary_key :id
String :task
Boolean :done
end
tasks = DB[:tasks] # Create a dataset
# чистим таблицу (на всякий случай)
tasks.delete
# Заполняем (заполните своми данными)
tasks.insert(task: 'Разработать урок', done: false)
tasks.insert(task: 'Провести урок', done: true)
tasks.insert(task: 'Попить чай', done: true)
# Выведем кол-во записей
puts "Всего дел: #{tasks.count}"
# Структура, к-ю получим при запросе всех дел:
tasks.each { |task| puts task.inspect }(Сравните синтаксис с CREATE TABLE из sql и другими запросами)
Запустите, как обычный ruby-код (bundle exec ruby seeds.rb)
Пример из документации sequel (для in-memory database)
# app.rb
require 'sinatra'
require 'sequel'
DB_PATH = 'sqlite://tasks.db'
DB = Sequel.connect(DB_PATH)Выведем задачи в цикле в index.erb (коллекция дел будет в DB[:tasks])
# в блоке get '/' do ... перед erb index.erb
@tasks = DB[:tasks]Инстанс-переменная @tasks будет доступна во view (в index.erb) и мы сможем вывести список дел, используя each:
<ul>
<% @tasks.each do |task| %>
<li>
<%= task[:task] %> - <%= task[:done] ? "сделано" : "не сделано" %>
</li>
<% end %>
</ul>Пропишем создание дел в блоке post '/tasks/create' do
tasks = DB[:tasks]
tasks.insert(...) # подставьте параметры запроса в соотв. с полями бдРедирект после успешного создания:
redirect '/'# get '/tasks:id' do ...
tasks = DB[:tasks]
@task = tasks.first(id: params[:id])
# рендерим
erb :showСоздайте show.erb и там выведите информацию о деле @task.
Проверить можно будет по адресу /tasks/:id, например localhost:9292/tasks/1
Теперь можно поставить в списке дел (index.erb) ссылки на страницы дел (вместо названия):
Пример:
<a href="/tasks/<%= task[:id] %>"><%= task[:task] %></a> - <%= task[:done] ? "сделано" : "не сделано" %>Для того, чтобы отметить дело сделанным, нужно создать форму для каждого дела. Будем отправлять формы методом post, т.к. в результате запроса будут внесены изменения в базу данных.
Обратите внимание на ообенности формы:
action = '/tasks/toggle_done'(наш эндпоинт в app.rb)- скрытое поле (
input type="hidden"), в нём будет передаваться id дела, которое будем обновлять.
Формы добавим в список вывода дел (index.erb) внутри блока each, чтобы форма была создала для каждого task.
Пример формы ниже, submit-кнопка здесь также отображает текущий статус дела, поэтому исходное "сделано/не сделано" можно убрать (также вы можете оформить статус дела, кнопку и остальные детали по своему желанию).
Пример формы:
<form style="display:inline" action="/tasks/toggle_done" method="POST">
<input type="hidden" name="id" value="<%= task[:id] %>" />
<input type="submit" title="Отметить<%= " не" if task[:done] %> сделанным" value="<%= task[:done] ? "❌" : "✅" %>" />
</form># app.rb , блок get "/tasks/toggle_done" do ...
# получаем дело, чтобы проверить, что оно существует + узнать значение done
task = tasks.first(id: params[:id])
# обновляем - если было не сделано, отмечаем сделанным и наоборот
tasks.where(id: params[:id]).update(done: !task[:done])Также нужно поставить редирект после обновления (как после создания).
В примере также добавлена обработка ситуации, когда запись не найдена.
- удаление дел
Туториал по синатре от Railsgirls
Туториал: пишем блог на фреймворке roda
API для вашего проекта