Do you like Backbone.js? Do you like Sinatra? Did you ever wish you can use them together? Well now you can, with the new Sinatra Backbone!
This is a Ruby gem.$ gem install sinatra-backbone --pre
Or do you use Bundler?gem 'sinatra-backbone', :require => 'sinatra/backbone'
Sinatra-backbone is comprised of two Sinatra plugins:
Sinatra::JstPages
– Provides support for JavaScript server templates (JST)
for use in Backbone views. See JstPages example for a full example
application.
Sinatra::RestAPI
– Provides restful API for your models for use in Backbone
models. See RestAPI example for a full example application.
A Sinatra plugin that adds support for JST (JavaScript Server Templates). See JstPages example for a full example application.
require 'sinatra/jstpages'
class App < Sinatra::Base
register Sinatra::JstPages
serve_jst '/jst.js'
end
Register the Sinatra::JstPages
plugin in your application, and use
serve_jst
. This example serves all JST files found in /views/**/*.jst.*
(where /views
is your views directory as defined in Sinatra's
settings.views
) as http://localhost:4567/jst.js
.
<script type='text/javascript' src='/jst.js'></script>
You will need to link to the JST route in your layout. Make a <script>
tag
where the src='...'
attribute is the same path you provide to serve_jst
.
# views/editor/edit.jst.tpl
<h1>Edit <%= name %></h1>
<form>
<button>Save</button>
</form>
So, if you have a JST view placed in views/editor/edit.jst.tpl
:
// Renders the editor/edit template
JST['editor/edit']();
// Renders the editor/edit template with template parameters
JST['editor/edit']({name: 'Item Name'});
Now in your browser you may invoke JST['templatename']
:
TIP: If you're using the sinatra-assetpack gem, just add /jst.js
to a package. (If you're not using Sinatra AssetPack yet, you probably
should.)
# views/editor/edit.jst.jade
h1= "Edit "+name
form
button Save
Jade (.jst.jade
) -- Jade templates. This requires
jade.js. For older browsers, you will also need json2.js,
and an implementation of String.prototype.trim.
# views/editor/edit.jst.tpl
<h1>Edit <%= name %></h1>
<form>
<button>Save</button>
</form>
Underscore templates (.jst.tpl
) -- Simple templates by
underscore. This requires underscore.js, which Backbone also
requires.
# views/editor/edit.jst.haml
%h1= "Edit "+name
%form
%button Save
Haml.js (.jst.haml
) -- A JavaScript implementation of Haml.
Requires haml.js.
# views/editor/edit.jst.eco
<h1>Edit <%= name %></h1>
<form>
<button>Save</button>
</form>
Eco (.jst.eco
) -- Embedded CoffeeScript templates. Requires
eco.js and coffee-script.js.
You can add support for more templates by subclassing the Engine
class.
A template engine.
module Sinatra::JstPages
class MyEngine < Engine
def function() "My.compile(#{contents.inspect})"; end
end
register 'my', MyEngine
end
You will need to subclass Engine
, override at least the function
method,
then use JstPages.register
.
This example will register .jst.my
files to a new engine that uses
My.compile
.
The string path of the template file.
Returns the contents of the template file as a string.
The JavaScript function to invoke on the precompile'd object.
What this returns should, in JavaScript, return a function that can be called with an object hash of the params to be passed onto the template.
require 'sinatra/restapi'
class App < Sinatra::Base
register Sinatra::RestAPI
end
A plugin for providing rest API to models. Great for Backbone.js.
To use this, simply register
it to your Sinatra Application. You can then
use rest_create
and rest_resource
to create your routes.
Here's a simple example of how to use Backbone models with RestAPI. Also see the example application included in the gem.
db = Sequel.connect(...)
db.create_table :books do
primary_key :id
String :title
String :author
end
class Book < Sequel::Model
# ...
def to_hash
{ :title => title, :author => author, :id => id }
end
end
Let's say you have a Book
model in your application. Let's use Sequel
for this example, but feel free to use any other ORM that is
ActiveModel-compatible.
You will need to define to_hash
in your model.
require 'sinatra/restapi'
class App < Sinatra::Base
register Sinatra::RestAPI
rest_create '/book' do
Book.new
end
rest_resource '/book/:id' do |id|
Book.find(:id => id)
end
end
To provide some routes for Backbone models, use rest_resource
and
rest_create
:
Book = Backbone.Model.extend({
urlRoot: '/book'
});
In your JavaScript files, let's make a corresponding model.
book = new Book;
book.set({ title: "Darkly Dreaming Dexter", author: "Jeff Lindsay" });
book.save();
// In Ruby, equivalent to:
// book = Book.new
// book.title = "Darkly Dreaming Dexter"
// book.author = "Jeff Lindsay"
// book.save
Now you may create a new book through your JavaScript:
book = new Book({ id: 1 });
book.fetch();
// In Ruby, equivalent to:
// Book.find(:id => 1)
Or you may retrieve new items. Note that in this example, since we defined
urlRoot()
but not url()
, the model URL with default to /[urlRoot]/[id]
.
book.destroy();
Deletes will work just like how you would expect it:
class App < Sinatra::Base
rest_create "/documents" do
Document.new
end
end
Creates a create route on the given path
.
This creates a POST
route in /documents that accepts JSON data.
This route will return the created object as JSON.
When getting a request, it does the following:
A new object is created by yielding the block you give. (Let's
call it object
.)
For each of the attributes, it uses the attrib_name=
method in
your record. For instance, for an attrib like title
, it wil lbe
calling object.title = "hello"
.
if object.valid?
returns false, it returns an error 400.
object.save
will then be called.
object
's contents will then be returned to the client as JSON.
See the example.
class App < Sinatra::Base
rest_resource "/document/:id" do |id|
Document.find(:id => id)
end
end
Creates a get, edit and delete route on the given path
.
The block given will be yielded to do a record lookup. If the block returns
nil
, RestAPI will return a 404.
In the example, it creates routes for /document/:id
to accept HTTP GET
(for object retrieval), PUT (for editing), and DELETE (for destroying).
Your model needs to implement the following methods:
save
(called on edit)destroy
(called on delete)<attrib_name_here>=
(called for each of the attributes on edit)If you only want to create routes for only one or two of the actions, you may individually use:
rest_get
rest_edit
rest_delete
All the methods above take the same arguments as rest_resource
.
This is the same as rest_resource
, but only handles GET requests.
This is the same as rest_resource
, but only handles PUT/POST (edit)
requests.
This is the same as rest_resource
, but only handles DELETE (edit)
requests. This uses Model#destroy
on your model.
class Album < Sequel::Model
def to_hash
{ :id => id,
:title => title,
:artist => artist,
:year => year }
end
end
The create and get routes all need to return objects as JSON. RestAPI
attempts to convert your model instances to JSON by first trying
object.to_json
on it, then trying object.to_hash.to_json
.
You will need to implement #to_hash
or #to_json
in your models.
There are some helper methods that are used internally be RestAPI
,
but you can use them too if you need them.
Responds with a request with the given object
.
This will convert that object to either JSON or XML as needed, depending on the client's preferred type (dictated by the HTTP Accepts header).
Returns the object from the request.
If the client sent application/json
(or text/json
) as the content
type, it tries to parse the request body as JSON.
If the client sent a standard URL-encoded POST with a model
key
(happens when Backbone uses Backbone.emulateJSON = true
), it tries
to parse its value as JSON.
Otherwise, the params will be returned as is.
© 2011, Rico Sta. Cruz. Released under the MIT License.
Sinatra-Backbone is authored and maintained by Rico Sta. Cruz with help from it's contributors. It is sponsored by my startup, Sinefunc, Inc.