the blog

dev

02/05/2016

The past few weeks I have had the pleasure of interning at ActBlue as a tech intern. It's been a great experience and I've had the opportunity to work on a few cool projects. One of my favorite projects during this time, has been experimenting with service workers to prototype a potential new app feature. So go pour yourself a cup of coffee, relax back in your favorite chair, and get ready to learn about an awesome new web technology.

So what's the deal with service workers? (I promise this isn't a Seinfeld joke)

As of today, out of the four big browsers in use: Internet Explorer, Chrome, Safari and Firefox, only Chrome and Firefox provide support for service workers. So you're limited by potential users, but don't let that fool you. Service workers are very powerful. It allows you to do really cool stuff like send messages to your users without them having to actually be on your website. The browser, however, must be open. You can make your website run faster and even keep running when offline. No internet connection? No problem. Keep enjoying your website experience on ActBlue. In the future, there is even talk of websites having geofencing capabilities using service workers. Oh, what's geofencing? Imagine being on ActBlue's website while walking around New York City. Which, of course, for your safety, I urge you not to (considering how often people get hit by cars there). But, for the sake of this blog post, let's say you are walking around NYC on ActBlue’s website, you could potentially trigger different pieces of code to run based on your current location.

Pretty cool!

So what exactly is a Service Worker?

Good question! You're obviously a very astute ActBlue blog reader. A service worker is javascript code that runs in the background of your browser. It basically runs on a different thread than the main browser UI and you can think of it conceptually as code chillin' between the browser, network and website.

Since it runs on a different thread, you can't access the DOM in your service worker code and, for security purposes, you can only use service workers on pages that are served over HTTPs. Finally, the service worker is event-driven. It listens for some sort of event and then when it detects that event, some code is executed.

And, there you have it, that is a service worker. Welcome to the future of the web… potentially.

And if any ActBlue campaign admins out there have read this far, stay tuned for some sweet push contribution notifications.

10/28/2015

A Brief History of Saving Credit Card Numbers at ActBlue

We take payments, it’s what we do. Thus, when donors ask us to, we save their credit card numbers. Saving payment information for our awesome users is immensely important to how well we operate, as we’ve mentioned many times before. Our site is a large Rails app so naturally our initial approach was to save the card numbers1 in our main database alongside the rest of the data we need for each card.2

Motivations

We put the upmost value on security across our entire site, but credit cards are obviously the biggest target and require the most protection. A few years back we were in the process of upgrading to the highest level of PCI3 compliance. Several important changes came with this. Our server infrastructure would need to be certified and contain very strict levels of scrutiny: ultra-restrictive firewalls, intrusion detection, and the like. We would also need to put into place an extra layer of procedures for code changes. We want to make sure that developers are constantly thinking through and documenting all possible ramifications of the changes they are making. Other people then review and approve the new work.

This level of security around credit cards is very important, but we also strive to be agile4 in our development practices. We’re accustomed to deploying site updates multiple times per day in order to get improvements into the hards of our users just as fast as possible. We didn’t want to drag down all our work with extra process and overhead5 when just the credit card number storage requires PCI compliance.

The New Way

In the end we decided to split off a separate service just for the storage of credit cards. This app lives on its own ultra-secure servers and passes tokens back to the main site to save in the place of credit card numbers (which the main app never sees).

How It Works

You click a link somewhere and come to a page with a contribution form on our Rails app. Obviously you are super psyched to donate so you start filling out all your information. At the point when you enter your credit card number things get interesting. A bit of Javascript on the page sends that 166 digit number (and nothing else) in an XHR request to our card number tokenization service. If it finds a previous token for this number in its database it returns that. Otherwise the service randomly comes up with a token for the card, saves the original and the token, and returns the token. The Javascript on the contribution form then swaps that token in for the credit card number in the data that is submitted to the main app. In this way the main app only ever sees the token and never the original card number.

A diagram of our credit card number storage system.

Structure of the Token

While we do want to keep the full credit card number out of our app, there are some structural features of a card number that are rather convenient and we’d rather not lose entirely. The first few digits of the number tell us what type of card this is—Visa, MasterCard, etc. The last four digits are a ubiquitous identifier aiding the donor and our customer service team alike in determining which card was the one used for this transaction.

We designed our tokens around these features. We make them 16 digits long to smell a bit like a credit card number. The first few digits and the last four are the same as the original card number. In the middle we stick a bunch of random letters. Using letters here gives a very straightforward indication that this is a token and not a real credit card number.

Benefits

The most important benefit of this design is an increase in security. Our main app—which is necessarily large, complex, and used by lots of people—has no ability to access any credit card numbers. The application that does store them is much smaller in scope. It can be run on different servers with more lock-down and monitoring. And because it is smaller and simpler, fewer people need to have access in order to keep it up and running.7

A secondary benefit of this design comes from reduced bureaucratic overhead. Our level of PCI compliance brings with it reporting, double checking, paperwork, etc. There’s obviously a ton of good reasons for all this, but there’s also a lot of value in being nimble and shortening the time between writing code and having it running for our customers. Splitting out the code that touches credit card numbers helps us practice our due diligence properly, but just for the bits that need it. Meanwhile we’re still deploying our main application multiple times a day.

This design has been working great for us. Have you done something similar? Or faced with a similar challenge did you take a different path? Let us know, we’d love to hear about it!

7 There’s an additional feature designed to stop theft of the database as well. The card numbers are all encrypted (of course) using an algorithm that requires several people to all enter their personal secret keys (much like a missile silo) before the running server process can decrypt anything. Any time the server restarts, the keys need to be entered again. ↩︎

11/19/2014

In the previous blog post, using a series of tests, we described how strong parameters work. In this post we detail the steps we followed to upgrade our main application in ActBlue.

Starting Point

To help with the process Rails provides the protected_attributes gem. This allows you to run your app on 4.1 without having to make any changes related to mass-assignment protection. The gem brings backwards compatibility by implementing attr_accessible, attr_protected and other methods.

Add these lines to your Gemfile, run bundle install and make all your tests pass (you have tests, right?)

gem 'rails', '~> 4.1'
gem 'protected_attributes'

There are other incompatibilities you will have to resolve, but this post is about strong parameters and we are assuming your tests run green at this point.

Mixing Both

It is unlikely you can make all the changes in a single release and therefore you will want to have both protected attributes and strong parameters working at the same time. So the next step is to add this line to Gemfile and run bundle install:

gem 'strong_parameters'

In every model you want to upgrade add this line to include the ForbiddenAttributesProtection module. This is the way to indicate Rails which models are using the new mechanism, for example:

class Book < ActiveRecord::Base
include ActiveModel::ForbiddenAttributesProtection
end

In the model also remove all calls to attr_accessible and attr_protected, for example:

attr_accessible :isbn, :title
attr_protected :price

In the corresponding controller it is useful to create a private method that whitelists its parameters, for instance:

Dropping Protected Attributes

When you think you have upgraded all your models and controllers and feel you are ready to pull the plug on the old protected attributes, these are the steps we recommend:

Remove these 2 lines from Gemfile and run bundle install.

gem 'protected_attributes'
gem 'strong_parameters'

In Rails 4 the default is strong parameters, so there is no need to include the gem.

Remove the configuration for protected_attributes, this means removing from config/application.rb:

config.active_record.whitelist_attributes = false

Remove from config/environments/test.rb:

config.active_record.mass_assignment_sanitizer = :logger

Remove any include ActiveModel::ForbiddenAttributesProtection from models, added in the previous step.

In the default configuration of strong parameters, when you whitelist only a subset of the params passed to the controller, instead of raising an exception, Rails is going to generate a notification. You can see a test illustrating this.

It is better instead to always raise an exception. This is done by adding this line to config/environments/test.rb:

config.action_controller.action_on_unpermitted_parameters = :raise

Now run all your tests. If you have a large application and you are getting errors you do not understand or the code is not behaving the way you expect, check our previous blog post Understanding Strong Parameters, this is the part where this information is most useful.

Final Step

When you are done with the tests you can remove the line from config/environments/test.rb:

config.action_controller.action_on_unpermitted_parameters = :raise

The default value in Rails is to generate a notification in test and development environments, and ignore otherwise.

You are done! We hope the 2 articles helped you to make the transition smoother.

11/12/2014

Earlier this year, in ActBlue, we completed the upgrade of our main application from Rails 3.2 to 4.1. The last step in the process was incorporating strong parameters.

Several of our models are simple and we did not have a problem following the documentation, RailsCast and other articles. But a good number of models (and its controllers) are more complex or were using our own protection mechanism, and we were dragging our feet on them.

The main issue was that we did not really understand how strong parameters worked. Correction: I did not understand, which is the big realization that took place when I had to explain what I was doing to the rest of the team. The part that is missing from all the articles I read is what happens when you do not use strong parameters in the correct way. For this reason, the best solution was a series of tests, which is what we present here.

In order to minimize the dependencies, the tests were written in MiniTest::Spec, and the only additional gem required is mocha. Ruby version is 2.1.4 and Rails 4.1.6.

The full list of tests can be found in this github repo, following we go through the most important ones:

If you change the version of Rails in your Gemfile from 3.2 to 4.1, without making any other changes, parameters in the controllers will be passed untouched to methods new and update_attributes on your models, raising this error:

The next step is to start whitelisting some parameters by calling the permit method. For sure, you will miss some, which will trigger this notification:

describe 'permit some elements from params and miss others' do
before do
@params = ActionController::Parameters.new @hash
end
it 'should log non-permitted attributes' do
ActiveSupport::Notifications.
expects(:instrument).
with('unpermitted_parameters.action_controller', keys: ['body']).
once
@params.permit(:title).must_equal 'title' => 'Test'
end
end

In Rails 3.2 when you create or update objects on a model and include attributes that do not exist
they willl just be ignored. Version 4.1 raises an exception, which is a better way of handling it,
no one would ever rely on the fact they are ignored, right?

describe 'call permit on attributes that do not exist in the model' do
before do
params = ActionController::Parameters.new @hash.
merge('non_attr' => 'test')
@permitted_params = params.permit(:title, :non_attr)
end
it 'ActiveRecord should raise exception on non-attribute' do
ex = -> { Article.new @permitted_params }.
must_raise ActiveRecord::UnknownAttributeError
ex.message.must_equal 'unknown attribute: non_attr'
end
end

The require method is useful when you want to make sure that certain
parameter is present, if not it will raise an exception:

Note that if there are other keys in the params hash they will be removed:

it 'should filter out everything but the required key' do
@params.require(:article_attributes).must_equal 'title' => 'Test',
'body' =>'test body'
end

Additionally, requiring without calling permit will raise an exception:

it 'should raise error if we try to use it as is (without permit)' do
-> { Article.new @params.require(:article_attributes) }.
must_raise ActiveModel::ForbiddenAttributesError
end

Finally the "standard" way to use strong parameters, this is the form that you will see presented in other blog posts.

describe 'proper use' do
before do
@attributes = @params.require(:article_attributes).
permit(:title, :body)
end
it 'should be fine if we use require and permit combined' do
@article = Article.new @attributes
@article.title.must_equal 'Test'
@article.body.must_equal 'test body'
end
end

Nested attributes on a model that has a one-to-one relation. In the example a comment belongs_to an article:

Nested attributes on a model with a one-to-many relation. The example shows
an article that has_many comments. Note that the controller will receive an
extra level of keys, the integers 0, 1, etc. Rails internally ignores these
numbers so we don't have to include them in the call to permit:

08/29/2013

The vast majority of the time we don’t think much about the height of the web page we are building. Maybe we try to get the most important content “above the fold”, for whatever that’s worth these days, but otherwise we create complex frameworks for horizontal grids while letting the vertical dimension scroll as it wants.

And most of the time that’s just fine. But once in awhile the situation arises where you care about a defined height for a page. That happened to us recently with a metrics status board we have on our wall. This is a single-screen’s worth of our most important numbers, constantly updated throughout the day with no user interaction. After tweaking something or other to fit on the screen for the seven hundred and thirty-second time, and I got fed up and decided this thing should just understand it’s own height and the amount of space each row has within that. I wanted a framework that was just like the grid system we’re already using, only vertical…

So I made it. And I called it: vertical_grid. Maybe a little too on the nose, perhaps?

Visuals

Here's the gist with screenshots. With Bootstrap you have a horizontal grid system like this:

vertical_grid helps you expand it into a vertical grid system, so you get something like this:

(Basically we're mostly looking to avoid this:)

The Details

It’s based on Bootstrap because we’re already using that. Anything already taken care of by Bootstraps horizontal grid we don’t need to recreate. It’s also written using Sass because I don’t need to type the same stuff twelve times over.

The framework is working well for us, but it’s still fresh from the oven. If you try it and come up with some issues or improvements we’d love to see them. Hit us up on the GitHub with bugs and pull requests.

06/19/2012

so, we're using a new service that we've built to tokenize credit cards. we are running this tokenizer at a subdomain of actblue.com (while the app itself runs at a different subdomain: "secure.actblue.com").

thus we run into the great same origin policy. and sadly, we're reminded that nothing is easy.

you could load jQuery here, or set up a bit of a javascript environment, but I chose not to. it is far easier for us to edit and deploy code in our primary app. so we're doing the absolute minimum in the iframe.

the tunnel

now, in our primary app we use something like this to load the iframe.

Check out the slides, check out all those amazing links. Have fun. That'll keep you busy for awhile.

One of those links is to Squeel. Even if you don't care to know what GIS stands for, check that baby out. All I'm going to say is it makes ActiveRecord better like you want it to be; just go scroll through those examples. Word up.

Ilya Grigorik gave a super talk called Making the Web Fast(er). It's all stuff you should know about, and one bit that was new to me was the Navigation Timing stuff from the W3C. (There's one picture in there, so obviously just scroll down to that.) "This specification defines an interface for web applications to access timing information related to navigation and elements." This covers, like, everything, which is cool, and is shows up in Google Analytics, which is even better. Content > Site Speed > Page Timings is the magical incantation, and also the Performance tab will show you histograms which are a cool blue.

Sarah Mei gave a nice shout out to our friends over at Meteor. Meteor is a cool new JavaScript framework for building web apps. I have to link to Meteor a lot because they don’t seem to understand how search crawlers work…

03/30/2012

We use Mixpanel as one of the main tools in our metrics arsenal. It’s great for capturing any event that we think is interesting, and for reporting on conversion funnels.

Since we’ve already defined the events that are important to our business, we can set up A/B tests for all sorts of aspects of our site and measure how they impact those conversions we are already watching.

Let’s say that we have a simple signup conversion defined. We’ll start with an event triggered when a visitor reaches our signup form. If they successfully submit the form a second event is triggered and we count them as having converted. Pretty standard.

Now we have some intro copy on the page asking the user to sign up, and we want to test how altering that language affects the rate at which people make the leap. We have the original paragraph as the control, and we come up with a few alternate options to try out. When we send the form event to Mixpanel, we include a property for this A/B test. We decided to use a unique identifier for the test as the key, and a label for the option the user saw as the value.

In Mixpanel we can drill down into our funnel to examine the breakdown for our test. Here’s what it looks like:

You can get a pretty good ballpark idea of how the different options are performing just by glancing at this chart. For more discipline we’ll want to use the API to pull these numbers out and run them through some stats equations you probably forgot in high school. Stay tuned for more on that process in a later post.

02/10/2012

Like a lot of sites, we display a list of recent blog posts on our homepage. The mechanism by which we get it there has gone through several revisions over the years, and we found it interesting to reflect on the path we’ve took.

1) In the first implementation our application server pulled the RSS feed from the blog inline while generating the response. This is probably the simplest, dumbest thing that could possibly work. I always like starting with the simplest thing that can work. But of course this is slow: the user has to wait for two server responses just to see the homepage, and our app servers are blocked waiting to hear from the blog. We could do better.

2) Well, what’s the simplest way to get the feed there, but not hold up the page waiting for it? Give the user the homepage without the blog content and let them pull that bit asynchronously. The client will still have to wait a little bit for that chunk of content, but the rest of the page will show up quicker. The blog feed probably won’t be the first thing the user’s going to look at anyway. Pretty decent.

3) At some point we decided that our whole site, including the homepage, should run over HTTPS. Sounds like a tangent, right? What does this have to do with the blog feed? Mixed content warnings, that’s what.

You probably know this already, but when you are on a secure page and make an insecure request (like to a blog RSS feed that runs over HTTP), you’re browser’s going to get all, “Yo, dawg, not cool.” Like, ugh.

4) There was no reason for our blog to emigrate to SSL land, so the homepage would have to call the application server to get the feed. Not a big deal there. Really all we need is the titles and URLs for the five most recent entries, and those don’t change very frequently. So we set up a periodic job to call over to the blog, get the RSS feed, and toss the data we care about into Memcached. When the client makes the asynchronous request for the feed, we serve up this small chunk of cached data. Easy and super fast. Game on!

5) And then came the day that Chris Felt Meddlesome. “Uh, guys, why do we still have our users making this extra request?”

Yeah, ok. Once upon a time splitting off that request sped up general page load times. Now it was just in the way. The data we need is always going to be coming from a high speed cache, so our initial troubles with app server blocking are gone. If we moved the feed back into the original page generation we’d eliminate an extra request. So move it we did. And it was good.

So did we just come full circle? Did it take us four changes to fix one inefficiency? Maybe. But each time we did just enough to fix the single problem in front of us. It wasn’t perfect from the start, but it was working, and it was a simple enough implementation that we could easily tweak it over time.

i made the big number move

the hard part was easy

all i had to do was sign up for Pusher, include the Pusher gem (this is a Rails app), and push data to pusher at the end of the contribution flow. I chose to do this after the email receipt was sent. Nothing critical happens after this point, and this was happening in the background, so great. Send receipt, send "cha-ching" message to pusher.

that was so easy i took a moment to feel the future rays from the future sun hit me in the future face in the future. and i knew the gladness of living in the future.

the easy part was hard!

so now with this little bit we can subscribe to the magic future beams of data from pusher.

new Pusher(pusherKey).subscribe("actblue_production").bind('new_contribution', BigNumber.update);

still easy. now, we need to animate the number as contributions roll in.

problem 1: racing contributions

we could get 2 contributions in quick succession, so that the second comes before the first has finished animating.

my strategy: store the target display total in the jQuery 'data' of the element. animate to that stored number, instead of animating according to the number received in the push.

problem 2: the really busy day vs. looking good

if the rate of animation isn't high enough, there would exist a rate of cash flowing in so that the animating "Big Number" would never catch up.

solution 1: just make the rate really really fast. this idea sucks, it looks like crap as just renders a meaningless blur of numbers as contributions come in. it also means that, aside from short bursts, the big number is seldom moving. it would be nicer if it looked like the number was always moving!

solution 2: increase the rate as the displayed number falls further and further behind reality. this got complicated!

problem 3: i don't trust this at all

what if pusher hiccups? i'm afraid you out there are staring at our number and checking our math. solution: just send the whole total with every push to pusher. why not? it's free. so that update function from above, i was a bit insincere, it actually looks like this:

07/29/2011

ActBlue is the leading source of online funds for the Democratic Party and an innovator in the field of grassroots politics. We build tools that are used by hundreds of thousands of people to change the country everyday. We're an established player (eight years strong!) gearing up to make a huge impact on the 2012 election season....and we need you for our team.

Don't be misled by our "so-2006" look (goes along with being one of the oldest rails sites), we don’t mess around. We use best in class tools (rails, postgresql, resque/redis, memcached, jquery, chef) and methods (github, extensive automated testing, continuous integration, deployment, cloud hosting) to deliver the best technology in politics. We are collaborative. We are nimble. We are experts.

You'll be an essential contributor to a small team of opinionated bearded cyclists professionals in our Harvard Square office. You'll have significant responsibility right out of the gate and a voice in designing our architecture and the features we build. You’ll have plenty of leeway to choose the best tools and technologies to implement those features.

We offer autonomy, responsibility, an amazing workplace (full of people geeking out about politics and tech all day), competitive salary, and a benefits package that includes 401k, health, dental, vision, transportation subsidies, and the opportunity to have an outsized impact on politics. Join us.

Please send a cover letter, resume, and a GitHub URL, code sample or portfolio to techjobs@actblue.com.

Wanna be a front end developer?

You should have a solid grasp on web application architecture, a commitment to code quality, and be know your way around jQuery, HTML5, and CSS. Bonus points for design experience and good writing skills.

Wanna be a back end developer?

You should have a solid grasp on web application architecture, a commitment to code quality, and be well-versed in Rails and PostgreSQL. Bonus points for design experience and good writing skills.

Wanna be a sysadmin?

You should have a solid grasp of unix (or linux), web architecture, and at least a couple years as root. You should be familiar with configuration management systems, version control, security, automation, monitoring, performance -- all the usual stuff. Bonus points for experience with Ruby, Ubuntu, or PCI-DSS.

05/27/2011

ActiveRecord uniqueness validation is nice, but you're always open to race conditions, where two application instances (mongrels, passengers, dynos, ...) process the same request at the same time. They both look to see if there is a match, both see there is none, then both write identical copies of the record.

After this, Bad Things Happen. The race condition is glossed over when humans driving web browsers are the only clients, but get much more common when AJAX and automated API clients are involved.

If you care about your data integrity, you need to ensure it at the database level.

Say you've got a postgres backed rails application where users write reviews. You list movies and books, and any given review will be about a movie or a book. (But not both.)

The models are User, Movie, Book, UserReview. Details of User, Movie, Book aren't important for this discussion, here we're interested in the UserReview. (This toy app intentionally leaves out the useful parts, to highlight just the uniqueness constraint part.)

You appear to be hoping that a unique index would constrain a column to
contain at most one null entry. It doesn't work like that, and I
strongly urge you to reconsider what you're using null for. I think you
are in for a world of hurt, well beyond this one particular point,
because the SQL spec's semantics for null are not designed around the
idea that it represents a single distinguishable value. What it
represents is "unknown".

See, this is why we can't have nice things. The guy asks a simple question with a valid problem. And even presents the solution.

OK, fine, so the "SQL spec semantics are not designed around the idea", but it's really quite common to use a null in a foreign key column to mean "I know that there is none". So let's fix the problem rather than getting all lectury about theory, eh?

The trick is to use the SQL COALESCE function to allow that: no, really, I know that NULL means no record.

So let's go back and do the migration to generate the correct unique constraint:

Something I don't understand - is there ever a use case where you would want a nullable foreign key column to be part of a uniqueness constraint and not want this? Perhaps the real problem is that the ActiveRecord constraint generator doesn't do this for me automatically, perhaps by reflecting on the fact the column is nullable?