В моей статье Ruboto: Ruby’s и Android’s First Born я рассмотрел один из способов использования Ruby для разработки мобильных приложений. В этой статье мы создали собственное Android- приложение на JRuby, которое может работать на виртуальной машине Java на Android.
На этот раз мы погрузимся в мир мобильных веб-приложений. Эти маленькие модные магниты в основном являются обычными веб-приложениями, которые были высоко оптимизированы и развернуты для мобильных устройств. Как правило, внешний вид пытается напоминать нативное мобильное приложение и, благодаря некоторым более новым API-интерфейсам HTML5, даже получить доступ к датчикам устройств для получения некоторых дополнительных интересных функций.
Что мы строим?
Я предполагаю, что все ожидают еще одно приложение todo на данный момент. Однако я могу с уверенностью сказать, что не только это не так, но мы на самом деле строим что-то, что основано на реальной просьбе моего друга. Она тестировала некоторые пищевые добавки и хотела отследить последствия. Поэтому вместо того, чтобы позволить ей использовать ручку и бумагу, как пещерный человек, я предложил вместо этого создать мобильное веб-приложение. Таким образом, она могла бы приятно использовать его со своего смартфона или любого браузера, а потом, возможно, даже сделать некоторый автоматический анализ данных.
Как мы собираемся это сделать?
Желая быстрых результатов, я решил выбрать технологический стек соответственно:
На мой взгляд, эти драгоценные камни представляют собой идеальную площадку для прототипов мобильных приложений. Конечно, если бы мы стремились к большему приложению с более чем несколькими простыми моделями и тысячами пользователей, вы бы определенно поступили иначе. Но для первого прототипа, который поможет добиться успеха и произвести впечатление на клиентов или на частные проекты, вам будет сложно найти гораздо лучший стек.
Кроме того, просто для простоты (всегда большой плюс в моем списке) я покажу вам, как сделать все это в одном файле, содержащем менее ста строк кода.
Давай приступим к работе!
В восторге? Большой! Итак, без дальнейшего введения, давайте начнем наш проект с правильной линии Шебанга и потребуем необходимые драгоценные камни:
#!/usr/bin/env ruby | |
%w(sinatra sqlite3 dm-sqlite-adapter data_mapper haml time).each{|g| require g} |
После этого пришло время определить классы модели. В нашем случае нам нужна только одна модель для представления событий, которые мы собираемся отслеживать:
class Event | |
include DataMapper::Resource | |
property :id, Serial | |
property :time, DateTime | |
property :type, String | |
property :description, String | |
end |
Для модели обычно требуется постоянство, чтобы мы могли перезапустить приложение и сохранить наши данные. Мы будем использовать базу данных SQLite для этого и DataMapper Gem в качестве ORM, главным образом по двум причинам: с одной стороны, использование ORM, такого как DataMapper, позволяет нам позже изменить внутреннюю часть базы данных без изменения логики приложения, а с другой стороны, DataMapper поддерживает автоматические миграции и создание схем. Это очень сексуальные функции, особенно если вы хотите быстро и быстро разработать прототип. Итак, добавление постоянства в наше приложение сводится к этим двум строкам кода:
DataMapper::setup(:default,«sqlite3:pilltracker.db») | |
DataMapper.finalize.auto_upgrade! |
Одиннадцать строк кода в проект, модели и упорство сделано. Пришло время добавить несколько контроллеров или, с точки зрения Синатры, маршруты. Конечно, мы хотим увидеть список всех событий, которые мы добавили до сих пор. Этот список событий пока будет нашей главной страницей. Кроме того, мы должны иметь возможность добавлять новые события и сохранять их. Это делает три довольно простых и понятных маршрута:
get ‘/’ do | |
@events = Event.all(:order => :time.desc) | |
haml :index | |
end | |
get ‘/new/?’ do | |
haml :new | |
end | |
post ‘/new/?’ do | |
begin | |
Event.create( | |
:time => Time.parse(params[‘time’]), | |
:type => params[‘type’], | |
:description => params[‘description’] | |
) | |
redirect ‘/’ | |
rescue | |
haml :new | |
end | |
end |
Еще девятнадцать строк — тридцать, и сейчас нам не хватает только некоторых просмотров. К счастью для нас, Haml — довольно сжатый способ написания HTML-шаблонов, а у Sinatra есть козырь, когда дело доходит до крошечных проектов и представлений. Нам нужно только завершить наш Ruby-файл оператором __END__
чтобы остановить интерпретатор, и затем добавить наши представления следующим образом:
__END__ | |
@@ layout | |
!!! 5 | |
%html{:lang => ‘en’} | |
%head | |
%meta{:charset => ‘utf-8’} | |
%meta{:name => ‘viewport’, :content => ‘width=device-width, initial-scale=1’} | |
%meta{:name => ‘format-detection’, :content => ‘telephone=no’} | |
%title PillTracker | |
%link{:href => ‘//code.jquery.com/mobile/1.0.1/jquery.mobile-1.0.1.css’, :rel => ‘stylesheet’} | |
%link{:href => ‘//dev.jtsage.com/cdn/datebox/latest/jquery.mobile.datebox.min.css’, :rel => ‘stylesheet’} | |
%script{:src => ‘//code.jquery.com/jquery-1.7.1.min.js’} | |
%script{:src => ‘//code.jquery.com/mobile/1.0.1/jquery.mobile-1.0.1.min.js’} | |
%script{:src => ‘//dev.jtsage.com/cdn/datebox/latest/jquery.mobile.datebox.min.js’} | |
%body | |
%div{‘data-role’ => ‘page’} | |
%div{‘data-role’ => ‘header’} | |
%h2 PillTracker | |
= yield(:layout) | |
@@ index | |
%ul.ui-listview{:data => {:role => ‘listview’, :theme => ‘b’}} | |
%li{:data => {:theme => ‘a’}} | |
%a{href:’/new/’} New | |
— @events.each do |event| | |
%li | |
%img{:style => ‘float:left;margin:1em;’, | |
:src => event.type == ‘took’ ? ‘pills.png’ : ‘stethoscope.png’} | |
%div&= event.time.strftime(«%Y-%m-%d %H:%M») | |
%div&= «#{event.type}: #{event.description}» | |
@@ new | |
%form{:action => ‘/new/’, :method => ‘post’} | |
%p | |
%label{:for => ‘event’} Event | |
%p | |
%fieldset{:data => {:role => ‘controlgroup’, :type => ‘horizontal’}} | |
%input{:type => ‘radio’, :name => ‘type’, :id => ‘took’, :value => ‘took’, :checked => ‘checked’} | |
%label{:for => ‘took’} took | |
%input{:type => ‘radio’, :name => ‘type’, :id => ‘feel’, :value => ‘feel’} | |
%label{:for => ‘feel’} feel | |
%p | |
%label{:for => ‘time’} Time | |
%p | |
%input{:name => ‘time’, :id => ‘time’, :type => ‘date’, ‘data-role’ => ‘datebox’, | |
:value => Time.now.strftime(‘%Y-%m-%d %H:%M:%S’), | |
‘data-options’ => ‘{«mode»: «slidebox», «dateFormat»:»YYYY-MM-DD GG:ii», «timeFormat»:24, «fieldsOrderOverride»:[«y»,»m»,»d»,»h»,»i»]}’} | |
%p | |
%label{ :for => ‘description’} Description | |
%p | |
%textarea{:name => ‘description’, :id => ‘description’} | |
%p | |
%a{:href => ‘/’, :data => {:role => ‘button’, :data => ‘true’}} Cancel | |
%button.ui-btn-hidden{:type => ‘submit’, ‘data-theme’=>’a’, ‘aria-disabled’=>’false’} Save |
Компоновка и два вида примерно в пятьдесят строк, не так уж и плохо. Как видите, мы загружаем jQuery, jQuery Mobile и дополнительный плагин jQuery Mobile Datebox прямо из их удаленных источников. Примечание. Часть протокола в URL-адресе является необязательной, и ее пропуск будет работать для HTTP и HTTPS без каких-либо изменений.
Если вы с готовностью скопировали / вставили все эти фрагменты и хотите запустить их сейчас, вы можете сделать это с помощью простого ruby pilltracker.rb
или, если вы забыли установить бит исполняемого файла, даже с ./pilltracker.rb
следовательно, притон. Приложение будет работать нормально, если вы установили все необходимые Gems. Он также автоматически создаст файл базы данных в рабочем каталоге, но будет отсутствовать некоторые изображения.
Для полной версии кода и изображений просто клонируйте этот репозиторий .
Я надеюсь, вам понравился этот маленький проект, и, возможно, вы даже хотите добавить функцию удаления для дальнейшего изучения. Как всегда, я постараюсь ответить на любые вопросы и совсем не разозлюсь, если вы почувствуете желание написать в твиттере об этой статье 🙂