Това ръководство има за цел да ви даде някои насоки ако сте избрали уеб сайт за проект. Повечето от нещата тук са препоръки и със сигурност има повече от един правилен начин да се направят.
Sinatra е DSL, който ви предоставя минимален набор от инструменти за създаване на уеб приложения. За разлика от Rails и други подобни на него, Sinatra не ви дава готова и твърда структура, налагайки ви коя част от кода ви къде да стои. Бихте могли да сложите всичко в един файл (което, разбира се, не трябва да правите).
Най-добрият източник на информация за Sinatra е документацията.
Sinatra, както и повечето frameworks в света на Ruby, използва Rack. Това е много полезно, защото Rack може да бъде разширяван чрез добавяне на посредници (middleware). Силно вероятно е ако ви липсва някаква функционалност, да намерите Rack посредник точно за това. Затова търсете и за rack <feature>
в Google, вместо само sinatra <feature>
. Например Rack::Session::Cookie
добавя възможност за използване на сесия чрез бисквитки.
Щом ще правите уеб приложение е почти сигурно, че ще ви се наложи да използвате някаква база от данни. Конкретната база от данни, която ще изберете, за нас не е от значение.
SQLite е проста за използване SQL база от данни. Не се слави с голяма производителност, но е идеална докато разработвате проекта си, защото се "подкарва" лесно. Единственото, което ви е необходимо, е да добавите gem 'sqlite3'
в Gemfile
-а. Забележка: Ако използвате windows може да се наложи да инсталирате допълнителни неща. Този пост в github може да помогне.
Една база от данни при SQLite е просто един something.sqlite
файл.
ORM (Object-Relational Mapping) библиотеките като ActiveRecord, Sequel, DataMapper и други ви предоставят удобен интерфейс за работа с SQL бази от данни. Ключовите неща са, че (почти) не ви се налага да пишете SQL заявки и можете лесно да превключвате между различни бази от данни (SQLite, PostgreSQL, MySQL и т.н.).
За интегриране на ActiveRecord и Sinatra, може да използвате Sinatra-ActiveRecord. Добро ръководство за ActiveRecord има тук.
Почти всеки ORM ви предоставя възможност да създавате и изпълнявате миграции. Една миграция представлява инструкция за промяна на структурата на база от данни. Например добавяне на таблица, добавяне или премахване на поле от таблица и т.н. Миграцията обикновено е просто Ruby код, който вика специални методи, които впоследствие, при "изпълнение" на миграцията, се транслират до съответните команди към SQL базата данни и така се извършва необходимата промяна.
Ръководство за създаване на ActiveRecord миграции има тук. Единствената разлика при Sinatra-ActiveRecord е, че вместо bin/rails generate migration <име>
, трябва да използвате rake db:create_migration NAME=<име>
.
Изводът от тази секция е, че не трябва да се грижите ръчно за структурата на базата си данни. Това трябва да става само през миграции.
Миграциите могат да се ползват и за промяна на данни, не само на структура. Понякога възниква необходимост от това, като част от промяната на структурата.
Както вече споменахме, Sinatra не ви дава готова файлова структура с инструкции къде какъв код да пишете. Затова е и много лесно да се вземе не чак толкова добър подход.
Хубаво е да си разделите проекта на следните директории:
-
routes
- Вътре слагате ruby файлове, които използват DSL-a на Sinatra. Всеки файл в тази директория отговаря за няколко адреса, свързани логически по някакъв начин. Например вroutes/users.rb
може да се съдържат адресите за регистрация, вход, редакция на потребителски профил и други дейности, свързани с потребители. Ето примерен такъв файл, който съдържа един адрес (users/all
), на който се показва списък от всички потребители на сайта:get '/users/all' do @users = User.all erb :'users/all' # Това е пътят към темплейта в папката `views`. Обърнете внимание на това, че е символ. end
-
models
- Тук е мястото на моделите. Моделите са класове, чиято задача е да си комуникират с базата и да моделират някаква таблица от нея. Обикновено се създава по един клас за всяка такава. Ако използвате ORM, почти няма да ви се налага да добавяте методи към тези класове. Ако не използвате ORM, ще трябва да си създадете методи за нещата, които ще използвате. В горния пример сме използвали класов методall
на моделаUser
. Примерна реализация за този модел може да е следният код:class Users def self.all # Забележка - db е връзката към базата от данни db.execute('select * from users').to_a end end
Горният пример не използва ORM - в ActiveRecord вече имате дефиниран такъв метод, който можете да използвате наготово.
-
views
- Това е мястото за HTML кода. Можете да използвате различни темплейт системи като ERB, HAML и т.н. Разликата е (почти) единствено в начина, по който се вгражда Ruby код в HTML. Целта на всеки template engine е след изпълнение, да се продуцира HTML код. ERB е част от стандартната библиотека и е по-праволинеен и лесен за схващане, затова ако се чудите кое да изберете - използвайте него. Ползва се доста масово. Всеки файл в директориятаviews
съдържа шаблони на HTML страници в съответния формат на template engine-а. Например единerb
файл (views/users/all.erb
) за страницатаusers/all
може да съдържа следното:<h1>Всички потребители</h1> <% if @users.any? %> <ul> <% @users.each do |user| %> <li><%= user.name %></li> <% end %> </ul> <% else %> <p>Все още няма регистрирани потребители.</p> <% end %>
Хубаво е файловете да бъдат групирани по това за кои адреси и модели се отнасят - за всеки файл в
routes
тук ще има по една директория, сerb
файлове за всеки адрес.Ако сложите файл с име
layout.erb
, той автоматично ще "опакова" всички останали темплейти.<html> <head> <title>Моят мега як сайт</title> </head> <body> <!-- На мястото на този yield ще се появава съдържанието на темплейта, който е зададен за показване. Например, `views/users/all.erb` ще бъде вмъкнат в този html и резултатът ще бъде пратен на браузъра. --> <%= yield %> </body> </html>
-
public
- Тук е мястото на всичко, което не е Ruby код - CSS, картинки, шрифтове, JavaScript код и подобни неща, разбира се добре разделени в подпапки. От тази папка (и нейните наследници), Sinatra директно изпраща файловете на браузъра. Например, ако имате файлpublic/img/картинка.png
, то на адресаhttp://<сайт>/img/картинка.png
ще се показва тази картинка.
Най-вероятно ще ви се налага да ползвате външни зависимости, освен Sinatra. За целта е силно препоръчително да ползвате Bundler. Инсталира се с gem install bundler
и се ползва с bundle
(без "r"). Документацията на сайта на Bundler е добра.
Всички файлове от routes
и models
трябва да бъдат require-нати във файла, в който се зарежда Sinatra (app.rb
, server.rb
, app.ru
в зависимост от това кой туториал за Sinatra следвате). Този файл може да наричаме "главен"/"стартов" файл на вашето уеб приложение. Той би могъл да изглежда така (ако приемем, че използвате Bundler):
require 'rubygems'
require 'bundler/setup'
require 'sinatra'
require 'sinatra-activerecord'
# More require statements...
require_relative 'models/users'
require_relative 'models/products'
require_relative 'models/orders'
# More require statements...
require_relative 'routes/users'
require_relative 'routes/orders'
require_relative 'routes/products'
require_relative 'routes/pages'
# More require statements...
Файловете, които има в routes
обикновено се наричат контролери - тяхната задача е да използват моделите и чрез изгледите (views) да показват неща на екрана (т.е. да генерират HTML страници, които да пращат на браузъра за визуализация).
Задачата на моделите (класовете в models
) е да си комуникират с базата от данни, така че другите компоненти от системата да не знаят конкретно с каква база от данни се работи, как точно са структурирани данните там и да няма SQL код навсякъде.
Изгледите просто генерират HTML от подадените им данни.
Този подход за структуриране на код се нарича MVC (Model-View-Controller).
Ако ви трябва по-специална логика, която не пасва на някое от трите места, може да създадете папка lib, в която да се намират класове, които са необходими за работата на проекта. Тези класове може да се използват в контролерите или моделите.
За да тествате вашето уеб приложение, обикновено правите комбинация от две неща:
- Тествате вашите модели и класове с unit-тестове. RSpec или MiniTest ще ви свършат много добра работа тук.
- Тествате логиката в контролерите и изгледите (която би трябвало да е малко и само сглабяща) накуп, с интеграционни тестове. Тези интеграционни тестове симулират HTTP-заявки. За целта бихте могли да ползвате Capybara, в комбинация с RSpec или нещо сродно.
Може да намерите повече информация за това в лекцията за тестване.