» Publishers, Monetize your RSS feeds with FeedShow: More infos (Show/Hide Ads)
So, you've got what it takes to turn on LEDs and move some motors around using your trusty Arduino. You also have some skills writing web code. Here’s a simple walkthrough of how to combine your great talents and make a nice web interface for your Arduino project!
Communication with the Arduino
Here at Viget we write a fair amount of Ruby code, so this post will focus on interfacing your Arduino with Ruby. Using the serialport gem, communication with your Arduino over the serial port is easy. To enable serial communication from your Arduino, you need a line of setup code:
setup {
Serial.begin(9600)
}
You can then send out data anywhere in your program:
loop {
...
Serial.println("Hello world!")
...
}
Catching this on the Ruby side is straightforward as well. With some set up to specify the port, you’re ready to listen:
require 'serialport'
port_str = '/dev/tty.usbmodem1411'
baud_rate = 9600
data_bits = 8
stop_bits = 1
parity = SerialPort::NONE
sp = SerialPort.new(port_str, baud_rate, data_bits, stop_bits, parity)
while(true) do
message = sp.get
message.chomp!
puts message
end
This code will read every message coming through the Serial port and print it out (messages come in with a trailing newline character so .chomp! handles that for you). It's worth noting that sp.gets blocks until a message comes in from the Serial port.
Sending messages back to your Arduino from Ruby can be done using sp.write(message), and catching the messages with Serial.read().
Communication with your browser
Now that you’re catching updates from your Arduino in real time, we’ll make use of websockets to instantly update a web page. There’s a great article here explaining this technology and how to easily get yourself set up using Ruby. Here are the basic code snippets.
In your Ruby file:
require 'em-websocket'
require 'json'
require 'serialport'
sp = SerialPort.new('/dev/tty.usbmodem1411', 9600, 8, 1, SerialPort::NONE)
EventMachine::WebSocket.start(:host => '0.0.0.0', :port => 8080) do |ws|
ws.onopen { ws.send "hello client" }
ws.onclose { puts "WebSocket closed" }
ws.onmessage do
ws.send message_from(sp).to_json
end
end
def message_from(sp)
message = sp.get
message.chop!
{ "event" => message }
end
In your HTML file:
$(document).ready(function() {
ws = new WebSocket("ws://localhost:8080");
ws.onopen = function() {
ws.send("hello server");
};
ws.onclose = function() {};
ws.onmessage = function(evt) {
console.log(evt.data);
var message = JSON.parse(evt.data);
// code to update the page given the incoming message
// send a dummy message back to initiate
// the onmessage callback again
ws.send("next message please!");
}
});
We now have an instant channel for communication between Arduino-listening Ruby code and JavaScript. With the Ruby file running, we can open up the HTML file in a browser and the communication loop will begin. Ruby will then wait on the Arduino for a message over the serial port, work it into a hash, and ship it over to our JavaScript in JSON. The JavaScript then needs to send a dummy message back so the process can start again.
At this point, your web skills can take over and you can update divs and spans every time something happens on your Arduino. This is an easy way to give a pretty face to our Arduino projects. Bonus points for running your web server on a cheap Raspberry Pi.
Extra credit
Take a look at Dino. This is a sweet little gem that allows you to read from and control your Arduino using only Ruby code -- and it gives you the ability to send commands in real time to the Arduino such as servo.position = 80 or led.on. With Dino, you would not need your Arduino to respond to specific strings coming over the Serial port, but instead could have your Ruby file control the Arduino itself.
Think this is a good idea? Found a much better way to interface your Arduino with the web? I’d love to hear your comments below.
Recently, when working on a JavaScript-heavy Backbone.js + Rails application, I spent a significant amount of time working with Capybara and the JavaScript driver Poltergeist for automated browser testing. After struggling with some specific asynchronous test steps, I stumbled across a great blog post detailing some effective asynchronous helper methods: wait_for_ajax, wait_for_dom, and the recently removed Capybara method wait_until. I ended up using a slightly modified version of wait_until that allows me to pass in a block that must return true:
def wait_until
require "timeout"
Timeout.timeout(Capybara.default_wait_time) do
sleep(0.1) until yield == true
end
end
wait_until { dom_element['class'].include? "is-active" }
While these asynchronous helper methods are great for assisting with finicky JS tests, I ran into some frustration when tests would fail on our Continuous Integration (CI) server (at Viget we use Jenkins). Tests involving JavaScript rely heavily on timing. It is fairly easy to have a test pass on your speedy development machine, only to have the test fail on CI either because it is running slower due to parallel builds happening or simply because of the timing of executing the assertions. Even after increasing the Capybara.default_wait_time setting, I was still getting seemingly random test failures.
After a few times ssh'ing into our Jenkins server, modifying the test to save a screenshot, and then scp'ing that file back to my machine in order to view it, I decided to try and automate this process. My first idea was to make a plugin that would automatically save a screenshot of a failing test and then email that image to a configurable set of receivers. After playing around with it a bit, I realized that you could just access the images hosted right on the CI server.
This bit of code will automatically take a screenshot of a failing JavaScript test. I've decided to assert that the type of test is ':js => true' because the default Capybara driver (RackTest) does not support saving screenshots.
RSpec.configure do |config|
config.after(:each) do
if example.exception && example.metadata[:js]
meta = example.metadata
filename = File.basename(meta[:file_path])
line_number = meta[:line_number]
screenshot_name = "screenshot-#{filename}-#{line_number}.png"
screenshot_path = "#{Rails.root.join("tmp")}/#{screenshot_name}"
page.save_screenshot(screenshot_path)
puts meta[:full_description] + "\n Screenshot: #{screenshot_path}"
end
end
end
Now when a finicky JavaScript test fails on Jenkins, the auto-emailed report includes a URL to the saved screenshot:

I was pleasantly surprised to find that Jenkins converts a path from the console output into a convenient URL.
This allows me to simply click the provided link to see what is happening in the browser, which has been an immense time-saver in diagnosing failing tests.
What kind of tricks do you use for asynchronous browser tests and/or debugging them? Please leave a comment below!
In two previous posts about writing better bug reports, I've detailed the information developers need to be able to reproduce — and hence diagnose and fix — bugs. Since then, an unstated assumption in both posts has been nagging at me: that developers must be able to reproduce a bug in order to diagnose and fix it.
To a developer, this is not an assumption — it's truth, and obvious. But to non-developers, the necessity of reproducibility is not obvious. If it were, devs wouldn't see so many bug reports that say little more than "A vague thing vaguely happened — fix it!!!"
I think this disconnect is the primary cause of frustrating-to-devs bug reports. If we can better understand the reason for the disconnect, maybe it'll be easier to convince non-devs of the necessity of reproducibility.
So what causes this disconnect? Here's my theory:
I believe that most non-developers think developers are like Neo in The Matrix: that devs can see all parts of an app simultaneously at all times, like Neo's living-ASCII-art view of the Matrix itself. That devs are omniscient, omnipotent beings in regard to an app. I've come to think of this mental model as the Neo Fallacy.
If pressed, I don't think we could say how we think developers do this. (Optic fiber running from servers to devs' brain stems? Magic emanating from the bowels of 4chan? Google Glass?) But I can't think of a better explanation for why so many of us assume devs can figure out a bug from so little information.
Returning to theory No. 1, I asked some Viget developers why reproducibility is so important. Some of their answers:
- "So we can hopefully write a failing test first, and then have one in place to prevent future regressions"
- "To confirm it's an actual bug"
- "To know when we've fixed it"
- "To be able to investigate the issue deeply"
- "So we don't waste our super valuable time"
All make sense. But those answers are beside the point to someone operating under the Neo Fallacy: "Fine, but why do you need to reproduce the bug to achieve all those things? Can't you just 'see' what's happening?"
Here's an answer that I hope helps reframe the way we think about developers:
Developers are not Neo. Yes, they have superpowers when it comes to writing code. But they're mere mortals when it comes to knowing what's happening in an app in real time. They're not omniscient.
Occasionally, they may be able to quickly ascertain a problem based on an intuitive sense of an app's behavior and an auto-generated error report from Airbrake. But most of the time, a context-free, vague bug report will mean no more to a developer than it would to you. Literally: without the details I outlined in my other posts — URLs, login creds, specific steps — you might as well submit the bug report to yourself.
And having to spend time trying to glean meaning from such a vague report? For devs, that's about as fun as hanging out with these guys.
I recently found myself building out a comp which seemed to have only enough code repetition to include a header and footer. However, the further I got into build-out the more code repetition emerged. I saw an opportunity for a MVC-like views system to help, so I set out to build one to make my build-out process easier.
Code Examples
Let's say you have a basic layout with a reusable header and footer, like the one in the example below.
<!-- location: views/layouts/default.php -->
<html lang="en">
<head>
<title>Example Layout</title>
</head>
<body>
<header>
<?php $this->render('shared/header'); ?>
</header>
<div class="content">
<?php $this->getContent(); ?>
</div>
<footer>
<?php $this->render('shared/footer'); ?>
</footer>
</body>
</html>
<!-- location: views/about.php -->
<?php $this->layout('default'); ?>
<h2>About Page</h2>
<p>Lorem ipsum dolor copy.</p>
If we opened domain.com/about in the browser, we would see the About page content loaded within the default layout we created above. (Note: In the above example we could lose the layout declaration at the top since Layouts with Views expects to load default.php as the default layout. This setting can be changed in settings/config.php.)
The above example shows a basic application of Layouts with Views. Check out the Github page for examples of features like:
- Multiple layouts
- Nested views
- Passing variables to views
- Allow for common control structures (if, foreach, etc.)
- Referencing page assets (images, stylesheets) using an absolute path
- Simple routing (Create the file, done)
Download
git clone git@github.com:tommymarshall/layouts-with-views.git
In Conclusion
Layouts with Views sets out to solve a small problem and that's it. There's no customizable routing, no crazy templating features, no unusal syntax to learn. It’s just a simple way for me to build out comps. That's what I like about it.
A big challege with sites utilizing JavaScript is determining which JS should be executed on each page. Here are some approaches to doing this, along with my preferred method. While libraries like Backbone and Ember have ways of executing JavaScript, this article will mainly focus on executing JavaScript for web sites, not web apps. So I'm talking about more marketing style sites instead of applications. An example would be this very site versus something like Gmail.
For these examples, I'm assuming the following:
- jQuery is being used on the site
- All of the JS for the site is concatenated into a single file and loaded on every page.
Everything in document.ready
Before I go into preferred methods, I figured that it makes sense to talk about what you shouldn't do. This is how I used to do it when I first learned how to use jQuery, and I still see some people doing this today.
$(document).ready(function() {
$('.tabs').tabs();
$('.carousel').carousel();
$('.slider').slider();
});

Just don't do this. Even though jQuery fails silently, there is no reason to just throw stuff at the DOM and hope it sticks. Come up with a plan to execute only the JS that you need for each page.
Dom Based Routing
Paul Irish initially talked about this technique in 2009. The idea is to use the id and class attributes on the body element to determine which JavaScript should be fired.
Let's pretend that your body element looks like this:
<body class="shopping" id="cart">
And you have some JS that looks like this:
SITE = {
common: {
init: function(){ ... },
finalize: function(){ ... }
},
shopping: {
init: function(){ ... },
cart: function(){ ... },
category: function(){ ... }
}
};
The execution code is set up so that it calls the following methods:
SITE.common.init() SITE.shopping.init() SITE.shopping.cart() SITE.common.finalize()
Garber-Irish Implementation
This technique came out of my coworker, Jason Garber, working on a Rails project and had a desire for a little more structure. The idea is to use the Rails controller and action to execute specific JavaScript.
For example, on the users show page, the body element would look like this:
<body data-controller="users" data-action="show">
So you create objects based on controllers with a method for the action. The JavaScript would look like this:
SITE = {
common: {
init: function() {}
},
users: {
init: function() {},
index: function() {},
show: function() {}
}
};
The execution code is set up to call the following methods:
SITE.common.init(); SITE.users.init(); SITE.users.show();
This pattern has worked great for a number of sites, and I've even used the pattern for non-Rails projects. But, as we have continued to build more responsive and modular sites that are more system-based instead of page-based, the pattern has become less and less ideal.
Feature-Based Execution
This technique takes a feature based approach instead of a page specific approach. The idea is to break each feature out into a separate object, and then add the features that you want to execute as an attribute on the body. Here is an example of what our body element would look like:
<body data-features="timeline tabs filters modal">
Here is how we have each of the features broken out into separate objects:
SITE.features = {
filters: {
init: function() {}
},
modal: {
init: function() {}
},
tabs: {
init: function() {}
},
timeline: {
init: function() {}
}
};
Then, I typically add an init method onto our SITE.features object to initialize all of the feature based execution:
SITE.features = {
init: function() {
var features = $('body').data('features');
var featuresArray = [];
if(features) {
featuresArray = features.split(' ');
for(var x = 0, length = featuresArray.length; x < length; x++) {
var func = featuresArray[x];
if(this[func] && typeof this[func].init === 'function') {
this[func].init();
}
}
}
}
};
So when we call SITE.features.init() on document load, we grab the data attribute off of the body, and execute each feature. It would execute the following methods:
SITE.features.timeline.init() SITE.features.tabs.init() SITE.features.filters.init() SITE.features.modal.init()
Feature-Based Execution + Script Loader
An idea that I have been playing with, but haven't implemented yet on a site, is to use a script loader to load features for the page instead of including them in a single concatenated file. Here is what the modified SITE.features.init() method looks like using the yepnope script loader:
SITE.features = {
init: function() {
var features = $('body').data('features');
var featuresArray = [];
if (features) {
featuresArray = features.split(' ');
for(var x = 0, length = featuresArray.length; x < length; x++) {
var func = featuresArray[x];
yepnope([{
load: 'scripts/features/' + func + '.js',
complete: function () {
if(this[func] && typeof this[func].init === 'function') {
this[func].init();
}
}
}]);
}
}
}
};
jQuery Meetup
I recently had the opportunity to give a presentation on this topic, along with jQuery plugin development (go to slide 72 if you want to skip the jQuery plugin development piece) at the DC jQuery Meetup.
What Did We Learn?
Don’t just haphazardly fire a bunch of JS functions that may or may not be used. Come up with a pattern for triggering JS on each page that makes sense for your site.
So what methods have you used for executing JavaScript on sites?
This past fall, a group of us set out to (re-)learn the C programming language using Zed's Learn C the Hard Way as our primary resource. In the age of high-level languages like Ruby and JavaScript, it may seem a bit strange to take such a "step back" when it's been 10+ years since I have had any significant experience using the language. So why do it?
I wanted a new challenge.
As an experienced programmer, the basics of the language were unsurprising (as expected). Variables, conditionals, and loops presented no surprises as I've seen these concepts time and time again in other languages. I will admit that understanding pointers was initially as confusing as when I first encountered them more than 15 years ago. This confusion reinforced the fact that C is not a language for the faint of heart -- there are a number of challenges that a programmer has to overcome when working in a lower-level language.
These challenges weren't without their benefits. During our course of study, we became proficient with a number of language features and related tools:
- Memory allocation — Once I moved past writing trivial programs, heap allocation became a necessity. Not only did I learn how to use malloc and free appropriately, but also when to use realloc to create dynamic data structures and calloc to create robust allocations for storing string data.
- Makefiles — Zed's introduction to make and subsequent discussion of its advanced features really helped to de-mystify the tool for me. The additional documentation and alternate applications helped me understand its utility for building C programs and other automated tasks.
- Function pointers — It was interesting to me to see that such a low-level language contained functional programming concepts. I found function pointers a useful refactoring technique when dealing with different collections of structs. For example, when sorting an array of integers or strings, I was able to use functions with the same signature and behavior but with different implementations.
- C pre-processor — From the beginning, Zed made heavy use of the C pre-processor to create macros for debugging, iterating, and otherwise simplifying the code that I needed to write. After gaining more experience with the language, I learned when to choose a pre-processor macro over a subroutine (or vice versa) to refactor and improve readability of the code.
- Variable argument functions — Surprisingly, this language feature came in handy more often than I thought. Internally, this is how the printf family of functions is implemented. I used it to create functions like max_length(char *s1, char *s2, ...) to get the overall maximum length of n number of strings, and array_push(Array *array, ...)` to add elements to an array based on its underlying storage type.
- Valgrind — I have no idea how you would create a stable program without this tool. Time and time again, I would write what I thought was robust code, but valgrind would call me out on my mistakes. Whether it was a simple memory leak or an off-by-one error when accessing a segment of memory, I was able to quickly diagnose those mistakes and correct them. Without valgrind, these errors could easily slip by undetected.
Overall, the challenges presented with C really forced me to think deeply about how I organized my code and interacted with the machine. Understanding that balance between bare-metal performance and human understandability definitely revealed the language's sweet spot. Even in an industry where older technologies are constantly rendered obsolete, that balance is the reason developers of major modern software projects continue to choose C for their implementation language.
If you're interested in (re-)learning the language yourself, I recommend LCTHW as a good starting resource. Working through the exercises as a group helps keep everyone motivated and generates some fun ideas for other programs to write.
Draggable controls raise an interesting challenge when Backbone.Views share a common model.
Such controls include colorpickers, slides, and positionable elements. When users move around a color wheel or acutely adjust the position of an element, change events should trigger to let other components know their portion of the interface needs updating.
For this to happen, the browser's data layer must update immediately. But how does the application know when to pass the torch to the database?
Requesting to persist data on every pixel deviation can be disastrous. When a user wants the perfect shade of yellow, there's nothing like a torrent of PUT requests to dampen their mood.
To illustrate:
Not exactly performant. Fortunately UnderscoreJS provides a great toolset for tackling exactly this problem.
Only you can prevent forest-fires, by debouncing
UnderscoreJS's debounce method is particularly well suited for our use case: it postpones invocation of a function until a specified expiration time that resets on every function call. This can be used to bundle together Backbone.sync executions from the same source, significantly lowering requests without nasty side effects.
Update: Originally I handled debouncing directly within the sync method of the Backbone.Model, however a sharp commenter has suggested a more optimal solution by moving this functionality into the Backbone.View that oversees the input.
To avoid directly manipulating the Backbone.sync method, an event must be bound in the view that controls such inputs. On change, the view should immediately provide actions required to update the user interface, requesting to sync in the background.
var View = Backbone.View.extend({
events: {
'change input.slider' : 'onSliderChange'
},
saveInBackground: _.debounce(function(params) {
return this.model.save(params, { silent: true });
}, 800),
onSliderChange: function(e) {
// Take immediate action, such as setting the values locally:
this.model.set({
value: e.target.value
});
// Then call a debounced save method, which will eventually
// trigger Backbone.sync
this.saveInBackground();
}
});
Beautiful and Simple
This minor addition achieves exactly what is needed! No matter how furiously the user updates information, the model view is now smart enough to send an AJAX request once, a short period after the drag motion has completed. Minor tweaks may be required depending on the purposes of the application, but the resulting code lets the user interface immediately respond to the change, while not causing servers to catch on fire.
Draggable controls raise an interesting challenge when Backbone.Views share a common model.
Such controls include colorpickers, slides, and positionable elements. When users move around a color wheel or acutely adjust the position of an element, change events should trigger to let other components know their portion of the interface needs updating.
For this to happen, the browser's data layer must update immediately. But how does the application know when to pass the torch to the database?
Requesting to persist data on every pixel deviation can be disastrous. When a user wants the perfect shade of yellow, there's nothing like a torrent of PUT requests to dampen their mood.
To illustrate:
Not exactly performant. Fortunately UnderscoreJS provides a great toolset for tackling exactly this problem.
Only you can prevent forest-fires, by debouncing
UnderscoreJS's debounce method is particularly well suited for our use case: it postpones invocation of a function until a specified expiration time that resets on every function call. This can be used to bundle together Backbone.sync executions from the same source, significantly lowering requests without nasty side effects.
Update: Originally I handled debouncing directly within the sync method of the Backbone.Model, however a sharp commenter has suggested a more optimal solution by moving this functionality into the Backbone.View that oversees the input.
To avoid directly manipulating the Backbone.sync method, an event must be bound in the view that controls such inputs. On change, the view should immediately provide actions required to update the user interface, requesting to sync in the background.
var View = Backbone.View.extend({
events: {
'change input.slider' : 'onSliderChange'
},
saveInBackground: _.debounce(function(params) {
return this.model.save(params, { silent: true });
}, 800),
onSliderChange: function(e) {
// Take immediate action, such as setting the values locally:
this.model.set({
value: e.target.value
});
// Then call a debounced save method, which will eventually
// trigger Backbone.sync
this.saveInBackground();
}
});
Beautiful and Simple
This minor addition achieves exactly what is needed! No matter how furiously the user updates information, the model view is now smart enough to send an AJAX request once, a short period after the drag motion has completed. Minor tweaks may be required depending on the purposes of the application, but the resulting code lets the user interface immediately respond to the change, while not causing servers to catch on fire.
Hopefully, you've been able to experience our Jinglebots -- the 2012 Pointless Corp holiday project -- for yourself. Klaus 5000, Cornelius, and Ru 2 Dee 2 are the Jinglebots -- “robots” which reside in each of our Viget offices. They “speak” tweets and messages for all of the world to hear through a Dropcam feed. As a user, you can check out the web site and either tweet with the #jinglebots hashtag or submit a message through a basic messenger on the site.
I've estimated the amount of coordinating technologies to be around a bazillion. For those who may be interested in how to use your computer to control Christmas lights, power electric toy trains, or do other cool things (using Ruby!), I’ll walk you through how to do it below.
Step 1 - Instant Communication
We knew that we'd be responding to messages and tweets in real time. For this, we made use of Redis pub/sub capabilities. Redis is super simple to get going locally and use of RedisToGo gives you access to a free online Redis instance you can use in production. When a message comes in, we publish the message data (sender name, message, timestamp, etc.) in JSON to a Redis channel.
REDIS.publish("holiday_messages", data.to_json)
Each of our Jinglebots is subscribed to the holiday_messages channel.
REDIS.subscribe('holiday_messages') do |on|
on.message do |channel, raw_data|
data = JSON.parse(raw_data)
... some awesome stuff using the data
end
end
Instant communication has never been easier.
Step 2 - Receiving Messages/Tweets
On the web site, a form allows users to submit a message and a name. On submission success, the app then compiles the necessary data, converts it to JSON, and publishes it to the holiday_messages Redis channel.
To capture incoming tweets with the #jinglebots hashtag, we made use of EventMachine and the twitter-stream gem. This bit of code owes great credit to Twerrible Towel which has their code open sourced. The following code takes care of all the Twitter listening for us.
EventMachine::run do
stream = Twitter::JSONStream.connect(
:path => '/1/statuses/filter.json',
:auth => "#{twitter_username}:#{twitter_password}",
:method => 'POST',
:content => "track=#jinglebots"
)
stream.each_item do |item|
tweet = JSON.parse(item)
if tweet && tweet["user"]
data = assemble_data(tweet)
REDIS.publish("holiday_messages", data.to_json)
end
end
end
Step 3 - The Fun Part
So, with a stream of messages coming in, we had to figure out what to do with them. If you're on a Mac, open up the terminal and type say hello master. With the volume turned up, your computer has been given a voice! After some massaging of the incoming message (removing special characters, subbing out bad words for a system beeeeep), we now had robots which could speak any message we threw at them.
We weren't done though. What's a talking robot without a face? Enter the tag team work of designer Joseph Le and front-end developer Nate Hunzaker. A simple-yet-awesome Node.js app on Express meant that we had three different faces (one for each Jinglebot) which could be turned to "talking" and "not talking" mode with a curl command to the local server.
`curl --data "" http://localhost:3000/say?message=true`
`curl --data "" http://localhost:3000/shutup`
Open sourced code is available here.
Using the same Node.js/Express combination, a gif(t) displayer was coded up so the talking robots had something to display while they read your message aloud.
Step 3.5 - The Really Fun Part
Arduino time! An Arduino is a programmable microcontroller which allows you to develop in Processing and do cool things like turn on LEDs or make an Iron Man Costume. We're still pretty new at this stuff, so we went with the ability to control Christmas lights and an old electronic toy train set (maybe next year we'll go for the Iron Man Costume).
There's one more piece of this puzzle to introduce which made this process super easy -- dino. Dino is an awesome gem which lets you control your Arduino using Ruby. Simply load up the dino code to your Arduino, set up your board in Ruby, and start sending power where you want it.
require 'dino'
board = Dino::Board.new(Dino::TxRx.new)
pin = Dino::Components::Led.new(pin: 13, board: board)
pin.on
sleep 4
pin.off
We made use of a relay and a power cord cut in half. When the relay switch is open, no power can pass from the wall to our appliance. When we give the command pin.on, we send 5V to our relay, closing the switch, powering our appliance with a full 120V from the wall. A basic tutorial of how to set this up is available here.
Note: To get the Christmas lights to flash, we actually set a Redis key named "flash" to true or false and had a Ruby script checking that variable every second and flashing the lights independent of the robot. This was done to keep blocking operations from interfering with each other.
Step 4 - The Web Site
Viget's home turf. Designer Mark Steinruck, UXers Jason Toth and Lance Gutin, and again the almighty front-end developer Nate came together to make a festive, easy, and fun-to-use site. We leveraged the Dropcam already set up at each office to let users watch each Jinglebot right on the sight, and displayed a running list of the most recent messages as well as aggregate stats on the bots and messages.
Messages and tweets that came in were not only published to the Redis channel, but were also saved to a PostgreSQL database with the help of DataMapper. In this way, we had a clean and organized record of all messages that came in to the Jinglebots.
Step 5 - The Jingle Report
As a little bonus, we wanted to give the user more than just a talking robot. A Jingle Report was created for every message or tweet that came in, and tweets were sent to users with the Report link to view. Here's a personal favorite - http://jinglebots.com/report/901.
Each report required a screenshot of a Jinglebot scene, as well as a voice recording of the message. LAME was used to convert the saved audio files (say -o file/path/to/save.aiff message) into web-friendly formats, some Dropcam craftiness was used to grab screenshots from a given time (thanks to a post in this forum), and Amazon S3 was used to store these assets. Boom: Jingle Reports.
Step 6 - The Auto Pilot
Cronjobs were a big win for this project. Having the code systematically restart every so often meant that if anything did go wrong (a lot of coordinated tech -> a lot of potential problems), it would take care of restarting itself.
This was a major component for things like the amount of sleep Ben and I could get without having to restart the Jinglebots after they mysteriously crashed in the middle of the night. The code behind this is here.
Summary
Come this Friday, the Jinglebots will have been spreading holiday cheer for two whole weeks, and the project has been a blast to work on. It was a great combination of Viget’s coding skills as well as our discovered "building-real-things" skills. More on why the crew involved came together to build something like this can be read here.
Jinglebots was the brainchild of Ben Eckerson (without him the project would never have existed), and the collaborative effort of many - Becky Tornes, Khanh Stenberg, Anjali Mckenzie, Mike Ackerman, and the whole Viget dev team for their advice and mentorship.
Happy Jinglebottin!
Hopefully, you've been able to experience our Jinglebots -- the 2012 Pointless Corp holiday project -- for yourself. Klaus 5000, Cornelius, and Ru 2 Dee 2 are the Jinglebots -- “robots” which reside in each of our Viget offices. They “speak” tweets and messages for all of the world to hear through a Dropcam feed. As a user, you can check out the web site and either tweet with the #jinglebots hashtag or submit a message through a basic messenger on the site.
I've estimated the amount of coordinating technologies to be around a bazillion. For those who may be interested in how to use your computer to control Christmas lights, power electric toy trains, or do other cool things (using Ruby!), I’ll walk you through how to do it below.
Step 1 - Instant Communication
We knew that we'd be responding to messages and tweets in real time. For this, we made use of Redis pub/sub capabilities. Redis is super simple to get going locally and use of RedisToGo gives you access to a free online Redis instance you can use in production. When a message comes in, we publish the message data (sender name, message, timestamp, etc.) in JSON to a Redis channel.
REDIS.publish("holiday_messages", data.to_json)
Each of our Jinglebots is subscribed to the holiday_messages channel.
REDIS.subscribe('holiday_messages') do |on|
on.message do |channel, raw_data|
data = JSON.parse(raw_data)
... some awesome stuff using the data
end
end
Instant communication has never been easier.
Step 2 - Receiving Messages/Tweets
On the web site, a form allows users to submit a message and a name. On submission success, the app then compiles the necessary data, converts it to JSON, and publishes it to the holiday_messages Redis channel.
To capture incoming tweets with the #jinglebots hashtag, we made use of EventMachine and the twitter-stream gem. This bit of code owes great credit to Twerrible Towel which has their code open sourced. The following code takes care of all the Twitter listening for us.
EventMachine::run do
stream = Twitter::JSONStream.connect(
:path => '/1/statuses/filter.json',
:auth => "#{twitter_username}:#{twitter_password}",
:method => 'POST',
:content => "track=#jinglebots"
)
stream.each_item do |item|
tweet = JSON.parse(item)
if tweet && tweet["user"]
data = assemble_data(tweet)
REDIS.publish("holiday_messages", data.to_json)
end
end
end
Step 3 - The Fun Part
So, with a stream of messages coming in, we had to figure out what to do with them. If you're on a Mac, open up the terminal and type say hello master. With the volume turned up, your computer has been given a voice! After some massaging of the incoming message (removing special characters, subbing out bad words for a system beeeeep), we now had robots which could speak any message we threw at them.
We weren't done though. What's a talking robot without a face? Enter the tag team work of designer Joseph Le and front-end developer Nate Hunzaker. A simple-yet-awesome Node.js app on Express meant that we had three different faces (one for each Jinglebot) which could be turned to "talking" and "not talking" mode with a curl command to the local server.
`curl --data "" http://localhost:3000/say?message=true`
`curl --data "" http://localhost:3000/shutup`
Open sourced code is available here.
Using the same Node.js/Express combination, a gif(t) displayer was coded up so the talking robots had something to display while they read your message aloud.
Step 3.5 - The Really Fun Part
Arduino time! An Arduino is a programmable microcontroller which allows you to develop in Processing and do cool things like turn on LEDs or make an Iron Man Costume. We're still pretty new at this stuff, so we went with the ability to control Christmas lights and an old electronic toy train set (maybe next year we'll go for the Iron Man Costume).
There's one more piece of this puzzle to introduce which made this process super easy -- dino. Dino is an awesome gem which lets you control your Arduino using Ruby. Simply load up the dino code to your Arduino, set up your board in Ruby, and start sending power where you want it.
require 'dino'
board = Dino::Board.new(Dino::TxRx.new)
pin = Dino::Components::Led.new(pin: 13, board: board)
pin.on
sleep 4
pin.off
We made use of a relay and a power cord cut in half. When the relay switch is open, no power can pass from the wall to our appliance. When we give the command pin.on, we send 5V to our relay, closing the switch, powering our appliance with a full 120V from the wall. A basic tutorial of how to set this up is available here.
Note: To get the Christmas lights to flash, we actually set a Redis key named "flash" to true or false and had a Ruby script checking that variable every second and flashing the lights independent of the robot. This was done to keep blocking operations from interfering with each other.
Step 4 - The Web Site
Viget's home turf. Designer Mark Steinruck, UXers Jason Toth and Lance Gutin, and again the almighty front-end developer Nate came together to make a festive, easy, and fun-to-use site. We leveraged the Dropcam already set up at each office to let users watch each Jinglebot right on the sight, and displayed a running list of the most recent messages, as well as aggregate stats, on the bots and messages.
Messages and tweets that came in were not only published to the Redis channel, but were also saved to a PostgreSQL database with the help of DataMapper. In this way, we had a clean and organized record of all messages that came in to the Jinglebots.
Step 5 - The Jingle Report
As a little bonus, we wanted to give the user more than just a talking robot. A Jingle Report was created for every message or tweet that came in, and tweets were sent to users with the Report link to view. Here's a personal favorite - http://jinglebots.com/report/901.
Each report required a screenshot of a Jinglebot scene, as well as a voice recording of the message. LAME was used to convert the saved audio files (say -o file/path/to/save.aiff message) into web-friendly formats, some Dropcam craftiness was used to grab screenshots from a given time (thanks to a post in this forum), and Amazon S3 was used to store these assets. Boom: Jingle Reports.
Step 6 - The Auto Pilot
Cronjobs were a big win for this project. Having the code systematically restart every so often meant that if anything did go wrong (a lot of coordinated tech -> a lot of potential problems), it would take care of restarting itself.
This was a major component for things like the amount of sleep Ben and I could get without having to restart the Jinglebots after they mysteriously crashed in the middle of the night. The code behind this is here.
Summary
On Friday the 21st, the Jinglebots had been spreading holiday cheer for two whole weeks, and the project was a blast to work on. It was a great combination of Viget’s coding skills, as well as our discovered "building-real-things" skills. More on why the crew involved came together to build something like this can be read here.
Jinglebots was the brainchild of Ben Eckerson (without him the project would never have existed) and the collaborative effort of many - Becky Tornes, Khanh Stenberg, Anjali Mckenzie, Mike Ackerman, and the whole Viget dev team for their advice and mentorship.
Happy Jinglebottin!
Hopefully, you've been able to experience our Jinglebots -- the 2012 Pointless Corp holiday project -- for yourself. Klaus 5000, Cornelius, and Ru 2 Dee 2 are the Jinglebots -- “robots” which reside in each of our Viget offices. They “speak” tweets and messages for all of the world to hear through a Dropcam feed. As a user, you can check out the web site and either tweet with the #jinglebots hashtag or submit a message through a basic messenger on the site.
I've estimated the amount of coordinating technologies to be around a bazillion. For those who may be interested in how to use your computer to control Christmas lights, power electric toy trains, or do other cool things (using Ruby!), I’ll walk you through how to do it below.
Step 1 - Instant Communication
We knew that we'd be responding to messages and tweets in real time. For this, we made use of Redis pub/sub capabilities. Redis is super simple to get going locally and use of RedisToGo gives you access to a free online Redis instance you can use in production. When a message comes in, we publish the message data (sender name, message, timestamp, etc.) in JSON to a Redis channel.
REDIS.publish("holiday_messages", data.to_json)
Each of our Jinglebots is subscribed to the holiday_messages channel.
REDIS.subscribe('holiday_messages') do |on|
on.message do |channel, raw_data|
data = JSON.parse(raw_data)
... some awesome stuff using the data
end
end
Instant communication has never been easier.
Step 2 - Receiving Messages/Tweets
On the web site, a form allows users to submit a message and a name. On submission success, the app then compiles the necessary data, converts it to JSON, and publishes it to the holiday_messages Redis channel.
To capture incoming tweets with the #jinglebots hashtag, we made use of EventMachine and the twitter-stream gem. This bit of code owes great credit to Twerrible Towel which has their code open sourced. The following code takes care of all the Twitter listening for us.
EventMachine::run do
stream = Twitter::JSONStream.connect(
:path => '/1/statuses/filter.json',
:auth => "#{twitter_username}:#{twitter_password}",
:method => 'POST',
:content => "track=#jinglebots"
)
stream.each_item do |item|
tweet = JSON.parse(item)
if tweet && tweet["user"]
data = assemble_data(tweet)
REDIS.publish("holiday_messages", data.to_json)
end
end
end
Step 3 - The Fun Part
So, with a stream of messages coming in, we had to figure out what to do with them. If you're on a Mac, open up the terminal and type say hello master. With the volume turned up, your computer has been given a voice! After some massaging of the incoming message (removing special characters, subbing out bad words for a system beeeeep), we now had robots which could speak any message we threw at them.
We weren't done though. What's a talking robot without a face? Enter the tag team work of designer Joseph Le and front-end developer Nate Hunzaker. A simple-yet-awesome Node.js app on Express meant that we had three different faces (one for each Jinglebot) which could be turned to "talking" and "not talking" mode with a curl command to the local server.
`curl --data "" http://localhost:3000/say?message=true`
`curl --data "" http://localhost:3000/shutup`
Open sourced code is available here.
Using the same Node.js/Express combination, a gif(t) displayer was coded up so the talking robots had something to display while they read your message aloud.
Step 3.5 - The Really Fun Part
Arduino time! An Arduino is a programmable microcontroller which allows you to develop in Processing and do cool things like turn on LEDs or make an Iron Man Costume. We're still pretty new at this stuff, so we went with the ability to control Christmas lights and an old electronic toy train set (maybe next year we'll go for the Iron Man Costume).
There's one more piece of this puzzle to introduce which made this process super easy -- dino. Dino is an awesome gem which lets you control your Arduino using Ruby. Simply load up the dino code to your Arduino, set up your board in Ruby, and start sending power where you want it.
require 'dino'
board = Dino::Board.new(Dino::TxRx.new)
pin = Dino::Components::Led.new(pin: 13, board: board)
pin.on
sleep 4
pin.off
We made use of a relay and a power cord cut in half. When the relay switch is open, no power can pass from the wall to our appliance. When we give the command pin.on, we send 5V to our relay, closing the switch, powering our appliance with a full 120V from the wall. A basic tutorial of how to set this up is available here.
Note: To get the Christmas lights to flash, we actually set a Redis key named "flash" to true or false and had a Ruby script checking that variable every second and flashing the lights independent of the robot. This was done to keep blocking operations from interfering with each other.
Step 4 - The Web Site
Viget's home turf. Designer Mark Steinruck, UXers Jason Toth and Lance Gutin, and again the almighty front-end developer Nate came together to make a festive, easy, and fun-to-use site. We leveraged the Dropcam already set up at each office to let users watch each Jinglebot right on the sight, and displayed a running list of the most recent messages, as well as aggregate stats, on the bots and messages.
Messages and tweets that came in were not only published to the Redis channel, but were also saved to a PostgreSQL database with the help of DataMapper. In this way, we had a clean and organized record of all messages that came in to the Jinglebots.
Step 5 - The Jingle Report
As a little bonus, we wanted to give the user more than just a talking robot. A Jingle Report was created for every message or tweet that came in, and tweets were sent to users with the Report link to view. Here's a personal favorite - http://jinglebots.com/report/901.
Each report required a screenshot of a Jinglebot scene, as well as a voice recording of the message. LAME was used to convert the saved audio files (say -o file/path/to/save.aiff message) into web-friendly formats, some Dropcam craftiness was used to grab screenshots from a given time (thanks to a post in this forum), and Amazon S3 was used to store these assets. Boom: Jingle Reports.
Step 6 - The Auto Pilot
Cronjobs were a big win for this project. Having the code systematically restart every so often meant that if anything did go wrong (a lot of coordinated tech -> a lot of potential problems), it would take care of restarting itself.
This was a major component for things like the amount of sleep Ben and I could get without having to restart the Jinglebots after they mysteriously crashed in the middle of the night. The code behind this is here.
Summary
On Friday the 21st, the Jinglebots had been spreading holiday cheer for two whole weeks, and the project was a blast to work on. It was a great combination of Viget’s coding skills, as well as our discovered "building-real-things" skills. More on why the crew involved came together to build something like this can be read here.
Jinglebots was the brainchild of Ben Eckerson (without him the project would never have existed) and the collaborative effort of many - Becky Tornes, Khanh Stenberg, Anjali Mckenzie, Mike Ackerman, and the whole Viget dev team for their advice and mentorship.
Happy Jinglebottin!
On a recent Rails application I built, I needed to determine which time zone a user was in to correctly display and use time-related information. I'll walk through two techniques I've found to get the job done.
The theory around working with time zones is pretty straightforward. Save all time-related data in Coordinated Universal Time (UTC), and display all time-related data in the time zone of any given user. If you're unfamiliar with ActiveSupport's TimeWithZone, quickly check out this blog post from David Eisinger and familiarize yourself with the in_time_zone method for display purposes.
The question then becomes, "How do we know what time zone a user is in?"
Method 1 - Quick, simple, 90% right
In search for the answer, I first discovered some simple JavaScript code:
var currentTime = new Date();
var utcOffset = currentTime.getTimezoneOffset()
document.cookie = 'time_zone_offset='+utcOffset+';';
new Date() constructs a date object with the current time based on your system clock. getTimezoneOffset() returns the number of minutes from which you differ from UTC. Throw that in a cookie and you're done with the JavaScript.
On the Rails side of things, you can grab that offset from the cookies and run the following code to determine which time zone has that offset.
offset = cookies["time_zone_offset"].to_i
time_zone = ActiveSupport::TimeZone[-offset.minutes]
current_user.update_attribute(:time_zone => time_zone)
However, This doesn't exactly work. There are multiple time zones that share a common offset. If you use this technique on the east coast of America, it's likely you'll get (GMT-05:00) Bogota, the capitol of Columbia, or (GMT-04:00) Atlantic Time (Canada), depending on if you've recently sprung forward or fallen back. This is due to the fact that these time zones come before (GMT-04/05:00) Eastern Time (US & Canada) alphabetically.
While this approach will still give you the accurate time for the present day, Daylight Savings standards of other regions could affect your code in the future. If your app does not care about the future, this solution is fine. My app does care about the future, though, and suddenly all my tests started failing when Daylight Savings Time came around.
Method 2 - Quick, a little less simple, 100% right
Enter JSTZ! This stands for jsTimezoneDetect and is a sweet bit of code which parses out the actual time zone from your computer's system time. Source code can be found here.
With the set of functions jstz offers, the following lines of code will correctly determine the user's system time zone and store it in a cookie called jstz_time_zone.
var timeZone = jstz.determine();
document.cookie = 'jstz_time_zone='+timeZone.name()+';';
From there, you can retrieve the cookie in any controller and update the time_zone attribute on the user.
current_user.update_attribute(:time_zone => cookies["jstz_time_zone"])
Excellent! Now we are correctly retrieving a user's time zone from their computer and saving it on the user.
Confirming
At this point you have retrieved the user's system time zone, however it's possible that this is not the correct time zone. While it's a good guess to have when asking the user for input on the matter, it's necessary that you ask the user to confirm or select a time zone to guarantee correctness.
<% unless cookies[:selected_a_time_zone] %>
<div class="time-zone-confirmation">
<%= "Are you currently in the following time zone: #{current_user.time_zone}?" %>
<%= button_tag "Yes", :class => 'hide-time-zone-confirmation' %>
<%= button_tag "No", :class => 'show-time-zone-selection' %>
<div class="time-zone-selection" style="display:none;">
<%= simple_form_for @user, :url => "/time_zone", :method => :put do |f| %>
<%= f.input :time_zone, :collection => ActiveSupport::TimeZone.us_zones.map(&:name) %>
<%= f.submit "Submit" %>
<% end %>
</div>
</div>
<% end %>
The following jQuery code accompanies the form to make for a nice user interaction.
$('button.hide-time-zone-confirmation').on('click', function() {
document.cookie = 'selected_a_time_zone=true;';
$('.time-zone-confirmation').hide();
});
$('button.show-time-zone-selection').on('click', function() {
$('.time-zone-selection').show();
});
A route is added in routes.rb to direct the post to the correct controller.
put "/time_zone" => "time_zones#update"
And lastly, here is the controller code to save the decision.
def update
current_user.update_attribute(:time_zone => params["user"]["time_zone"])
cookies[:selected_a_time_zone] = true
redirect_to :back
end
To sum up, we first make our best guess as to what time zone the user is in. We then ask the user to either confirm our guess, or select a time zone from a given list. In both cases, a cookie named selected_a_time_zone is set to true, which prevents the confirmation form from being displayed in the future. Updating a time_zone attribute on the current_user can then be used to correctly display all time-related info.
On a recent Rails application I built, I needed to determine which time zone a user was in to correctly display and use time-related information. I'll walk through two techniques I've found to get the job done.
The theory around working with time zones is pretty straightforward. Save all time-related data in Coordinated Universal Time (UTC), and display all time-related data in the time zone of any given user. If you're unfamiliar with ActiveSupport's TimeWithZone, quickly check out this blog post from David Eisinger and familiarize yourself with the in_time_zone method for display purposes.
The question then becomes, "How do we know what time zone a user is in?"
Method 1 - Quick, simple, 90% right
In search for the answer, I first discovered some simple JavaScript code:
var currentTime = new Date();
var utcOffset = currentTime.getTimezoneOffset()
document.cookie = 'time_zone_offset='+utcOffset+';';
new Date() constructs a date object with the current time based on your system clock. getTimezoneOffset() returns the number of minutes from which you differ from UTC. Throw that in a cookie and you're done with the JavaScript.
On the Rails side of things, you can grab that offset from the cookies and run the following code to determine which time zone has that offset.
offset = cookies["time_zone_offset"].to_i
time_zone = ActiveSupport::TimeZone[-offset.minutes]
current_user.update_attribute(:time_zone => time_zone)
However, This doesn't exactly work. There are multiple time zones that share a common offset. If you use this technique on the east coast of America, it's likely you'll get (GMT-05:00) Bogota, the capitol of Columbia, or (GMT-04:00) Atlantic Time (Canada), depending on if you've recently sprung forward or fallen back. This is due to the fact that these time zones come before (GMT-04/05:00) Eastern Time (US & Canada) alphabetically.
While this approach will still give you the accurate time for the present day, Daylight Savings standards of other regions could affect your code in the future. If your app does not care about the future, this solution is fine. My app does care about the future, though, and suddenly all my tests started failing when Daylight Savings Time came around.
Method 2 - Quick, a little less simple, 100% right
Enter JSTZ! This stands for jsTimezoneDetect and is a sweet bit of code which parses out the actual time zone from your computer's system time. Source code can be found here.
With the set of functions jstz offers, the following lines of code will correctly determine the user's system time zone and store it in a cookie called jstz_time_zone.
var timeZone = jstz.determine();
document.cookie = 'jstz_time_zone='+timeZone.name()+';';
From there, you can retrieve the cookie in any controller and update the time_zone attribute on the user.
current_user.update_attribute(:time_zone => cookies["jstz_time_zone"])
Excellent! Now we are correctly retrieving a user's time zone from their computer and saving it on the user.
Confirming
At this point you have retrieved the user's system time zone, however it's possible that this is not the correct time zone. While it's a good guess to have when asking the user for input on the matter, it's necessary that you ask the user to confirm or select a time zone to guarantee correctness.
<% unless cookies[:selected_a_time_zone] %>
<div class="time-zone-confirmation">
<%= "Are you currently in the following time zone: #{current_user.time_zone}?" %>
<%= button_tag "Yes", :class => 'hide-time-zone-confirmation' %>
<%= button_tag "No", :class => 'show-time-zone-selection' %>
<div class="time-zone-selection" style="display:none;">
<%= simple_form_for @user, :url => "/time_zone", :method => :put do |f| %>
<%= f.input :time_zone, :collection => ActiveSupport::TimeZone.us_zones.map(&:name) %>
<%= f.submit "Submit" %>
<% end %>
</div>
</div>
<% end %>
The following jQuery code accompanies the form to make for a nice user interaction.
$('button.hide-time-zone-confirmation').on('click', function() {
document.cookie = 'selected_a_time_zone=true;';
$('.time-zone-confirmation').hide();
});
$('button.show-time-zone-selection').on('click', function() {
$('.time-zone-selection').show();
});
A route is added in routes.rb to direct the post to the correct controller.
put "/time_zone" => "time_zones#update"
And lastly, here is the controller code to save the decision.
def update
current_user.update_attribute(:time_zone => params["user"]["time_zone"])
cookies[:selected_a_time_zone] = true
redirect_to :back
end
To sum up, we first make our best guess as to what time zone the user is in. We then ask the user to either confirm our guess, or select a time zone from a given list. In both cases, a cookie named selected_a_time_zone is set to true, which prevents the confirmation form from being displayed in the future. Updating a time_zone attribute on the current_user can then be used to correctly display all time-related info.
Recently, we've been doing a lot more with Rails engines. We've developed a few engines that we've released publicly, and even more that we use privately on applications. We've found it's a good way to organize and share reusable code across a number of applications.
We really like using RSpec, Capybara, and FactoryGirl to test our Rails applications, and we like to use them to test our engines too. Here's a few steps to get your new engine up and running with these gems in no time:
-
Run
rails plugin new ENGINE_NAME --fullorrails plugin new ENGINE_NAME --mountable. This is a good discussion of why you'd choose mountable or full engines. -
Add these lines to the
gemspecfile:s.add_development_dependency 'rspec-rails' s.add_development_dependency 'capybara' s.add_development_dependency 'factory_girl_rails' -
Modify the
gemspec'stest_filesline to this:s.test_files = Dir["spec/**/*"] -
Modify
Rakefileto look like this:#!/usr/bin/env rake begin require 'bundler/setup' rescue LoadError puts 'You must `gem install bundler` and `bundle install` to run rake tasks' end APP_RAKEFILE = File.expand_path("../spec/dummy/Rakefile", __FILE__) load 'rails/tasks/engine.rake' Bundler::GemHelper.install_tasks Dir[File.join(File.dirname(__FILE__), 'tasks/**/*.rake')].each {|f| load f } require 'rspec/core' require 'rspec/core/rake_task' desc "Run all specs in spec directory (excluding plugin specs)" RSpec::Core::RakeTask.new(:spec => 'app:db:test:prepare') task :default => :specThis will setup your
Rakefileto run your specs and make that the default task. It will also setup the specs to reload the test database just like how it works inside a Rails application. -
Make a spec directory:
mkdir spec -
Move the dummy application to the spec directory:
mv test/dummy spec/ -
Remove the test directory:
rm -fR test -
Modify the
.gitignorefile. Replacetestwithspecon these lines:test/dummy/db/*.sqlite3 test/dummy/log/*.log test/dummy/tmp/ test/dummy/.sass-cache -
Create a
spec/spec_helper.rbfile:ENV['RAILS_ENV'] ||= 'test' require File.expand_path("../dummy/config/environment.rb", __FILE__) require 'rspec/rails' require 'rspec/autorun' require 'factory_girl_rails' Rails.backtrace_cleaner.remove_silencers! # Load support files Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f } RSpec.configure do |config| config.mock_with :rspec config.use_transactional_fixtures = true config.infer_base_class_for_anonymous_controllers = false config.order = "random" endThis code requires all the gems you need for writing your specs, loads the dummy application, and configures RSpec.
-
Finally, add this config to your engine file (lives at
lib/my_engine/engine.rb):module MyEngine class Engine < ::Rails::Engine config.generators do |g| g.test_framework :rspec, :fixture => false g.fixture_replacement :factory_girl, :dir => 'spec/factories' g.assets false g.helper false end end endHere, we're telling Rails when generating models, controllers, etc. for your engine to use RSpec and FactoryGirl, instead of the default of
Test::Unitand fixtures
After this, you can start writing specs with FactoryGirl factories and integration specs (inside the spec/features directory) with Capybara. Have fun testing!
UPDATED: I've updated the instructions based on feedback in the comments suggesting the use of the --dummy-path=spec/dummy --skip-test-unit options on the rails plugin new command.
Recently, we've been doing a lot more with Rails engines. We've developed a few engines that we've released publicly, and even more that we use privately on applications. We've found it's a good way to organize and share reusable code across a number of applications.
We really like using RSpec, Capybara, and FactoryGirl to test our Rails applications, and we like to use them to test our engines too. Here's a few steps to get your new engine up and running with these gems in no time:
-
Run
rails plugin new ENGINE_NAME --dummy-path=spec/dummy --skip-test-unit --fullorrails plugin new ENGINE_NAME --dummy-path=spec/dummy --skip-test-unit --mountable. This is a good discussion of why you'd choose mountable or full engines. -
Add these lines to the
gemspecfile:s.add_development_dependency 'rspec-rails' s.add_development_dependency 'capybara' s.add_development_dependency 'factory_girl_rails' -
Add this line to your
gemspecfile:s.test_files = Dir["spec/**/*"] -
Modify
Rakefileto look like this:#!/usr/bin/env rake begin require 'bundler/setup' rescue LoadError puts 'You must `gem install bundler` and `bundle install` to run rake tasks' end APP_RAKEFILE = File.expand_path("../spec/dummy/Rakefile", __FILE__) load 'rails/tasks/engine.rake' Bundler::GemHelper.install_tasks Dir[File.join(File.dirname(__FILE__), 'tasks/**/*.rake')].each {|f| load f } require 'rspec/core' require 'rspec/core/rake_task' desc "Run all specs in spec directory (excluding plugin specs)" RSpec::Core::RakeTask.new(:spec => 'app:db:test:prepare') task :default => :specThis will setup your
Rakefileto run your specs and make that the default task. It will also setup the specs to reload the test database just like how it works inside a Rails application. -
Create a
spec/spec_helper.rbfile:ENV['RAILS_ENV'] ||= 'test' require File.expand_path("../dummy/config/environment.rb", __FILE__) require 'rspec/rails' require 'rspec/autorun' require 'factory_girl_rails' Rails.backtrace_cleaner.remove_silencers! # Load support files Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f } RSpec.configure do |config| config.mock_with :rspec config.use_transactional_fixtures = true config.infer_base_class_for_anonymous_controllers = false config.order = "random" endThis code requires all the gems you need for writing your specs, loads the dummy application, and configures RSpec.
-
Finally, add this config to your engine file (lives at
lib/my_engine/engine.rb):module MyEngine class Engine < ::Rails::Engine config.generators do |g| g.test_framework :rspec, :fixture => false g.fixture_replacement :factory_girl, :dir => 'spec/factories' g.assets false g.helper false end end endHere, we're telling Rails when generating models, controllers, etc. for your engine to use RSpec and FactoryGirl, instead of the default of
Test::Unitand fixtures
After this, you can start writing specs with FactoryGirl factories and integration specs (inside the spec/features directory) with Capybara. Have fun testing!
UPDATED: I've updated the instructions based on feedback in the comments suggesting the use of the --dummy-path=spec/dummy --skip-test-unit options on the rails plugin new command.
Recently, we've been doing a lot more with Rails engines. We've developed a few engines that we've released publicly, and even more that we use privately on applications. We've found it's a good way to organize and share reusable code across a number of applications.
We really like using RSpec, Capybara, and FactoryGirl to test our Rails applications, and we like to use them to test our engines too. Here's a few steps to get your new engine up and running with these gems in no time:
-
Run
rails plugin new ENGINE_NAME --dummy-path=spec/dummy --skip-test-unit --fullorrails plugin new ENGINE_NAME --dummy-path=spec/dummy --skip-test-unit --mountable. This is a good discussion of why you'd choose mountable or full engines. -
Add these lines to the
gemspecfile:s.add_development_dependency 'rspec-rails' s.add_development_dependency 'capybara' s.add_development_dependency 'factory_girl_rails' -
Add this line to your
gemspecfile:s.test_files = Dir["spec/**/*"] -
Modify
Rakefileto look like this:#!/usr/bin/env rake begin require 'bundler/setup' rescue LoadError puts 'You must `gem install bundler` and `bundle install` to run rake tasks' end APP_RAKEFILE = File.expand_path("../spec/dummy/Rakefile", __FILE__) load 'rails/tasks/engine.rake' Bundler::GemHelper.install_tasks Dir[File.join(File.dirname(__FILE__), 'tasks/**/*.rake')].each {|f| load f } require 'rspec/core' require 'rspec/core/rake_task' desc "Run all specs in spec directory (excluding plugin specs)" RSpec::Core::RakeTask.new(:spec => 'app:db:test:prepare') task :default => :specThis will setup your
Rakefileto run your specs and make that the default task. It will also setup the specs to reload the test database just like how it works inside a Rails application. -
Create a
spec/spec_helper.rbfile:ENV['RAILS_ENV'] ||= 'test' require File.expand_path("../dummy/config/environment.rb", __FILE__) require 'rspec/rails' require 'rspec/autorun' require 'factory_girl_rails' Rails.backtrace_cleaner.remove_silencers! # Load support files Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f } RSpec.configure do |config| config.mock_with :rspec config.use_transactional_fixtures = true config.infer_base_class_for_anonymous_controllers = false config.order = "random" endThis code requires all the gems you need for writing your specs, loads the dummy application, and configures RSpec.
-
Finally, add this config to your engine file (lives at
lib/my_engine/engine.rb):module MyEngine class Engine < ::Rails::Engine config.generators do |g| g.test_framework :rspec, :fixture => false g.fixture_replacement :factory_girl, :dir => 'spec/factories' g.assets false g.helper false end end endHere, we're telling Rails when generating models, controllers, etc. for your engine to use RSpec and FactoryGirl, instead of the default of
Test::Unitand fixtures
After this, you can start writing specs with FactoryGirl factories and integration specs (inside the spec/features directory) with Capybara. Have fun testing!
Have you ever written code like this:
def my_method
begin
object.method_that_can_raise_exception
rescue Exception
# some exception handling
end
end
Whenever we write code like this we should stop ourselves and ask: “Is this an exception I need to know about?” Sometimes the answer is legitimately “no”, but there are important cases where you need to know about these caught exceptions.
For instance, sometimes you’re just rescuing a ActiveRecord::RecordNotFound error, in these cases you often know exactly why the error happened, and you know exactly what needs to happen because of it. In these very specific cases you have excellent insight into what’s happening, and the error you’re rescuing is very specific, so silently swallowing these errors is fine.
However, there are some common situations where you need to be aware that exceptions are happening:
1. Rescuing a very generic exception class
If you’re going to be rescuing Exception, StandardError, TimeoutError, IOError, RuntimeError, a descendant of SignalException, or something equally generic, you should probably be notifying yourself of these. If you’re going to be rescuing something this generic, it’s a signal to yourself that you probably don’t know a lot about what can go wrong here or why. Capturing what went wrong is the first step to understanding and solving a problem.
2. Making a connection to an external service
If you’re putting a rescue around a network call to an external service (any service you don’t control, and perhaps maybe those you do control but are on separate servers), you should probably notify yourself that something went wrong. Similar to the situation above, you often have little insight (at the time you’re writing the code) into why it might fail. The external service may be down, or maybe your servers are having network issues. Whatever the reason, a remedy needs to be found, and the easiest way to start diagnosing the problem is with good insight into went wrong.
3. Mystery code
Perhaps you’re using someone else’s library, or maybe some code internal to your application was written long ago and is now legacy code. Whatever the reason, even if you’re using a more specific exception class, if you don’t know why you need to rescue the exception you should probably be notifying yourself that it’s happening.
How you notify yourself and track these errors is entirely up to you. We use Airbrake, but there are lots of options available including just using ActionMailer. Here’s an example of how I might use Airbrake to handle catching an error from an external service:
module APIClient
private
def api_call(method, options)
# network code to external service
rescue Exception => exception
Airbrake.notify(exception, {
:component => self.class.to_s,
:action => method,
:url => url_of_api_we_are_using,
:parameters => options,
:cgi_data => ENV
})
end
end
class MyAPI
include APIClient
def some_api_method(options)
# some other code perhaps
api_call('api_method', options)
end
end
With this notification, I’m trying to capture the name of the API (self.class.to_s), the API endpoint/method called (method), the exact URL we are hitting (url_of_api_we_are_using), the options/parameters we’re passing to the API (options), and any ENV data that might be configured on the server. If you’re worried about any portion of this having sensitive data (the options or the ENV for instance), you should scrub that data first, or not include that data at all. If you’re constructing a large body to post (in an XML API for instance), it can be valuable to capture that too. With Airbrake, I’d probably put a large body like that in the hash I pass to :parameters.
For errors not connecting to an external service, there’s often a lot less data to report. It might be as simple as this:
Airbrake.notify(exception, {
:component => self.class.to_s,
:cgi_data => ENV
})
You might, however, have something relevant to put in the :parameters option.
Whatever service you choose and data you send though, it’s important that you get these notifications and investigate exactly what went wrong. You’ll thank yourself later.
Have you ever written code like this:
def my_method
begin
object.method_that_can_raise_exception
rescue Exception
# some exception handling
end
end
Whenever we write code like this we should stop ourselves and ask: “Is this an exception I need to know about?” Sometimes the answer is legitimately “no”, but there are important cases where you need to know about these caught exceptions.
For instance, sometimes you’re just rescuing a ActiveRecord::RecordNotFound error, in these cases you often know exactly why the error happened, and you know exactly what needs to happen because of it. In these very specific cases you have excellent insight into what’s happening, and the error you’re rescuing is very specific, so silently swallowing these errors is fine.
However, there are some common situations where you need to be aware that exceptions are happening:
1. Rescuing a very generic exception class
If you’re going to be rescuing Exception, StandardError, TimeoutError, IOError, RuntimeError, a descendant of SignalException, or something equally generic, you should probably be notifying yourself of these. If you’re going to be rescuing something this generic, it’s a signal to yourself that you probably don’t know a lot about what can go wrong here or why. Capturing what went wrong is the first step to understanding and solving a problem.
2. Making a connection to an external service
If you’re putting a rescue around a network call to an external service (any service you don’t control, and perhaps maybe those you do control but are on separate servers), you should probably notify yourself that something went wrong. Similar to the situation above, you often have little insight (at the time you’re writing the code) into why it might fail. The external service may be down, or maybe your servers are having network issues. Whatever the reason, a remedy needs to be found, and the easiest way to start diagnosing the problem is with good insight into went wrong.
3. Mystery code
Perhaps you’re using someone else’s library, or maybe some code internal to your application was written long ago and is now legacy code. Whatever the reason, even if you’re using a more specific exception class, if you don’t know why you need to rescue the exception you should probably be notifying yourself that it’s happening.
How you notify yourself and track these errors is entirely up to you. We use Airbrake, but there are lots of options available including just using ActionMailer. Here’s an example of how I might use Airbrake to handle catching an error from an external service:
module APIClient
private
def api_call(method, options)
# network code to external service
rescue Exception => exception
Airbrake.notify(exception, {
:component => self.class.to_s,
:action => method,
:url => url_of_api_we_are_using,
:parameters => options,
:cgi_data => ENV
})
end
end
class MyAPI
include APIClient
def some_api_method(options)
# some other code perhaps
api_call('api_method', options)
end
end
With this notification, I’m trying to capture the name of the API (self.class.to_s), the API endpoint/method called (method), the exact URL we are hitting (url_of_api_we_are_using), the options/parameters we’re passing to the API (options), and any ENV data that might be configured on the server. If you’re worried about any portion of this having sensitive data (the options or the ENV for instance), you should scrub that data first, or not include that data at all. If you’re constructing a large body to post (in an XML API for instance), it can be valuable to capture that too. With Airbrake, I’d probably put a large body like that in the hash I pass to :parameters.
For errors not connecting to an external service, there’s often a lot less data to report. It might be as simple as this:
Airbrake.notify(exception, {
:component => self.class.to_s,
:cgi_data => ENV
})
You might, however, have something relevant to put in the :parameters option.
Whatever service you choose and data you send though, it’s important that you get these notifications and investigate exactly what went wrong. You’ll thank yourself later.
We build a lot of small apps here at Viget as part of Pointless Corp, like SpeakerRate, OfficeGames, and BabyBookie. It’s fun to track how many people are using them, and rather than write yet another Rakefile to generate reports, I decided to create a simple Rails Engine to display some basic stats. Announcing, then, StatBoard:

Installation is a cinch: add the gem to your Gemfile, mount the app in routes.rb, and set the models to query (full instructions available on the GitHub page). The code itself is embarrassingly simple, so if you have any ideas for improvements, or just want to see how a simple Rails Engine works, take a look.
We build a lot of small apps here at Viget as part of Pointless Corp, like SpeakerRate, OfficeGames, and BabyBookie. It’s fun to track how many people are using them, and rather than write yet another Rakefile to generate reports, I decided to create a simple Rails Engine to display some basic stats. Announcing, then, StatBoard:

Installation is a cinch: add the gem to your Gemfile, mount the app in routes.rb, and set the models to query (full instructions available on the GitHub page). The code itself is embarrassingly simple, so if you have any ideas for improvements, or just want to see how a simple Rails Engine works, take a look.







