Rapid development
Inspired by posts on Western blogs like
Clone TinyURL with 40 lines of Ruby or
Clone Pastie in 15 Minutes with Sinatra & DataMapper , I decided to try to go through and describe the whole process of implementing a lightweight web application on Ruby from design to deployment.
Instruments
Ruby has a huge number of different tools for quick development. I stopped at the following:
')
Sinatra - DSL for the web. Lightweight framework operating according to the “convention over configuration” principle. It allows you to quickly and easily develop web applications, and is easily complemented by everything you need. The basis of our application.
DataMapper - ORM, the main competitor of ActiveRecord. In some way inferior, in something superior to the above, works great with different databases, easily configurable and embedded.
HAML - HTML for programmers. Markup language, slightly more beautiful than traditional erb, generates clean and valid xhtml. Contains the equivalent for CSS -
SASS .
Heroku - Allows you to conveniently and even for free (of course, with restrictions) to place the resulting application. Optional tool, you can deploy anywhere.
What are we going to write?
Choosing the tools, I thought, and what, exactly, to write? And I decided that it would be a tool for organizing my comic strip. In such an application, there is a client functionality, and an admin panel, and the generation of rss feed for a subscription, which will allow you to touch on different aspects of the development, and bring it closer to real tasks. Well, I also love web comics :)
Parsing code
Here we come to the most interesting. Virtually all of the resulting code is easily understood and can be found on
github . I recommend to open it in order to present the big picture, and I would like to dwell on the most important code fragments, and those fragments that caused me some difficulties in implementation.
First, let's analyze the structure of the project, it is very simple:
comics.rb
config.ru
models.rb
public
views
The
models.rb file contains models, database configuration and everything related to working with it.
comics.rb contains all the code for Sinatra. Also, by default, Sinatra picks up the
views folders containing views in haml and
public with files accessible from the web (javascript, images).
Let's start with the models.
models.rbDataMapper. setup ( :default , ENV [ 'DATABASE_URL' ] || "sqlite3:///#{Dir.pwd}/comics.db" )
The database parameters for heroku are contained in ENV ['DATABASE_URL'], if there is no such variable, then create the sqlite database in the project directory. There is nothing to edit in the source.
models.rb- class DateTime
- def rfc822
- self . strftime "% a,% d% b% Y% H:% M:% S% z"
- end
- end
The RSS 2.0 specification requires a date in RFC # 822 format. To do this, add the rfc822 method to the DateTime class objects, which will format the timestamp as needed, and we will use it later in the views.
comics.rb- def protected!
- response [ 'WWW-Authenticate' ] = % ( Basic ) and \
- throw ( : halt , [ 401 , "Not authorized ] ) and \
- return unless authorized?
- end
- def authorized?
- comics = Comics. first
- @auth || = Rack :: Auth :: Basic :: Request . new ( request. env )
- @auth . provided ? && @auth . basic ? && @auth . credentials && @auth . credentials == [ comics. login , comics. password ]
- end
A simple implementation of authentication for Sinatra. Almost entirely taken from the
FAQ , the difference is that the username and password are taken from the database, instead of embedded in the source. The use is extremely simple: just enter the
protected action in need of authentication
!comics.rb- get '/rss.xml' do
- content_type 'application / rss + xml' ,: charset => 'utf-8'
- @comics = Comics. first
- @strips = Strip. all : limit => 10
- haml ( : rss ,: layout => false )
- end
Return rss feed. Change the Content-Type, and add: layout => false to prevent the feed from being rendered to layout.
Now a few hints in the views.
layout.haml- % title = "#{@comics.title} - #@@strip.title}" rescue @comics . title
If you do not use the exception mechanism here, then with an empty
@strip variable, the
NoMethodError error will stop us, since the
nil class does not have a
title method. In the cut such things should always be kept in my head.
models.rb- class Strip
- # declare property
- def next
- Strip. first ( : created_at . gt => self . created_at,: order => [ : created_at . asc ] )
- end
- def previous
- Strip. first ( : created_at . lt => self . created_at )
- end
- def get_id
- self . id
- end
- default_scope ( : default ) . update ( : order => [ : created_at . desc ] )
- end
layout.haml- - tonext = "/#{@strip.next.get_id}" rescue "#"
- - toprevious = "/#{@strip.previous.get_id}" rescue "#"
The mechanism is clear - search for the next and previous strip for the one that we are looking at now, and displaying links to them in the view. Why it was necessary to do a separate
get_id method instead of directly using an existing
id ? The fact is that if we watch the last strip for the current moment, then the
next method will return
nil . And
nil in turn has an
id method, which I think will return “4” for a long time. You can see for yourself by experimenting in irb.
On this with analysis you can and finish, I will be happy to answer any questions about the code, and respond to criticism in the comments.
Deployment
The written application can be easily launched like any other application on the synatra using the
ruby comics.rb command . But we want to show it to the world, and Heroku will help us in this. We register on heroku, and install gem heroku on our local machine. Now we write the config for Rack:
config.ru- require 'comics'
- run Sinatra :: Application
The next step is to create an application on heroku, and push the code there. Let's agree that the application is already in your git repository:
heroku create comics
git push heroku master
It remains only to
fill the database with initial data. For this
purpose, there is an
install method in
models.rb :
heroku console
install
That's all, you can go to the address that issued the gem when creating the application, and if everything is done correctly, then enjoy the result.
Links
Comics on github
Heroku demo ( admin , password on request in habraposhta).