> Envelope is a web-based email management solution built with Ruby on Rails. Currently in the process of moving to a JS Framework (Spine). Despite the fact it is still in development, Envelope repository is worth to `watch` for future releases.
seen from Germany
seen from Germany

seen from Malaysia
seen from United Kingdom

seen from United States
seen from Australia
seen from Russia
seen from China
seen from Türkiye
seen from Belarus
seen from Türkiye

seen from Israel
seen from United Kingdom
seen from United States
seen from United States
seen from Germany

seen from United States
seen from Germany
seen from Israel
seen from Spain
> Envelope is a web-based email management solution built with Ruby on Rails. Currently in the process of moving to a JS Framework (Spine). Despite the fact it is still in development, Envelope repository is worth to `watch` for future releases.
The purpose of this article is to highlight these differences and hopefully make it easier to choose which framework fits your needs.
For SpineJS With Rails Use spine-rails
I’ve been learning how to use spinejs with rails. When I’m learning I like to forgo code generators as much as possible and write the necessary code myself. I’ve done that with the past few projects I’ve posted here.
However, for most of my future projects I’m going to use the spine-rails gem. The gem is written by Alex MacCaw, the author of spinejs which is much nicer than the situation of backbone with rails.
The gem’s README already documents it pretty well, so I won’t repeat it here.
Rails With SpineJS and Google Maps
I wanted to create a simple project that used ruby on rails, spinejs, and google maps together. I came up with the following features:
Dragging a marker icon from outside of a map onto a map creates a marker on the map and in the database
Dragging a marker from one position to another updates the marker on the map and updates its position in the database
Right-clicking on a map marker removes it from the map and the database
The end result can be seen here and the source code is on github.
Let’s get started.
First, create a new rails project. I prefer to use rails 3.1 because the asset pipeline makes it easy to use coffeescript with your application.
rails new dragmarkers --database=postgresql
I used PostgreSQL because it’s awesome and I wanted to put an example up on Heroku. For this project, the database doesn’t matter. ignore the database option if you’d like. Remember you’ll need to edit config/database.yml accordingly.
Take care of the usual cleanup.
cd dragmarkers rm public/index.html
Now that we have our rails project, let’s add spinejs. I think that the spine-rails gem is great (I’m even a minor contributor), but I’d like to write everything from scratch for this project. Instead, download the latest version of spine from the spinejs website. There will be several directories. Create a directory in your project for the spine files
mkdir -p vendor/assets/javascripts/spine
and copy all of the files from the lib directory of your spinejs download into the spine directory you created.
Now let’s add our standard libraries. For this project I decided to use CDN’s for the standard javascript libraries, rather than the jquery-rails gem. Open the file app/views/layouts/application.html.erb and add the libraries to the <head> section of your layout. The file should look like this:
Note that we’ll be using jquery-ui to make the marker icons draggable from outside of the map onto the map. I also added a div for page styling.
The foundation is in place, let’s start writing our own code. First we want to scaffold a Marker.
rails generate scaffold Marker
Edit config/routes.rb to make generated route the root route, for convenience. The file should look like this when you’re done:
Now let’s set up the marker model on the rails side. Edit the migration file db/migrate/[datestamp]_create_markers.rb to add columns for latitude, longitude, and icon. The file should look like this when you’re done:
Run the migration.
rake db:migrate
The rails model is done. Let’s turn to the views for a bit. Most of the scaffolded views are unnecessary and you can remove them.
rm app/assets/stylesheets/scaffolds.css.scss rm app/views/markers/_form.html.erb rm app/views/markers/edit.html.erb rm app/views/markers/new.html.erb rm app/views/markers/show.html.erb
Only the index.html.erb will be used.
We don’t need to touch the controller. Spine requires a REST interface and json, which our controller is already doing beautifully.
The rails part is done, so now for the spinejs portion. I like to do everything with coffeescript so let’s rename the application.js file to application.js.coffee (I wish this were a default).
mv app/assets/javascripts/application.js app/assets/javascripts/application.js.coffee
Open the application.js.coffee file for editing. We aren’t using the jquery gem, so you can remove the jquery-related require statements at the top. One of the nice features of spinejs is its modularity. For this project we’re using the core spinejs module and the ajax module (to work with the rails REST).
#= require spine/spine #= require spine/ajax
I like to create my directory structure for spinejs similar to what I’d find in rails application (or any MVC) and require them accordingly:
#= require_tree ./lib #= require_self #= require_tree ./models #= require_tree ./controllers #= require_tree ./views #= require_tree .
Create the corresponding directories:
mkdir app/assets/javascripts/lib mkdir app/assets/javascripts/models mdkir app/assets/javascripts/controllers mkdir app/assets/javascripts/views
Let’s create a base spinejs controller and expose it. So far, your application.js.coffee file should look like this:
We want our index file to set up html for the base controller to hook in to and create the base controller. Edit app/views/markers/index.html.erb by taking out the scaffolding and making it look like this:
A div with an “app” id and create a new App and pass that div in as the root element. At this point you could actually run your rails application and have a single-page javascript application, even though you’d only see a blank page.
Let’s create a spinejs model to correspond to our rails model. First let’s create the file
touch app/assets/javascripts/models/marker.js.coffee
Open it up and create a Marker model that inherits from Spine.Model, is configured with the same fields as our rails model, and extends the Spine.Model.Ajax functions. The file should look like this for now:
At this point, if you ran the rails application, you’d be able to do CRUD operations with the database through the javascript console in your browser with commands like: App.Marker.create({latitude: 0, longitude: 0}) (create a marker entry in the database), marker = App.Marker.find(id) (get the marker from the database that was just created, using its id), marker.updateAttributes({latitude: 1, longitude: 2}) (update the marker’s fields in the database), marker.destroy() (delete the marker from the database)
Things are shaping up pretty well, but we still have a blank-page application. Let’s remedy that. We need to show a map a marker images that can be dragged onto the map. Let’s make a javascript template (JST) view for it. I like to use eco, but there are other nice options like jQuery templates and mustache. to use eco, let’s add the line gem 'eco' to our Gemfile and install it.
bundle install
Now let’s create a new directory for our marker views and create the view file.
mkdir app/assets/javascripts/views/markers touch app/assets/javascripts/views/markers/index.jst.eco
Note the jst and eco extensions. Edit the file to contain a div with a “map” id and a bunch of image tags. Your file should look like this when you’re done.
Notice that it references 0.png through 9.png in the app/assets/images directory. You can copy the images I used into that directory or use your own. I found this website to be a great resource for map marker images. Just make sure that the images you reference in the javascript template are there.
Now let’s create a spinejs controller for the template and actually display it. I like to alias $ for jQuery and Marker for the App.Marker model. Also, we want references to the elements in our view and to display our view. Create the new spine controller file.
touch app/assets/javascripts/controllers/markers_controllers.js.coffee
Edit markers_controller.js.coffee to include that code. The file should look like this so far:
Remember in our rails view index, we’re actually creating a new App so we need to add our spinejs markers controller to that one. Edit the app/assets/javascripts/application.js.coffee file and have the constructor append our new controller. When you’re done the file should look like this.
This is the last time we’ll edit that file. If you were to run your rails application now, you would see it working because the marker icons would show up, but there still isn’t a map yet. We still need to create our google map. First, however, let’s add some style to the div that will hold the map and a bit of CSS for the marker icons too. Edit your app/assets/stylesheets/application.css file to look something like this
and edit your app/assets/stylesheets/markers.css.scss file to look something like this
If you run your rails application again, you’ll see a border around the div where the map will go and spacing for the marker icons.
Let’s return to our markers controller (app/assets/javascripts/controllers/markers_controller.js.coffee) and add the rest of the code to it. We want it to create our google map, create an overlay for the map (so that we can calculate the drag position on the map), make our marker icons draggable (and droppable), and, lastly, add any existing markers to the map. Let’s write the code for it in our controller’s constructor, then create each function in turn. Edit the file to look like this.
The first function is to create the map. I initialize it to the middle of the United States at a reasonable zoom level and use the roadmap view. Our elements declaration for our map div returns a jQuery wrapped set, the same as $('#map') and we need to get the first (and only) member to pass to the google map constructor. The function for creating the map is pretty straightforward:
The second function is to create an overlay for the map. It is simple. Note that we’re using the variable @overlay because we’ll be using it later.
The third function uses jquery-ui to make the icons draggable. We need another function to handle the icon when it is dropped (we’ll call it placeNewMarker). Note that I’m using the draggable option clone to make a copy of the image and containment of parent to keep it within the map area. Placing a new marker takes some calculations to figure out where the dropped location is within the page and uses our overlay to figure out what the equivalent longitude and latitude on the map would be. Finally, we create the new marker and put it on the map (the setMap function doesn’t exist yet, we’ll get to that in a bit). The two functions look like this
Lastly, we want to make sure the existing markers show up on the map. A fetch will retrieve the marker information from rails which triggers a refresh event. Let’s bind that even to display our markers, which will be triggered when we fetch. Our last function looks like this
Altogether, our markers_controller.js.coffee file should look like this.
Our controller is done, but we have a few more things to do to finish up. Our spinejs model for markers has no concept of a map to set a map to, and, for that matter, has no concept of a google marker for the map. Lastly, we need to make the markers draggable once they are on the map, and provide a means to remove the marker from the map.
Let’s edit our spinejs marker model (app/assets/javascripts/models/marker.js.coffee) and add these finishing touches. First, let’s have our constructor create a corresponding google map marker
add add the setMap function we were using in our controller. It’s a simple 1-liner
When a marker has been dragged on the map we want it to save its new position to the database
and right-click will remove the marker. We want to remove it from the map and the database
If we add the code to listen to the events and respond with those functions, we’re done. The file should look like this when you’re done.
The project is now complete and does everything I set out to do. However, I think there is still some room for improvement. This is nice for a small set of points, but if you were dealing with a large number of markers you’d want to fetch only the markers within the map’s currently viewable area. You may want to use a GIS system (like postgis). Instead of having right-click delete the marker, perhaps you could have a context menu with delete as one of the options.
Acknowledgements:
Thanks to Alex MacCaw for creating spinejs and all of the great documentation to go with it.
Thanks to kwicher who’s example code helped me debug some frustrating bugs.
SpineJS With Rails Screencast Transcribed
I transcribed the "Spine and Rails" screencast by Alex MacCaw and put it together with the source code on github.
Simple SpineJS and Ruby on Rails Integration
I've recently been learning an MVC javascript framework called Spine. It is similar to backbone (hence the name), but I've found it to be a bit more rails friendly and closer to what I'm familiar with. The source is also written in coffeescript, which I think has a better syntax.
What's the first step when learning something new? "Hello World!" of course! I'll take you step by step through a simple application using Rails and Spine. The source code is on github.
First, create your rails (3.1) application:
rails new hello-spine
Next you'll want to download spine.js and copy the lib directory into vendor/assets/javascripts/spine of your new rails application (the directories won't exist, you'll have to create them).
Now you'll need to configure Rails to use Spine. Edit the application.js file in app/assets/javascripts to include a line to require spine (spine.js in the spine directory). I love coffeescript, so I renamed the file to application.js.coffee and this is what it should look like:
#= require jquery #= require jquery_ujs #= require spine/spine #= require_tree .
Rails needs to supply the basic HTML that Spine hooks into, so you'll need to generate a controller for it
rails generate controller Hello index
and set it as the root route. Your config/routes.rb file should look like this:
HelloSpine::Application.routes.draw do get "hello/index" root :to => "hello#index" end
Now for the Spine part. Because this is so simple, there are no views or templates; there is no routing logic. The only logic you'll need is a Spine.Controller that you can put straight in to your application.js.coffee file (for more complex applications you'd want to separate controllers, models, and views into separate directories and include them from there). The first step is to create your new class and expose it by assigning it to the javascript "window" object. Your file should look like this:
#= require jquery #= require jquery_ujs #= require spine/spine #= require_self #= require_tree . class App extends Spine.Controller constructor: -> super window.App = App
Note also the "require_self" line right after requiring spine.
Next edit views/hello/index.html.erb to provide a div for your Spine app to work with. Followed by some javascript to create your Spine app and pass it the div as it's base DOM element. Your file could look something like this:
<div id="hello"></div> <script type="text/javascript" charset="utf-8"> jQuery(function() { new App({el: $("#hello")}); }); </script>
The last step is to have your controller append the greeting to it's base element. The addition of one more line to application.js.coffee should do it:
... class App extends Spine.Controller constructor: -> super @append("<p>Hello from Spine!</p>") ...
Start up your rails app to see the message:
rails server
So what's the next step? Alex MacCaw, the author of Spine has done a great series of screencasts and the spine gem for rails makes it easy to use spine with rails.
Wordpress as the backend, Spine JS as the front
I use Wordpress alot as a CMS. Not just for simple blog projects but also for more complex projects with custom fields and such, often to achieve this I use Magic Fields.
I'm currently in the process of developing quite a complex single page site for my friend Magnus Deuling - he's a UX / Designer, so wants all the nice features he can cram in.
We're going to use WP to power the site, just because it's user friendly and he can easily add work to it (his work pieces are essentially title, content, loads of images and some tags) - however, I'm going to take a different approach to just skinning a WP theme as I would normally do and that's what I wanted to outline here.
Spine JS
Launched yesterday as FOWA Spine JS looks like a brilliant MVC JS framework. I've used Backbone in the past, which I have really enjoyed but I like the appeal of Spine and especially the integration with Node and it's mobile features. (I wrote a piece of the Dare tech feed)
Wordpress JSON-API
On my usual stumbles around the internet I came across the WP JSON-API plugin from Dan Phiffer. It basically opens up WP to be used as a data layer (you can see where I'm going here yeah?) The plugin is available here; http://wordpress.org/extend/plugins/json-api/
Combining the two
So, my idea is to create a front end built entirely on the Spine framework (it's a SPA app after all) and use Spine's routing etc to allow deep links. Then I want to hook the model up to the Wordpress backend, exposed via the JSON-API.
This may all seem a bit odd, after all it is quite a bit of effort however I believe it has the following rewards;
I get to build on Spine
All the nice Spine features are exposed (routing, processing data in the Model, Mobile etc)
The application could be distributed, serving the backend from a different server etc.
I don't have to spend hours getting custom AJAX functions in WP working
The CMS could be (in theory) swapped out with relative ease
One thing that the JSON-API is missing is a cache. Lots of the data that will be retrieved is pretty static, so I'm thinking of employing DB Cache Reloaded (http://wordpress.org/extend/plugins/db-cache-reloaded/) but time will tell how this goes.
I'll aim to write another post detailing progress here (I think it's interesting)