Yet Another Web Framework
SqueezeBox extends the Mongrel web server to provide an effortless web framework.
Designed after the Model-View-Controller pattern, SqueezeBox separates presentation and back-end cleanly but slightly differently than contemporary systems. The major difference between Rails, Merb, or the other Ruby frameworks is that SqueezeBox routes HTTP requests based on file system organization. (Like
mod_php!) While some may scoff at this simplistic design, filesystem routing significantly lessens the complexity of usage.
Despite being little more than a directory of
.erb files, SqueezeBox sites still have models and controllers. The model part is typical: ActiveRecord. The controller part is novel.
A SqueezeBox website is divided into
Resource does not have the same meaning as it does in Rails). A
Resource is an extension-less path in the document root — this path can match one or more files. For example the path
/products might match several files
/home/web_store/public/products.erb, an HTML template
products.erbor something else entirely could be returned from a HTTP request to
/products, depending on what the controller file,
The controller file is similar to an action in Rails.
# /home/web_store/public/products.rb @products = Product.find(:all) renderThe erubis templates are the same:
<!-- /home/web_store/public/products.erb --> <h1>Here are our Products!</h1> <ul> <% for product in @products %> <li><%= product.name %></li> <% end %> </ul>
mod_php, Resources with directory names can be targeted by using
While SqueezeBox routes by the file-system like antiquated Apache CGI modules (like PHP), there are many old-fashioned annoyances that it does not copy. For example, one does not need to include model definitions or header/footer files into each erb file. Rather when SqueezeBox starts up, it looks in a special file called
initialize.rb for instructions on what libraries to load globalally, what layouts should be availible, or other instructions.
There is nothing to using SqueezeBox. Here is everything you need to know. To install it:
~> sudo gem install squeezebox
To start new website:
~> mkdir -p new_website/public ~> echo "Now is <%= Time.now %>" > new_website/public/index.erb
Then start up the server by running the
squeezebox command with the website directory as an argument.
~> squeezebox -p 4200 new_website/
http://localhost:4200 should show the date and time.
The Controller File
Note that in Ruby the last line of execution is the return value. Explicit use of
return is allowed but not often used. When the last line of a controller file is
render, the return value of the controller file is the output of the function
render (a string containing a rendered erb template).
Controller files are functions whose return value is the body of the HTTP response. Typically one will call
render() to render the erb template (contained in the same Resource path) but there are numerous other possibilities. Returning just a string use that string as the body of the response—useful for sending back JSON data to a client. Returning any
IO object (or anything that acts like an
IO object) will prompt SqueezeBox to stream, in chunks, data to the response body. If you want to stream dynamic content (perhaps JSON containing updates) you need only define a class with a
read method and return an instance of that from a Controller file.
The controller file has access to all the relevant data:
@requestis the genuine
Mongrel::HttpRequestobject if you require low-level access.
@paramsis a hash containing any
@cookiesis a hash of cookies associated with the domain.
@headersis a hash of HTTP headers to be returned to the client.
Any instance variables assigned in the controller file (i.e., ones with
@ signs) will be available to erb templates.
redirect_to() sets the status code to 301 for redirection and returns nil (which is what the body of the response should be for redirection).
Layouts are an important part of web design—one would like their site to look consistent. In SqueezeBox one can define a default layout which is used automatically throughout the site unless otherwise specified. Layouts must be defined before SqueezeBox starts, in the
initialize.rb file. The function to define layouts is
set_layouts( :default => 'layouts/default.erb', :blue => 'layouts/blue.erb', :admin => 'layouts/admin.erb' )
This commands initializes three layouts each identified but a symbol. When
render() is called from a controller file an option
:layout => :blue would tell SqueezeBox to render with
render() will use the
:default layout; to avoid this use
render(:layout => false).
Layout templates should be placed outside of the
public/ directory so SqueezeBox does not accidentally serve them.
A layout template has a special variable,
content which will be replaced with the content of the inner template. Example:
<html> <head> <title> <%= @page_title ? @page_title : 'My Site' %> </title> <link type="text/css" rel="stylesheet" href="/site.css"/> </head> <body> <h1> <%= @page_title ? @page_title : 'My Site' %> </h1> <div id="mainContent"><%= content %></div> <div id="footer">:D</div> </body> </html>
@page_title can be defined inside the inner template yet effect the layout template.
SqueezeBox uses Ruby-level exceptions to display HTTP errors. It has a number of predefined exceptions which can be used. For example using
raise NotFoundfrom a controller file will stop current execution and display a page with status code 404 telling the user that the document could not be found. Similarly
raise Unauthorizedshows a page with a 501 error telling the user they do not have access rights to the requested information. A common exception would be denying requests unless they are using the
raise MethodNotAllowed unless @request.post?
These exceptions are actually genuine
Resources with paths at
/exceptions/unauthorized. That means that if you place
public/exceptions, SqueezeBox will use your template, and your controller to display the 404 page.
Exceptions that are raised during execution (syntax errors, out of memory, etc) which are not special SqueezeBox exceptions look at
/exceptions/index for instructions and return with 500 status code (internal server error).
This is really powerful! Now you have a way to display dynamic error pages, perhaps logging
Unauthorized requests to a database, or rendering a 404 page that knows what the request was.
- No magic Ruby: The code should be expressive and fast
- No generators: Make the API simple enough to start immediately from nothing. A large generated file-tree is as convoluted as a complex API.
Keep it fast: Rely on web servers as much as possible (e.g. send files with the
X-Sendfileheader), SqueezeBox is only meant to be run behind a full featured server. Only features that every single website will need should be included in the core, everything else should be pushed into add-on libraries that can be loaded easily from
Please look at the documentation and at the example web site included in the distribution for more information.
The mailing list is firstname.lastname@example.org. The FreeNode IRC channel is #squeezebox. The bug tracker is on RubyForge and the SVN repository is at