Статьи

Возиться с Синатрой

JSFiddle — это сайт, который существует уже давно. Это позволяет вам создать «скрипку», которая в основном представляет собой отдельную страницу HTML, CSS и JavaScript. Они могут быть использованы, чтобы показать конкретную технику или ошибку или просто показать ваши навыки плавной разметки.

В прошлом году появилось еще пара сайтов, которые делают подобное. Сначала был Dabblet, и совсем недавно была выпущена Code Pen . Я подумал, что было бы забавно попробовать клонировать приложение такого типа в Синатре. Это должно быть довольно просто, поскольку Синатра использует Tilt для визуализации представлений. Это дает вам доступ к множеству различных движков рендеринга, а также к Sass и Less для предварительной обработки CSS.

Моя идея состоит в том, чтобы создать простое приложение под названием Riddle (Fiddle со вкусом Ruby), которое позволяет пользователям создавать «загадки», которые по сути представляют собой отдельный фрагмент HTML, CSS и JavaScript. Для начала я собираюсь ограничить пользователей использованием разметки или старого HTML для разметки и SCSS или ванильного CSS для стилизации. Надеюсь, это поможет показать, как работают помощники вида в Sinatra и как обслуживать CSS и JavaScript с помощью Sinatra.

Макет

Я хотел получить правильную архитектуру сайта приложения, поэтому сначала сосредоточился на представлениях, чтобы показать, как пользователь будет перемещаться по приложению. Нам нужна стартовая страница, которая перечисляет все созданные загадки и позволяет пользователю щелкнуть их, чтобы просмотреть. Там также должна быть кнопка вверху, чтобы создать новую загадку. Это должно отобразить форму, где вы можете добавить HTML, CSS и JavaSript. Как только пользователь нажмет кнопку «Сохранить», он будет переведен во вновь созданное представление.

Итак, приступим к кодированию! Нам нужно начать с создания пустого текстового файла с именем main.rb и добавить следующие строки кода:

require ‘sinatra’
require ‘sass’
require ‘slim’
get(‘/css/styles.css’){ scss :styles }
get ‘/’ do
slim :index
end
get ‘/new/riddle’ do
slim :new
end
post ‘/riddle’ do
slim :show
end
__END__
@@layout
doctype html
html lang=»en»
head
title== @title || ‘Riddle’
meta charset=»utf-8″
link rel=»stylesheet» href=»/css/styles.css»
body
header role=»banner»
h1
a href=’/’ Riddle
a href=’/new/riddle’ New Riddle
#main.content
== yield
@@index
h1 Index Page
p This will list all of the riddles
@@new
form action=»/riddle» method=»POST»
label for=»title» Title
input#title name=»riddle[title]»
label for=»html» HTML
textarea#html cols=60 rows=10
label for=»css» CSS
textarea#css cols=60 rows=10
label for=»js» JS
textarea#js cols=60 rows=10
input.button type=»submit» value=»Save»
@@show
h1 Riddle Show page
p This will show the riddle
@@styles
form label {display: block;}

view raw
gistfile1.rb
hosted with ❤ by GitHub

Что тут происходит? Это полное приложение Sinatra, все в одном файле. Прежде всего, нам нужны синатра и тонкие драгоценные камни. Slim — мой предпочтительный видовой движок, но вы можете использовать другой (например, ERB или Haml). Далее у нас есть три маршрута, которые нам нужны — indexnewshow Затем, в нижней части страницы, я включил эти представления в линию (классная функция Синатры!). Первый — это стандартный макет HTML5. Следуя макету, есть три удерживающие страницы, которые просто описывают, что эта страница в конечном итоге сделает.

Попробуйте — запустите сервер, набрав в терминале ruby main.rb

Мне нравится это в Синатре — вы можете быстро смоделировать архитектуру сайта, чтобы продемонстрировать, как пользователь будет перемещаться по приложению. Используя эту функцию, легко убедиться, что она соответствует вашим ожиданиям, прежде чем приступить к выполнению тяжелых работ.

Все работает отлично, теперь пришло время начать создавать некоторые загадки — для этого нам понадобится база данных …

Создание некоторых загадок

Теперь у нас есть структура приложения, пришло время создать базу данных, которая будет содержать информацию о Загадках. Для этого нам сначала нужно настроить базу данных. Я собираюсь использовать DataMapper в качестве ORM, который очень легко настроить в Sinatra. Просто добавьте следующие строки в начало main.rb:

require ‘sinatra’
require ‘dm-core’
require ‘dm-migrations’
require ‘sass’
require ‘slim’
configure do
DataMapper.setup(:default, ENV[‘DATABASE_URL’] || File.join(«sqlite3://»,settings.root, «development.db»))
end

view raw
gistfile1.rb
hosted with ❤ by GitHub

Нам нужно довольно много дополнительных гемов, чтобы заставить работать DataMapper. Это происходит главным образом потому, что он достаточно модульный по конструкции — это хорошо, так как это означает, что вы можете выбирать, какие модули вы хотите включить для каждого проекта. Мы собираемся использовать модуль миграции позже для создания базы данных. Нам также необходимо настроить базу данных. Это делается внутри блока configure Это настраивает нас на использование Heroku для последующего развертывания, поскольку их базы данных хранятся в переменной среды, называемой ENV [‘DATABASE_URL’]. Если этого нет, то мы должны работать локально, поэтому вместо него будет использоваться файл SQLite.

Наша следующая работа — создать класс Riddle.

class Riddle
include DataMapper::Resource
property :id, Serial
property :title, String
property :html, Text
property :css, Text
property :js, Text
def title=(value)
super(value.empty? ? «Yet another untitled Riddle» : value)
end
end
DataMapper.finalize

view raw
gistfile1.rb
hosted with ❤ by GitHub

Это все довольно стандартные вещи DataMapper. Вам необходимо включить модуль DataMapper::Resourceid Далее у нас есть свойства каждого Riddle — у них будет заголовок, немного HTML, CSS и JavaScript. После этого я добавил дополнительный метод, который устанавливает заголовок «Еще одна загадка без названия», если вводится пустая строка. DataMapper имеет опцию по умолчанию, но это бесполезно при работе с формами в Интернете, потому что любые пустые поля попадают в базу данных как пустые строки, а не как ноль. Это один из способов справиться с этим.

Очень важно не забывать использовать объявление DataMapper.finalize Все идет плохо, если ты этого не делаешь (не могу сказать, сколько раз я забыл это!)

Пришло время перенести базу данных. Это простая работа, все, что нам нужно сделать, это зайти в терминал и перейти к папке, где находится наше приложение-загадка, а затем запустить сеанс irb:

 $ irb ruby-1.9.2-p180 :001 > require './main' ruby-1.9.2-p180 :001 > DataMapper.auto_migrate! 

Теперь база данных создана, нам нужно обновить наши маршруты, чтобы мы могли создать загадку.

get ‘/riddle/:id’ do
@riddle = Riddle.get(params[:id])
slim :show
end
post ‘/riddle’ do
riddle = Riddle.create(params[:riddle])
redirect to(«/riddle/#{riddle.id}«)
end

view raw
gistfile1.rb
hosted with ❤ by GitHub

Нам также необходимо обновить наш вид show Мы только собираемся отобразить то, что было сохранено, вместо того, чтобы пока отображать его как фактический HTML, CSS и JavaScript, просто чтобы убедиться, что все работает:

@@show
h1== @riddle.title
h2 Markup
== @riddle.html
h2 Styles
== @riddle.css
h2 Javascript
== @riddle.js
@@new
form action=«/riddle» method=«POST»
label for=«title» Title
input#title name=»riddle[title]»
label for=«html» HTML
textarea#html cols=60 rows=10 name=»riddle[html]»
label for=«css» CSS
textarea#css cols=60 rows=10 name=»riddle[css]»
label for=«js» JS
textarea#js cols=60 rows=10 name=»riddle[js]»
input.button type=«submit» value=«Save»

view raw
gistfile1.rb
hosted with ❤ by GitHub

Изменение формы добавляет имя к элементам формы. Они подобраны нашим приложением Sinatra и использованы в следующей строке для создания загадки:

 riddle = Riddle.create(params[:riddle]) 

Пройдите тестирование, и вы увидите, что оно работает — все сохраняется в базе данных, а затем отображается на странице show

Прежде чем мы продолжим, давайте просто обновим страницу index Просто добавьте строку в обработчик, чтобы получить все загадки в обратном порядке:

get ‘/’ do
@riddles = Riddle.all.reverse
slim :index
end

view raw
gistfile1.rb
hosted with ❤ by GitHub

Затем нам просто нужно обновить индексное представление, чтобы оно отображало все загадки (при условии, что они есть):

@@index
if @riddles
@riddles.each do |riddle|
li
a href=«/riddle/#{riddle.id}«== riddle.title
else
p No riddles have been created yet!

view raw
gistfile1.rb
hosted with ❤ by GitHub

Brilliant! Перезагрузите сервер (нажмите control + c в терминале, затем введите ruby main.rb Теперь нам просто нужно заставить их работать правильно …

Собираем все вместе

Теперь, когда мы знаем, что загадки сохраняются, пришло время подумать о том, как они отображаются. Давайте обновим представление «@@ show», чтобы оно отображало заголовок загадки и отображало HTML-код внизу:

@@show
h1== @riddle.title
#riddle
== @riddle.html

view raw
gistfile1.rb
hosted with ❤ by GitHub

Дайте это тест, и он должен правильно отображать HTML. Мы можем сделать это немного лучше, используя Tilt, чтобы использовать Markdown для отображения разметки. Это позволит людям использовать более простой язык уценки. Хорошо, что в этом случае, если вы введете только ванильный HTML, уценка все равно будет отображаться. Это позволяет пользователю выбрать использовать уценку или HTML. Чтобы использовать уценку, вам нужно включить библиотеку, которая поддерживает это, я собираюсь для Red Carpet:

 require 'redcarpet' 

Затем все, что вам нужно сделать, это обновить представление show, чтобы использовать помощник Sinatra для отображения разметки с использованием markdown:

@@show
h1== @riddle.title
#riddle
== markdown @riddle.html

view raw
gistfile1.rb
hosted with ❤ by GitHub

Попробуйте — вот несколько уценок, которые вы можете ввести в качестве быстрого теста:

 # Hello ## world * one * two * three 

Теперь, когда мы можем отобразить разметку, пришло время заставить стили работать …

Мы собираемся вставить стили загадки, как будто это фактическая таблица стилей в заголовке документа. Нам нужно добавить следующую строку в @@layout

 - if @riddle link rel="stylesheet" href="/css/riddle/#{@riddle.id}/styles.css" 

Это проверяет, есть ли объект @riddle, а затем ссылается на таблицу стилей, которая содержит идентификатор загадки. Эта таблица стилей на самом деле не существует как фактический файл — она ​​находится в базе данных — но мы можем извлечь ее, как если бы она использовалась с помощью классного и простого механизма маршрутизации Sinatra:

get ‘/css/riddle/:id/styles.css’ do
riddle = Riddle.get(params[:id])
scss «#riddle #{riddle.css}«
end

view raw
gistfile1.rb
hosted with ❤ by GitHub

Когда ссылка вызывается, Sinatra будет обслуживать стили, хранящиеся в базе данных, используя помощника SCSS. Причина, по которой я использовал SCSS, заключается в том, что я добавил идентификатор «#riddle» перед стилями. Механизм SCSS теперь будет именовать пространство всех стилей и помещать перед ними идентификатор «#riddle», что означает, что эти стили будут влиять только на что-либо внутри #riddle div (обратите внимание, что разметка HTMl для загадки была помещена внутри div с идентификатором ‘riddle’ в представлении show. Другими словами, эти стили будут влиять только на загадку!)

Проведите это быстрое тестирование, и вы увидите, что оно работает как положено Круто то, что это выглядит так, как будто это ссылка на внешнюю таблицу стилей — вы даже можете просмотреть стили, перейдя по ссылке «http: // localhost: 4567 / css / riddle / 9 / styles.css». Это также означает, что пользователь может выбрать использование простого CSS или SCSS.

И наконец, давайте включим JavaScript. По аналогии с CSS, мы собираемся сделать так, чтобы он выглядел так, как будто он исходит из внешнего файла, поэтому нам нужна дополнительная строка в макете @@:

 - if @riddle link rel="stylesheet" href="/css/riddle/#{@riddle.id}/styles.css" script src="/js/riddle/#{@riddle.id}/script.js" 

Это загрузит скрипт, который ссылается на идентификатор загадки, если существует объект @riddle. Теперь нам просто нужен обработчик, чтобы справиться с этим:

get ‘/js/riddle/:id/script.js’ do
riddle = Riddle.get(params[:id])
content_type ‘text/javascript’
render :str, riddle.js, :layout => false
end

view raw
gistfile1.rb
hosted with ❤ by GitHub

Нам нужно сделать немного больше здесь. Ранее, когда мы отображали стили, Синатра знал, что тип контента является таблицей стилей, потому что мы использовали помощника SCSS. На этот раз нам нужно явно объявить, что файл является JavaScript. Мы также должны убедиться, что макет больше не используется.

Дайте это тест, и он должен работать отлично. Вскоре нам удалось создать способ создания страниц с использованием HTML, CSS и JavaScript. В качестве дополнительного бонуса, он поддерживает уценку и SCSS из коробки! И все это в более чем 100 строках кода Ruby!

Но мы можем сделать больше! В следующей части я собираюсь ускорить процесс, раскрыв полную силу Tilt и предоставив пользователю возможность выбрать любой из движков представления… включая CoffeeScript! Я также включу возможность редактировать Загадки после того, как они были созданы. Надеюсь вскоре увидеть вас во второй части!