Одна из идей, выдвинутых на недавнем саммите Awesome Manchester Hackathon, была выдвинута Томом Окли для простой системы управления контентом, в которой использовался Markdown . Идея не была выбрана в качестве одного из проектов Хакатона, но я подумал, что она отлично подходит для написания на Синатре (он сам по себе легкий и уже имеет поддержку для Markdown). Итак, после того, как хакатон закончился, я решил попробовать его построить.
Я подумал, что было бы интересно (и очень полезно), если бы я задокументировал прогресс, который я сделал на RubySource, так как я продвинулся… так что это первая часть серии!
Моя идея состоит в том, чтобы создать некоторое промежуточное программное обеспечение Sinatra, которое можно прикрепить к проекту, чтобы добавить простую поддержку управления контентом. Я также хочу иметь тегируемые страницы и возможность расширений (таких как модули списков навигации, модули загрузки файлов, модули электронной почты и т. Д.).
MongoDB и Mongoid
Я решил использовать MongoDB для настойчивости. Я использовал это немного в прошлом и думал, что это будет хорошо здесь. MongoDB — это быстрое и масштабируемое хранилище данных NoSQL . Он использует концепцию коллекций документов вместо таблиц и строк. Большим преимуществом является то, что он не имеет схемы и поэтому не требует никаких миграций. Кроме того, вы можете добавлять новые поля на лету (фактически документы в одной коллекции даже не должны иметь одинаковые поля), что делает его очень гибким и подходящим для быстрой разработки.
Я решил использовать Mongoid в качестве ORM, так как мне понравился внешний вид синтаксиса, он хорошо документирован и находится в стадии активной разработки. Я обнаружил, что установка MongoDB локально — это немного болезненно, но документация MongoDB должна помочь вам. Как только он установлен, вам нужно запустить сервер mongod
. Это зависит от операционной системы, поэтому обратитесь к документации о том, как это сделать.
Настройка
Для начала я создал следующий Gemfile:
source "https://rubygems.org" ruby "2.0.0" gem "sinatra" gem "slim" gem "sass" gem "mongoid" gem "redcarpet"
Прежде всего, Mongoid требует как минимум Ruby 1.9.3, поэтому он помогает поместить это в Gemfile (особенно для случая, когда мы перейдем к развертыванию на Heroku позже.) Очевидно, нам нужен Sinatra. Я буду использовать Slim для логики представления и Sass для стилей. Это исключительно мой выбор и мой выбор по умолчанию в настоящее время. Честно говоря, не будет такого большого стиля, но всегда проще использовать Sass. Я уже упоминал Mongoid, которая оставляет Red Carpet — реализацию уценки, созданную добрыми людьми из GitHub.
Чтобы убедиться, что все установлено, запустите bundle install
из командной строки.
Mongoid также требует немного настройки. Для этого создайте файл с именем mongoid.yml и сохраните его в том же каталоге. Вот настройки по умолчанию, которые я нашел подходящими для начала работы с Mongoid:
development: sessions: default: database: cms hosts: - localhost:27017 production: sessions: default: uri: <%= ENV['MONGOHQ<em>URL'] %> options: skip_version_check: true safe: true
В том же каталоге нам нужно создать файл с именем main.rb, куда пойдут наши основные функции. Чтобы все пошло как по маслу, я решил погрузиться и создать классическое приложение, а позже перенесу его в модульное. В начале main.rb нам нужно запросить соответствующие гемы и настроить Mongoid:
require 'sinatra' require 'sinatra/reloader' if development? require 'mongoid' require 'slim' require 'redcarpet' configure do Mongoid.load!("./mongoid.yml") end
Класс страницы
Теперь мы переходим к сердцу нашей CMS — модели страницы. Начнем с простого — дайте ему заголовок и поле содержимого:
class Page include Mongoid::Document field :title, type: String field :content, type: String end
Чтобы использовать Mongoid в классе, все, что вам нужно сделать, это включить модель Mongoid::Document
. После этого вы можете определить поля, которые будут использоваться в базе данных. Наши два поля — это «заголовок» и «контент», и оба они имеют тип string. Теперь мы можем попробовать создать несколько страниц!
Создать несколько страниц
У нас пока нет определенных маршрутов, но это не значит, что мы не можем создавать страницы. Всегда полезно иметь возможность запускать нашу программу через консоль. Откройте терминал и запустите IRB, используя следующую команду:
$> irb
Это должно дать вам приглашение ruby, похожее на приведенное ниже, где нам может потребоваться файл main.rb:
2.0.0-p0 :001 > require './main' => true
Теперь мы можем добавить несколько страниц:
2.0.0-p0 :002 > hello = Page.new => # 2.0.0-p0 :003 > hello.title = "Hello World!" => "Hello World!" 2.0.0-p0 :004 > hello.content = " This is our first page " => " This is our first page " 2.0.0-p0 :005 > hello.save => true
Мы только что создали нашу первую страницу! Это делается с использованием new
метода. Мы назначаем страницу переменной hello
. У этого есть методы установки title
и content
обеспеченного Mongoid. После того, как они были установлены, мы используем метод save
для фиксации изменений в базе данных.
Вместо того, чтобы записывать каждое свойство по одному и затем сохранять объект, мы можем создать документ в базе данных в одну строку, используя метод create
:
2.0.0-p0 :006 > Page.create(title: "Markdown Page", content: "This page uses markdown") => #
Мы можем проверить, что страницы были созданы путем запроса базы данных. Прежде всего, давайте проверим, сколько страниц было сохранено, используя метод count
:
2.0.0p0 :007 > Page.count => 2
Это хорошая новость — в базе данных сохранено 2 страницы, как мы и ожидали. Существует множество способов поиска страниц с использованием Mongoid. Вот несколько запросов, которые мы могли бы использовать:
2.0.0p0 :009 > Page.first => # Page.last => #, title: "Hello World!", content: " This is our first page ">
first
и last
методы работают точно так же, как говорят на банке, и находят первый и последний документы в базе данных соответственно. Мы также можем найти конкретный документ, используя метод find
со строкой id документа в качестве аргумента:
2.0.0p0 :011 > Page.find("5173f574a39401776a000002") => #
Возможно, мы не всегда знаем идентификатор документа, поэтому мы также можем искать по разным полям, используя методы find_by
и where
:
2.0.0p0 :012 > Page.find_by(title: "Hello World!") => #This is our first page "> 2.0.0p0 :013 > Page.where(title: "Hello World!").first => #This is our first page ">
Хотя они выглядят одинаково, есть find_by
разница: find_by
возвращает объект Page, тогда как where
возвращает критерий MongoDB, который является прокси-объектом, который можно объединить в цепочку. Он не запрашивает базу данных, пока не будут выполнены все критерии.
Просмотр страниц
Теперь, когда у нас есть несколько страниц, давайте создадим несколько маршрутов и видов, чтобы мы могли их видеть!
Прежде всего, мы создадим страницу индекса, которая перечисляет все страницы в базе данных. Добавьте следующий маршрут в конец main.rb:
get '/pages' do @pages = Page.all @title = "Simple CMS: Page List" slim :index end
Это находит все страницы в базе данных и сохраняет их в виде массива в неизменяемом экземпляре @pages
. Мы также используем переменную экземпляра @title
для хранения заголовка страницы (это будет использоваться в представлении макета). Затем мы визуализируем представление, называемое index, используя slim.
Нам нужно создать это представление сейчас. Создайте файл с именем index.slim и сохраните его в папке с именем views в корневом каталоге. Поместите следующий код в этот файл:
h1 Pages -if @pages.any? ul.pages - @pages.each do |page| == slim :page, :locals => {page: page} - else p No pages here!
Это просто список всех страниц, но он использует часть для отображения фактической информации о каждой странице в строке == slim :page, :locals => {page: page}
. Это означает, что нам нужно создать другое представление с именем page.slim (также сохраненное в папке views), содержащее следующий код:
li a href="/pages/#{page.id}" =page.title
Это не большая часть, но имеет смысл хранить ее в отдельном файле, так как мы можем захотеть добавить больше информации к тому, что мы разместим здесь позже, или использовать ее в других представлениях.
Часть страницы имела ссылку на каждую отдельную страницу. Нам нужно написать обработчик маршрута, чтобы справиться с этим. Это используется для отображения каждой отдельной страницы — поместите следующий код ниже:
get '/pages/:id' do @page = Page.find(params[:id]) @title = @page.title slim :show end
Он находит страницу на основе идентификатора, @page
в URL, и создает переменную экземпляра с именем @page
для хранения объекта Page
. Мы также сохраняем заголовок страницы в переменной экземпляра @title
.
Далее, давайте создадим страницу для просмотра реальной страницы. Сохраните следующий код в каталоге views как ‘show.slim’:
h1= @page.title - if @page.content == markdown @page.content
Это очень простое представление, которое показывает заголовок в качестве заголовка уровня 1 и использует метод markdown
для отображения содержимого (если оно действительно есть). Обратите внимание, что оба они являются методами переменной экземпляра @page
созданной в обработчике маршрута.
Прежде чем мы протестируем это, нам нужно создать макет для приложения. Вот базовый макет HTML5, который отлично подойдет:
doctype html html head title= @title || "Simple Sinatra CMS" body h1 a href="/pages" Simple Sinatra CMS == yield
Сохраните приведенный выше фрагмент кода как «layout.slim» в каталоге views, затем запустите сервер, введя ruby main.rb
в терминал, затем перейдите по адресу http: // localhost: 4567 / pages в вашем браузере, и вы должны увидеть список страниц, аналогичный следующему:
Попробуй перемещаться по всем страницам!
Создание страниц
Это было весело, но у нас есть только две страницы, поэтому нам нужно создавать больше … и в браузере тоже.
Прежде всего, нам нужно создать обработчик маршрута для страницы, на которую мы добавим новую страницу. Добавьте следующий код в «main.rb», но убедитесь, что он идет перед маршрутом «/ pages /: id» (это потому, что Sinatra всегда ищет первый маршрут, который соответствует URL и «/ pages /: id» соответствует ‘/ pages / new’, установив params [: id] в ‘new’):
get '/pages/new' do @page = Page.new slim :new end
Это просто создает новый объект страницы и сохраняет его в переменной экземпляра @page
, которая будет доступна в представлении. Возможно, нам сейчас не понадобится этот объект, но в будущем мы можем использовать ту же форму для редактирования страницы, что и для создания новой. Форма редактирования будет содержать ссылки на редактируемую страницу, которая будет переменной экземпляра @page
. Если бы этого не было, мы бы получили ошибки, поэтому мы просто создаем новый объект Page
чтобы избежать этого.
Затем мы отображаем новый вид, который нам лучше создать в папке ‘views’, вот код:
h1 New Page form action="/pages" method="POST" fieldset legend Create a new page == slim :form input type="submit" value="Create"
Это использует частичное для фактической формы (поэтому мы можем повторно использовать его на странице редактирования). Нам также нужно сохранить следующее как «form.slim»:
label for="title" Title: input.title type="text" name="page[title]" value="#{@page.title}" size="32" label for="content" Content: textarea.content name="page[content]" rows="12" cols="72" ==@page.content
На данный момент у нас есть только два поля, которые являются обязательными, так что это довольно простая форма. Вы можете видеть ссылки на переменную экземпляра @page
— они будут отображаться как пустые, когда это новая страница.
Теперь нам нужно разобраться, что происходит при отправке этой формы. Мы можем использовать обработчик маршрута, чтобы справиться с этим. Мы используем URL «/ pages», поскольку это то, что было в атрибуте «action» формы. Но в этом случае мы используем HTTP-глагол «post», так как этот метод используется формой при отправке:
post '/pages' do page = Page.create(params[:page]) redirect to("/pages/#{page.id}") end
В этом действии мы создаем новый объект Page
используя метод create
который мы использовали в IRB ранее. params[:page]
— это хэш всех значений, введенных в форму. Затем мы используем полезное redirect
Синатры и методы для перенаправления на URL для вновь созданной страницы.
Теперь, когда все маршруты на месте, нам просто нужно добавить ссылку на страницу индекса, чтобы создать новую страницу. Сделайте следующую строку где-нибудь около вершины index.slim:
a href='/pages/new' Add a new page
Перезагрузите сервер (удерживая Ctrl + C, затем снова введите ruby main
) и попытайтесь создать несколько новых страниц.
Эврика! У нас есть начало нашей простой системы управления контентом. Мы можем создавать новые страницы с помощью Markdown и просматривать их.
Во второй части мы рассмотрим редактирование и удаление страниц, а также способы создания постоянных ссылок с «красивыми URL-адресами» на основе заголовка страницы.
Надеюсь, вам понравился этот пост, пожалуйста, оставьте любой отзыв в разделе комментариев. Мне было бы особенно интересно услышать какие-либо идеи для будущего проекта.