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;} |
Что тут происходит? Это полное приложение Sinatra, все в одном файле. Прежде всего, нам нужны синатра и тонкие драгоценные камни. Slim — мой предпочтительный видовой движок, но вы можете использовать другой (например, ERB или Haml). Далее у нас есть три маршрута, которые нам нужны — index
new
show
Затем, в нижней части страницы, я включил эти представления в линию (классная функция Синатры!). Первый — это стандартный макет 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 |
Нам нужно довольно много дополнительных гемов, чтобы заставить работать 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 |
Это все довольно стандартные вещи DataMapper. Вам необходимо включить модуль DataMapper::Resource
id
Далее у нас есть свойства каждого 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 |
Нам также необходимо обновить наш вид 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» |
Изменение формы добавляет имя к элементам формы. Они подобраны нашим приложением Sinatra и использованы в следующей строке для создания загадки:
riddle = Riddle.create(params[:riddle])
Пройдите тестирование, и вы увидите, что оно работает — все сохраняется в базе данных, а затем отображается на странице show
Прежде чем мы продолжим, давайте просто обновим страницу index
Просто добавьте строку в обработчик, чтобы получить все загадки в обратном порядке:
get ‘/’ do | |
@riddles = Riddle.all.reverse | |
slim :index | |
end |
Затем нам просто нужно обновить индексное представление, чтобы оно отображало все загадки (при условии, что они есть):
@@index | |
— if @riddles | |
— @riddles.each do |riddle| | |
li | |
a href=«/riddle/#{riddle.id}«== riddle.title | |
— else | |
p No riddles have been created yet! |
Brilliant! Перезагрузите сервер (нажмите control + c в терминале, затем введите ruby main.rb
Теперь нам просто нужно заставить их работать правильно …
Собираем все вместе
Теперь, когда мы знаем, что загадки сохраняются, пришло время подумать о том, как они отображаются. Давайте обновим представление «@@ show», чтобы оно отображало заголовок загадки и отображало HTML-код внизу:
@@show | |
h1== @riddle.title | |
#riddle | |
== @riddle.html |
Дайте это тест, и он должен правильно отображать HTML. Мы можем сделать это немного лучше, используя Tilt, чтобы использовать Markdown для отображения разметки. Это позволит людям использовать более простой язык уценки. Хорошо, что в этом случае, если вы введете только ванильный HTML, уценка все равно будет отображаться. Это позволяет пользователю выбрать использовать уценку или HTML. Чтобы использовать уценку, вам нужно включить библиотеку, которая поддерживает это, я собираюсь для Red Carpet:
require 'redcarpet'
Затем все, что вам нужно сделать, это обновить представление show, чтобы использовать помощник Sinatra для отображения разметки с использованием markdown:
@@show | |
h1== @riddle.title | |
#riddle | |
== markdown @riddle.html |
Попробуйте — вот несколько уценок, которые вы можете ввести в качестве быстрого теста:
# 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 |
Когда ссылка вызывается, 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 |
Нам нужно сделать немного больше здесь. Ранее, когда мы отображали стили, Синатра знал, что тип контента является таблицей стилей, потому что мы использовали помощника SCSS. На этот раз нам нужно явно объявить, что файл является JavaScript. Мы также должны убедиться, что макет больше не используется.
Дайте это тест, и он должен работать отлично. Вскоре нам удалось создать способ создания страниц с использованием HTML, CSS и JavaScript. В качестве дополнительного бонуса, он поддерживает уценку и SCSS из коробки! И все это в более чем 100 строках кода Ruby!
Но мы можем сделать больше! В следующей части я собираюсь ускорить процесс, раскрыв полную силу Tilt и предоставив пользователю возможность выбрать любой из движков представления… включая CoffeeScript! Я также включу возможность редактировать Загадки после того, как они были созданы. Надеюсь вскоре увидеть вас во второй части!