Добавление и удаление ресурсов в Синатре
В этом уроке я расскажу, как использовать Sinatra для добавления и удаления ресурсов в базу данных и из нее.
Чтобы продемонстрировать это, я собираюсь создать крошечное веб-приложение под названием The Robot Factory, которое позволяет пользователям «создавать» производственную линию роботов. Каждый робот будет сохранен в базе данных с произвольно выбранной головой, телом и ногами, а также может быть удален после его сборки. Вы можете увидеть окончательную версию здесь — http://robotfactory.heroku.com/ . Вы также можете увидеть весь готовый код здесь — https://gist.github.com/1110005 .
Чтобы следовать этому руководству, вам необходимо установить следующие гемы:
$ gem install sinatra data_mapper sqlite3 dm-sqlite-adapter slim sass
Перед тем, как начать, я использовал блестящий Inkscape, чтобы нарисовать некоторые классные части робота, а затем сохранил их как top1.png, top2.png, middle1.png… и т. Д. Вы можете найти все файлы здесь , но можете свободно создавать свои собственные изображения, используя те же соглашения об именах.
Сборка приложения
Все в этом приложении будет в одном файле, поэтому откройте ваш любимый текстовый редактор и сохраните файл как `main.rb`. Для начала нам нужно несколько гемов и настроить базу данных в DataMapper.
%w[sinatra dm-core dm-migrations slim sass].each{ |lib| require lib }
DataMapper.setup(:default, ENV['DATABASE_URL'] || File.join("sqlite3://",settings.root, "development.db"))
Далее идет класс роботов. Как видите, класс робота имеет 4 свойства: автоматически увеличивающийся идентификатор и 3 целых числа, которые соответствуют верхнему, среднему и нижнему изображениям. Эти целые числа генерируются с помощью Proc, чтобы установить значение по умолчанию в качестве случайного числа, которое соответствует количеству верхних, средних и нижних изображений:
class Robot
include DataMapper::Resource
property :id, Serial
property :top, Integer, :default => proc { |m,p| 1+rand(6) }
property :middle, Integer, :default => proc { |m,p| 1+rand(4) }
property :bottom, Integer, :default => proc { |m,p| 1+rand(5) }
end
DataMapper.finalize
Теперь, когда модель Robot настроена, ее необходимо перенести в базу данных. Откройте терминал и перейдите в папку, в которой вы сохранили файл main.rb, затем введите следующее:
$> irb
ruby-1.9.2-p180 :002 > require './main'
=> true
ruby-1.9.2-p180 :003 > Robot.auto_migrate!
=> true
Обработчики маршрутов
Следующая задача — создать обработчики маршрутов. Первый позволяет писать CSS как inline-views в одном и том же документе.
get('/styles.css'){ scss :styles }
Далее мы создадим три основных обработчика. Первая — это индексная страница, которая на самом деле является единственной страницей на фабрике роботов. Он получает все объекты робота в базе данных и сохраняет их в виде массива в переменной экземпляра @robots, к которой можно получить доступ в представлениях. Вторая касается запроса на публикацию, который выполняется при нажатии кнопки «BUILD A ROBOT». Это создаст нового робота, а затем перенаправит обратно на страницу индекса, где новый робот станет частью массива @robots. Последний обработчик имеет дело с удалением роботов. Он находит робота, который был удален, используя часть URL-адреса :id
Затем он перенаправляет обратно на страницу индекса, где этот робот больше не будет частью массива @robots.
get '/' do
@robots = Robot.all
slim :index
end
post '/build/robot' do
robot=Robot.create
redirect to('/')
end
delete '/delete/robot/:id' do
Robot.get(params[:id]).destroy
redirect to('/')
end
__END__
Взгляды
Теперь пришло время для некоторых взглядов. В этом примере я решил использовать встроенные представления, чтобы они могли быть включены в один файл. Я также использую замечательный язык шаблонов Slim, чтобы писать на них.
Первый — это довольно стандартный макет HTML 5. Я также включил ссылку на некоторые шрифты из Google Web Font Directory, которые я буду использовать в CSS позже.
@@layout
doctype html
html
head
meta charset="utf-8"
title Robot Factory
link rel="shortcut icon" href="/fav.ico"
link href="http://fonts.googleapis.com/css?family=Megrim|Ubuntu&v2" rel='stylesheet'
link rel="stylesheet" media="screen, projection" href="/styles.css"
/[if lt IE 9]
script src="http://html5shiv.googlecode.com/svn/trunk/html5.js"
body == yield
footer role="contentinfo"
p Building Quality Robots since 2011
Следующим представлением является страница индекса, которая является единственной страницей в приложении. В основном это кнопка внутри формы, которая нажимается для создания робота, а также список роботов, если таковые имеются. Если роботов еще не существует, появится сообщение о том, что вы должны их создать. Я разделил код для робота в отдельном представлении и включил его как частичный ( ==slim :robot, :locals => { :robot => robot }
@@index
h1 Robot Factory
form.build action="/build/robot" method="POST"
input.button type="submit" value="Build A Robot!"
-if @robots.any?
ul#robots - @robots.each do |robot|
==slim :robot, :locals =>; { :robot =>; robot }
- else
h2 You Need To Build Some Robots!
Код для робота помещает три изображения, которые формируют его тело, внутри элемента списка. В конце также есть форма, которая используется для кнопки удаления. Это должно быть частью формы, чтобы можно было использовать правильный HTTP-глагол DELETE (обратите внимание на скрытое поле формы, которое используется, чтобы сообщить Синатре, что на самом деле это запрос DELETE).
@@robot
li.robot
img src="https://s3.amazonaws.com/daz4126/top#{robot.top}.png"
img src="https://s3.amazonaws.com/daz4126/middle#{robot.middle}.png"
img src="https://s3.amazonaws.com/daz4126/bottom#{robot.bottom}.png"
form.destroy action="/delete/robot/#{robot.id}" method="POST"
input type="hidden" name="_method" value="DELETE"
input type="submit" value="×"
Приложение теперь полностью завершено и будет отлично работать, хотя и не очень хорошо. Основная проблема заключается в том, что изображения, из которых состоят роботы, отображаются рядом, а не вертикально друг над другом, как предполагалось.
Добавление некоторого стиля
Это все разбирается с применением некоторых стилей. Ранее мы добавили обработчик, который позволял нам помещать наш CSS в представления, так как мы используем встроенные представления, он просто идет под другими представлениями в том же файле:
@@styles
html,body,div,span,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote, pre,abbr,address,cite,code,del,dfn,em,img,ins,kbd,q,samp,small,strong,sub,sup,var,b,i,dl,dt, dd,ol,ul,li,fieldset,form,label,legend,table,caption,tbody,tfoot,thead,tr,th,td,article, aside, canvas, details,figcaption,figure,footer,header,hgroup,menu,nav,section, summary,time,mark,audio,video {
margin:0;
padding:0;
border:0;
outline:0;
font-size:100%;
vertical-align:
baseline;
background:transparent;
line-height:1;
}
body{font-family:ubuntu,sans;}
footer {
display:block;
margin-top:20px;
border-top:3px solid #4b947d;
padding:10px;
}
h1 {
color:#95524C;
margin:5px 40px;
font-size:72px;
font-weight:bold;
font-family:Megrim,sans;
}
.button {
background:#4b7194;
color:#fff;
text-transform:uppercase;
border-radius:12px;
border:none;
font-weight:bold;
font-size:16px;
padding: 6px 12px;
margin-left:40px;
cursor:pointer;
&:hover{background:#54A0E7;}
}
#robots {
list-style:none;
overflow:hidden;
margin:20px;
}
.robot {
float:left;
width:100px;
padding:10px 0;
position:relative;
form {
display:none;
position:absolute;
top:0;
right:0;
}
&:hover form {
display:block;
}
form input {
background:rgba(#000,0.7);
padding:0 4px;
color:white;
cursor:pointer;
font-size:32px;
font-weight:bold;
text-decoration:none;
border-radius:16px;
line-height:0.8;
border:none;
}
img {
display:block;
padding:0 10px;
}
}
Это все очень стандартные вещи. Он начинается с базового сброса, затем устанавливает все шрифты и цвета для основного текста, нижнего колонтитула и заголовков. Кнопка «Построить робота» разработана так, чтобы она была красивой, яркой и округлой (как и все хорошие кнопки Web 2.0). Роботы перемещаются влево, поэтому они будут отображаться рядом и изображения будут отображаться: блок, который заставляет их сидеть друг над другом. Форма, содержащая кнопку удаления, устанавливается скрытой, если только робот не находится над ней. Он также был стилизован под стандартную кнопку «удалить».
Приложение теперь работает и выглядит так, как должно, но некоторые страницы перезагружаются каждый раз, когда вы пытаетесь создать или уничтожить робота, что замедляет весь процесс. Это похоже на работу для XMLHttpRequest … но это будет ждать до второй части этого урока!
В то же время, провернуть несколько роботов, чтобы держать вас в компании …