giant robots smashing into other giant robots

Written by thoughtbot

Episode 36: A gem called exploit

This week Ben Orenstein is joined by Nick Quaranto, developer at 37signals and one of the maintainers of RubyGems.org. Nick and Ben discuss the just released Basecamp iOS app, the architecture of the app, the origins of the app and how it became what it is today, and RubyMotion in general. They then move on to discuss the recent RubyGems.org cracking, the mechanism behind it, the process of restoring the service, and how it might affect RubyGems going forward. They then circle back to talk more about RubyMotion, testing, working at 37signals, Co-work Buffalo, OpenHack, and good coffee.

dancroak

./bin/setup

In our protocol guide, we instruct new developers to set up an existing Rails app like this:

git clone git@github.com:organization/app.git
cd app
./bin/setup

The goal of the bin/setup script is quick, reliable, consistent setup. It is placed in the bin directory to match new Rails conventions about executables.

Here’s an example bin/setup:

#!/bin/sh

# Set up Rails app. Run this script immediately after cloning the codebase.
# https://github.com/thoughtbot/guides/tree/master/protocol

# Set up Ruby dependencies
bundle install --binstubs

# Set up staging and production git remotes
git remote add staging git@heroku.com:app-staging.git
git remote add production git@heroku.com:app-production.git

# Set up database
bundle exec rake db:setup

# Set up configurable environment variables for Foreman
if [ ! -f .env ]; then
  echo "RACK_ENV=development" > .env
fi

echo "port: 7000" > .foreman

# Set up DNS through Pow
if [ -d ~/.pow ]
then
  echo 7000 > ~/.pow/`basename $PWD`
else
  echo "Pow not set up but the team uses it for this project. Setup: http://goo.gl/RaDPO"
fi

The first section uses Bundler’s binstubs.

The second section sets up git remotes for staging and production commands.

The third section creates the development and test databases, loads the schema, and initializes with the seed data. It does not need to run all the migrations.

The last two sections use Foreman as process manager, Pow as DNS server and HTTP proxy.

This is just an example bin/setup file. Each project will be different. Some might not use Pow. Some might test if Redis or MongoDB is installed and run, install, or print a message if not. Some might want to pull some ENV variables into .env from Heroku.

Regardless of the bin/setup file’s contents, a developer should be able to clone the project and run a single, consistent, reliable command to start contributing.

Written by .

cpytel

Our Intro to Ruby on Rails workshop is now available online

I’m very pleased announce that our popular Intro to Ruby on Rails workshop is now available to take as a month-long online version.

The online workshop will run from February 4th to March 1st. After that, you get ongoing support from the thoughtbot team for any Ruby on Rails questions you have.

Our online workshops have been going very well, and in this latest round we’ve switched from text-based Campfire chat for office hours to full audio and video in Google Hangouts.

Register today for the upcoming online session of Intro to Ruby on Rails.

dancroak

Delivering all email from staging to a group email address

All email from the staging environment of a Rails app can be intercepted and delivered to a group email address. This avoids accidentally delivering staging email to production customers and lets the product team see all the emails that are being sent to customers.

Configure

Gemfile:

gem 'recipient_interceptor'

config/initializers/mail.rb:

if Rails.env.staging? || Rails.env.production?
  MAIL_SETTINGS = {
    address: 'smtp.sendgrid.net',
    authentication: :plain,
    domain: 'heroku.com',
    password: ENV['SENDGRID_PASSWORD'],
    port: '587',
    user_name: ENV['SENDGRID_USERNAME']
  }
end

config/environments/{staging,production}.rb:

require Rails.root.join('config/initializers/mail')

My::Application.configure do
  config.action_mailer.delivery_method = :smtp
  config.action_mailer.smtp_settings = MAIL_SETTINGS
end

Also in config/environments/staging.rb:

Mail.register_interceptor RecipientInterceptor.new(ENV['EMAIL_RECIPIENTS'])

Use the ENV['EMAIL_RECIPIENTS'] environment variable to update the list of email addresses that should receive staging emails. For example:

heroku config:add EMAIL_RECIPIENTS="staging@example.com" --remote staging

Gmail filter

Depending on the app, this may generate thousands of emails a day. Avoid spamming yourself by setting up a Gmail filter for emails sent to staging@example.com.

Written by .

dancroak

Improving Rails boot time with Zeus

Zeus improves Rails boot time. Saving seconds is most important when running focused tests:

rspec spec/models/user_spec.rb
rspec spec/models/user_spec.rb:123

Those are times when a tight feedback loop make a meaningful difference.

Install

Install the Zeus gem on your machine:

gem install zeus

Do not include it in your Gemfile. It is an external piece of software.

Set up

Initialize:

zeus init

This will create two files in your Rails app’s directory. Ignore them globally in ~/.gitignore:

custom_plan.rb
zeus.json

Edit zeus.json to include only the tasks for which you’ll use Zeus. Mine looks like this:

{
  "command": "ruby -rubygems -r./custom_plan -eZeus.go",

  "plan": {
    "boot": {
      "default_bundle": {
        "development_environment": {
          "prerake": {"rake": []},
          "console": ["c"],
          "generate": ["g"]
        },
        "test_environment": {
          "test_helper": {"test": ["rspec"]}
        }
      }
    }
  }
}

I remove cucumber in favor of RSpec and Capybara. I remove server in favor of Foreman and Pow.

Force the test environment

In spec/spec_helper.rb, change:

ENV['RAILS_ENV'] ||= 'test'

To:

ENV['RAILS_ENV'] = 'test'

Remove auto-running code

The goal is to run tests in the context of Zeus. So, remove other similar systems.

From the RSpec docs:

> Generally, life is simpler if you just use the rspec command. If you > must use the ruby command, however, you’ll want to do the following:

require 'rspec/autorun'

> This tells RSpec to run your examples.

We don’t need this behavior and can cause bugs when used with Zeus.

Remove either of these lines in spec/spec_helper.rb if they exist:

require 'rspec/autorun'
require 'rspec/autotest'

Remove Spork and Guard

For the same reasons, if you’re using Spork and Guard, delete them from your Gemfile, delete your Guardfile, and delete any related Spork code in spec/spec_helper.rb or spec/support/.

Start Zeus

Zeus will need to be running before you can use its commands:

zeus start

I usually run this, and other long-running processes in a tmux session.

Now, those original commands will have the benefit of Rails boot time in under a second:

zeus rspec spec/models/user_spec.rb
zeus rspec spec/models/user_spec.rb:123

Bonus: run specs from vim

Many of us are running specs directly from vim. If you edit your ~/.vimrc to use Zeus like in this commit, you can run focused specs with:

t

Enjoy!

Written by .