Статьи

Фабрика роботов – часть первая

Роботы

Добавление и удаление ресурсов в Синатре

В этом уроке я расскажу, как использовать 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 … но это будет ждать до второй части этого урока!

В то же время, провернуть несколько роботов, чтобы держать вас в компании …