Pivotal Labs

Main menu

Skip to primary content
Skip to secondary content
  • About
  • Case Studies
  • Team
    • Executives
    • Locations
      • San Francisco (HQ)
      • Boston
      • Boulder
      • Denver
      • London
      • Los Angeles
      • New York
  • Community
    • Blogs
    • Tech Talks
    • Events
  • Careers
    • Lifestyle
    • Principles & Practices
    • Benefits
    • FAQ
    • Apply
  • Contact
    • Press Room
    • Press Releases
    • In The News
    • Press Kit
  • All
  • Labs
  • Standup
  • Tracker
Tyler Schultz

[Standup][SF] 09/21/12: Get older faster

Tyler Schultz
Friday, September 21, 2012

Interestings

  • Timecop#lens

We just made this pull request to Timecop:

“Add Timecop#lens where time can go FASTER”

Create a new mock_type, :lens which will let time continue, like :travel, but the first argument is a scaling factor which will make time move at an accelerated pace.

https://github.com/jtrupiano/timecop/pull/42

  • 0 Shares
  • Share on Facebook
  • Share on Twitter
Tyler Schultz

[SF][Standup] 09/19/12: ActiveAdmin vs. RailsAdmin… Arrrggg!

Tyler Schultz
Wednesday, September 19, 2012

Interestings

  • ActiveAdmin after_save

If you are using ActiveAdmin, beware that the after_save callback gets fired both when the model gets saved, and when there are validation errors on the model.

It really behaves like a callback after the model save method gets called, regardless of its return value.

  • Testing RailsAdmin custom actions

Let’s say you’re writing a RailsAdmin custom action, and you want to test it with a request spec.

If the test passes when guard is on, but fails when guard is off, then you’ve forgotten that the RailsAdmin initializer does not run when loading a rake task. It does run as part of bundle exec guard start.

This is a performance ‘optimization’ that RailsAdmin adds.

To turn it back on, so you can test custom actions:

task :default => [:load_rails_admin_initializer]
task :load_rails_admin_initializer do
ENV['SKIP_RAILS_ADMIN_INITIALIZER'] = ‘false’
end

  • International Talk Like a Pirate Day!

Arrrgggggg me mateys! To your pairs you scabrous dogs!

  • 0 Shares
  • Share on Facebook
  • Share on Twitter
Glenn Jahnke

7/13/2012 – Happy Friday

Glenn Jahnke
Friday, July 13, 2012

Helps

  • Heroku Maintenance Mode Fail

Does anyone know why maintenance mode doesn’t seem to work? Is there any way to check from the command line that we are in maintenance mode?

– (Ken) This is how I test it on heroku_san: https://github.com/fastestforward/heroku_san/blob/master/features/step_definitions/remote_steps.rb#L130

  • Sending Faxes from Rails

Anyone had to send a fax from Ruby/Rails? Any good SaaS you used to do it?

  • carrierwave custom processing is called twice

Dumb workaround:

def intelligent_crop
crop_to = model.crop_to
# crop_to = [left_x, top_y, width, height]

manipulate! do |img|
  # guard against the second time intelligent_crop is called
  if (img.columns != crop_to[2] || img.rows != crop_to[3])
    img.crop!(*model.crop_to)
  end

  img
end

end

version :cropped_preview do
process :intelligent_crop
end

No one seems to have heard of this particular bug, unfortunately.

  • acts_as_soft_delete

What is the best soft-delete gem to help you not actually delete records?

acts_as_soft_delete_by_field was recommended, however rolling your own is probably also a very reasonable idea: this is pretty closely tied to your business logic.

Interestings

  • validate_presence_of does not work with booleans

…because it fails if the boolean is set to false. Use

validates_inclusion_of :boolean_field, in: [true, false], allow_nil: false

instead.

  • 0 Shares
  • Share on Facebook
  • Share on Twitter
Mark Rushakoff

A Great Example of Vendor-Library Abstraction in ActiveSupport

Mark Rushakoff
Monday, June 18, 2012

Depending on what you’re working on, you may have been bitten at least once by a heavy dependency on a third-party library.
This happens when you become very dependent on the API of someone else’s library, and suddenly you can no longer use that library or its API.

When this is a possibility, the defensive approach to this problem is to write your own API to wrap that API, so that if you need to drop that vendor library, you only have to reimplement the way your wrapper works.

You might think that you only need to worry about this in large, complicated APIs, but it can be worthwhile to do even for a simple API.

ActiveSupport::JSON uses MultiJSON behind the scenes.
Even though ActiveSupport::JSON has really only two publicly available “normal-use” methods (encode and decode which transform Ruby hashes back and forth with JSON objects), the Rails developers were wise enough to even wrap the specific error class that MultiJSON raises, as ActiveSupport::JSON.parse_error.

# File activesupport/lib/active_support/json/decoding.rb, line 50
def parse_error
  MultiJson::DecodeError
end

This way, you can write something like

begin
  obj = ActiveSupport::JSON.decode(some_string)
rescue ActiveSupport::JSON.parse_error
  Rails.logger.warn("Attempted to decode invalid JSON: #{some_string}")
end

And then if/when Rails switches from MultiJSON, you won’t have to change anything in your code to deal with exception handling around JSON.

(PS.
I wrote the documentation for that method recently, so that’s why I had to link to the Edge Guides.
If you haven’t seen it, check out my article on how easy it is to contribute to the Rails documentation.)

  • 0 Shares
  • Share on Facebook
  • Share on Twitter
Mark Rushakoff

We’re finally getting destroy! in Rails 4

Mark Rushakoff
Friday, June 8, 2012

Unlike create!, save!, and friends, the destroy! method didn’t exist in Rails 3.
It took me a while to get used to destroy instead of destroy! from the Rails console and from test code, but Rails 4 will provide destroy!, which is different from destroy in the following ways:

  • Instead of returning false on failure, it will raise ActiveRecord::RecordNotDestroyed
  • If you have a before_destroy callback that returns false, it will still raise ActiveRecord::RecordNotDestroyed

There’s going to be a lot less cycles of “write a test that calls destroy!, see a NoMethodError, change destroy! to destroy, and re-run the test” once Rails 4 is released. I know I’ve lost a few minutes of my life doing that :)

  • 0 Shares
  • Share on Facebook
  • Share on Twitter
Davis W. Frank

Jasmine 1.2 released

Davis W. Frank
Tuesday, June 5, 2012

Jasmine 1.2 has been available, quietly, for a few weeks now. But consider this the official announcement.

This release is relatively minor, but has a lot of things under the hood that will make it easier for us to continue to improve the project. Some highlights:

Jasmine Core Fixes & Features

  • New HTML Runner/Reporter (designed by Sean Durham) is now the default
  • An improved toEqual matcher for deep Objects

Jasmine Gem Fixes & Features

  • Detection and support for the Rails Asset Pipeline
  • All requests served with no-cache headers, helping out when your browser supports them correctly

Development fixes

  • Catch-up on issues with recent Rubygems and Ruby 1.9.3
  • Fixed bugs when developing for Jasmine on Linux
  • Moved CI to Travis
  • Cleaned up the building/concat of jasmine.js
  • Overall better task code, now tested, for building & testing Jasmine

In addition, we’ve revamped the Jasmine home page to give you a better online reference for using Jasmine every day in your projects. It should cover all of the public interface for writing tests. If we’ve missed something, let us know. It uses Rocco with a custom layout and includes Jasmine on the page, giving you not only a reference, but a test run to see if the reference runs green (Big thanks to Michael Jackson of Twitter who made the suggestion of ‘running documentation’).

  • 0 Shares
  • Share on Facebook
  • Share on Twitter
Mark Rushakoff

Testing mass assignment with RSpec-Shoulda

Mark Rushakoff
Monday, May 28, 2012

If you’re new to Rails, or if you’ve been using Rails 2 for a long time, you might not be aware that Shoulda offers an allow_mass_assignment_of matcher that works just like it sounds. Here’s the example from the source code:

it { should_not allow_mass_assignment_of(:password) }
it { should allow_mass_assignment_of(:first_name) }

Having explicit tests for whether fields should be mass-assignable is probably safer than letting developers arbitrarily add or remove fields from the attr_accessible declarations — at least when they break a test they’ll have to think twice about it.

  • 0 Shares
  • Share on Facebook
  • Share on Twitter
Ken Mayer

Deploy strategies for HerokuSan

Ken Mayer
Monday, May 14, 2012

Deploy Strategies

If you look at the network graphs of heroku_san on github, you’ll see a number of branches where the only change is the deletion of the following line from the deploy task:

stage.migrate

If more than a few people are willing to take the effort to fork a gem just so they can delete 1 line, something smells. The reason is that these forkers were using something other than Rails+ActiveRecord+SQL in their project. Some were using Sinatra, others were using Rails, but with CouchDB.

The raison d’ĂȘtre for the heroku_san gem is to make Heroku deploys dirt simple. So, if people are making whole forks to customize the deploy task, we should make it less painful.

Enter strategies

Strategies are an object oriented programming pattern for creating pluggable execution control. Now, there is a new class of objects that inherit from HerokuSan::Deploy::Base. These objects control how deploys are executed for you. The Rails strategy, HerokuSan::Deploy::Rails does exactly what HerokuSan has always done:

  • push to git@heroku.com
  • call rake db:migrate
  • restart

On the other hand, the Sinatra strategy, HerokuSan::Deploy::Sinatra does nothing more than the base strategy:

  • push to git@heroku.com

You can create your own strategies and then configure HerokuSan to use it instead of its default:

Rails 3 projects

Amend your Rakefile:

require 'heroku_san'

class MyStrategy < HerokuSan::Deploy::Base
  def deploy
    super
    # call my own code to do something unique
  end
end

HerokuSan.project = HerokuSan::Project.new(Rails.root.join("config","heroku.yml"), :deploy => MyStrategy)

Sinatra (and other Rack based apps)

Amend your Rakefile

require 'heroku_san'

class MyStrategy < HerokuSan::Deploy::Base
  def deploy
    super
    # call my own code to do something unique
  end
end

config_file = File.join(File.expand_path(File.dirname(__FILE__)), 'config', 'heroku.yml')
HerokuSan.project = HerokuSan::Project.new(config_file, :deploy => MyStrategy)

load "heroku_san/tasks.rb"
  • 0 Shares
  • Share on Facebook
  • Share on Twitter
Ken Mayer

From customer requirements to releasable gem

Ken Mayer
Sunday, May 13, 2012

One of the many pleasures of working at Pivotal Labs is that we are encouraged to release some of our work as open source. Often during the course of our engagements, we write code that might have wide-spread use. Due to the nature of our contracts, we can not unilaterally release such code. Those rights belong to the client. And rightly so. So, it is an even greater pleasure when one of our clients believes in “giving back” to the community, as well.

One such example is this modest gem, attribute_access_controllable which allows you to set read-only access at the attribute level, on a per-instance basis. For example, let’s say that you have a model Person with an attribute birthday, which, for security purposes, cannot be changed once this attribute is set (except, perhaps, by an administrator with extraordinary privileges). Any future attempts to change this attribute will result in a validation error.

e.g.

> alice = Person.new(:birthday => '12/12/12')
=> #<Person id: nil, attr1: nil, created_at: nil, updated_at: nil, read_only_attributes: nil, birthday: "0012-12-12">
> alice.attr_read_only(:birthday)
=> #<Set: {"birthday"}>
> alice.save!
=> true
> alice.birthday = "2012-12-12"
=> "2012-12-12"
> alice.save!
ActiveRecord::RecordInvalid: Validation failed: Birthday is invalid, Birthday is read_only
> alice.save!(:skip_read_only => true)
=> true

Setting this up is trivial, thanks to a Rails generator which does most of the heavy lifting for you.

rails generate attribute_access Person

After that, you need only know about one new method added to your class:

#attr_read_only(*attributes) # Marks attributes as read-only

There are a few others, but this one, plus the new functionality added to #save and #save! will get you quite far.

And if that’s all that you were looking for when you stumbled across this article, then there’s no need to read any further. Go install the gem and have fun (and may your tests be green when you expect them to be).

From customer requirements to releasable gem

On the other hand, if you are interested in how we got from the original customer story to a releasable open sourced gem, read on. The source code for the module is a mere 34 lines long. It implements 2 new methods, a validator and (gently) overrides #save and #save!. Being good Test Driven Developers, we wrote our specs first, and since we wanted this behavior to be included in several models, we wrote our specs as a shared behavior as well. The spec clocks in at 44 lines, slightly longer than our implementation. All in all, tiny. The whole commit was less than 100 lines of code.

AttributeAccessControllable
  it should behave like it has AttributeAccessControllable
    #attr_read_only(:attribute, ...) marks an attribute as read-only
    #read_only_attribute?(:attribute) returns true when marked read-only
    #read_only_attribute?(:attribute) returns false when not marked read-only (or not marked at all)
    #save! raises error when :attribute is read-only
    #save!(:context => :skip_read_only) is okay
    #save is invalid when :attribute is read-only
    #save(:context => :skip_read_only) is okay

In order to get to something “releasable” we needed a few more things, which we put on our To-Do list:

To do

  1. MIT License
  2. A gem specification
  3. Basic documentation in a README file

The list got longer as we fleshed out both the documentation and the integration tests, as you’ll see in a moment, but first, let’s talk about

Getting the legal issues resolved

Pivotal’s open sourcing policy is straightforward and simple to execute; We don’t touch it. We write code for our clients, it’s their code to do with as they please. My particular client liked the work we did for them and thought it would make a great open source gem. The Director of Engineering signed off on the idea and I paired with him to create the github repository during a lunch break. The first commit was tiny, just a basic directory structure and the existing code. I don’t think the tests passed because they lacked a proper RSpec infrastructure.

Creating the gem

bundler gem DIRECTORY

is your best friend. It set up the layout for us, including an MIT License and a gem specification. It had a boilerplate README, too.

Writing the documentation for the code you wished you had

Next, we wrote a draft of the README file which documented what we knew: You needed a migration to create a column called :read_only_attributes and you needed to include the module into the class. Then we started thinking about the pain points of using our code as is. Wouldn’t it be nice if we could create the migration automatically? Rails generators do that sort of thing, how hard could it be? (Famous last words…) It became clear that we needed to test drive out some new features of the gem that supported the actual module.

To do

  1. MIT License
  2. A gem specification
  3. Basic documentation in a README file
  4. Integration test

I am not a big cucumber fan, but…

Really, I’m not. I used to write Cucumber features all the time, but nowadays, I use a combination of RSpec and Capybara to get most of my day-to-day integration testing done. There is, however, one sweet spot for Cucumber that I’m finding more and more useful; A very high-level document that describes essential features in a way that a reader will say, “Ahhh, so that is how it is supposed to work!” Here’s a copy of the spec I wrote:

Feature: Read only attributes

Scenario: In a simple rails application
  Given a new rails application
  And I generate a new migration for the class "Person"
  And I generate an attribute access migration for the class "Person"
  And I have a test that exercises read-only
  When I run `rake spec`
  Then the output should contain "7 examples, 0 failures"

You probably won’t find any web-steps out there to handle these lines. I use Aruba to handle the dirty work of executing shell commands in a safe sandbox-y way. The step definition file hides most of the ugliness. Even so, most readers could figure out what to do, by hand, for each step.

To do

  1. MIT License
  2. A gem specification
  3. Basic documentation in a README file
  4. Integration test
  5. Generator

Big generators

This gem was my first attempt at writing a generator, so it was awkward. I still don’t understand Thor properly. Fortunately, I happened upon Ammeter, which helped me write out test specs for the generator. If you’ve got good specs, then you can sometimes stumble along until you learn enough to get it right. Alex Rothenberg’s original blog post about the gem was quite informative, as were the test cases from the Devise gem.

I have to admit; constructing the generator was more complex than the original module! There are more “moving parts;” templates, usage files, specs, in addition to the generator itself. So there is a certain amount of overhead that might overwhelm the original content. On the other hand, I learned quite a bit, and the gem is far more useful.

require "spec_helper"
require 'generators/attribute_access/attribute_access_generator'

describe AttributeAccessGenerator do
  before do
    prepare_destination
    Rails::Generators.options[:rails][:orm] = :active_record
  end

  describe "the migration" do
    before { run_generator %w(Person) }
    subject { migration_file('db/migrate/create_people.rb') }
    it { should exist }
    it { should be_a_migration }
    it { should contain 'class CreatePeople < ActiveRecord::Migration' }
    it { should contain 'create_table :people do |t|'}
    it { should contain 't.text :read_only_attributes'}
  end

  describe "the class" do
    before { run_generator %w(Person) }
    subject { file('app/models/person.rb') }
    it { should exist }
    it { should contain 'include AttributeAccessControllable' }
  end

Some interesting things to note; you must require the generator, since it is not pulled in by default. The subject of each suite is a file, not the class AttributeAccessGenerator. The migration_file helper prepends the TIMESTAMP onto the migration file for you. If you need to set up more things for your test, destination_root is a helper with a path to the temporary directory. It remains after the tests have run, which makes it useful when debugging.

Here’s something else that I did not know, but it might help new generator writers; the order in which you define your methods in the generator class is significant. I don’t know how this is done, but each “method” in the generator class is executed in turn. This is important for my generator; the model class definition must exist before I inject the new content that mixes in the module, so I had to write the generate_model method before the inject_attribute_access_content method. I was scratching my head over that one for quite awhile.

require "rails/generators/active_record"

class AttributeAccessGenerator < ActiveRecord::Generators::Base
  source_root File.expand_path('../templates', __FILE__)

  def create_migration_file
    if (behavior == :invoke && model_exists?)
      migration_template "migration.rb", "db/migrate/add_read_only_attributes_to_#{table_name}"
    else
      migration_template "migration_create.rb", "db/migrate/create_#{table_name}"
    end
  end

  def generate_model
    invoke "active_record:model", [name], :migration => false unless model_exists? && behavior == :invoke
  end

  def inject_attribute_access_content
    class_path = class_name.to_s.split('::')

    indent_depth = class_path.size
    content = "  " * indent_depth + 'include AttributeAccessControllable' + "n"

    inject_into_class(model_path, class_path.last, content)
  end

To do

  1. MIT License
  2. A gem specification
  3. Basic documentation in a README file
  4. Integration test
  5. Generator
  6. Shareable tests

Yo, I hear you like tests in your tests

Lastly, we want to share the testing love. The gem consumer should not have to write tests to drive out the same feature that we have already tested. That would not be very DRY. So, in order to make our shared behavior, er, um, shareable, we moved it into lib with a few wrappers, namely, the spec_support.rb file, which you can include in your own spec files to test drive adding the module to your own classes.

Which is where And I have a test that exercises read-only comes in. You can see this in the steps.rb file:

require 'spec_helper'
require 'attribute_access_controllable/spec_support'

describe Person do
  it_should_behave_like "it has AttributeAccessControllable", :attr1
end

To do

  1. MIT License
  2. A gem specification
  3. Basic documentation in a README file
  4. Integration test
  5. Generator
  6. Shareable tests

Don’t be afraid to release v1.0.0

I am a strong believer in semantic versioning. I simply can not understand why some core ruby tools are still living in version zero land, even after years and years of development and use. So, after a couple of internal commits, we released v1.0.0 of the gem, and less than a day later released v1.1.0 and then v1.1.1! (You probably shouldn’t use anything less than v1.1.1)

An interesting mix

In summary, we used a lot of tools and techniques to go from a simple commit to a shareable gem:

  • Rails generators
  • Cucumber
  • Aruba
  • Ammeter
  • RSpec shared behaviors
  • Integration tests
  • Generator tests
  • Module tests

I encourage everyone to release as much of their work as possible because it raises the state of the art for us all. There are limits, of course, but that still affords lots of wiggle room. Small gems like attribute_access_controllable won’t change the world, but they ease the pain of staying DRY and we all get to learn a little something.

Thanks

To Social Chorus for choosing to open source this code. And to Pivotal Labs for encouraging a better way to do software engineering.

  • 0 Shares
  • Share on Facebook
  • Share on Twitter
Mark Rushakoff

Getting Compass to put generated sprites somewhere reasonable

Mark Rushakoff
Thursday, May 3, 2012

When generating sprites with Compass (which is extremely easy), we found that the default output directory for your sprites is the same as the root images directory. This is annoying because we would have to add a line line app/assets/images/icons-*.png to our .gitignore, repeated for each sprite file.

We wanted to put all our sprites in a single folder to be put in .gitignore — this was easy to find, by adding config.compass.generated_images_dir = 'public/sprites' to our config/application.rb. The next problem was that while the sprite file was correctly being saved to e.g. public/sprites/icons-xxx.png, the client-facing path to the sprite file was still /assets/icons-xxx.png which was always 404ing.

The final answer came from an open pull request on compass-rails which clearly explains that you need to add the output path to the assets path, e.g. config.assets.paths << Rails.root.join('public', 'sprites'). Finally, we can easily add public/sprites to our .gitignore.

The other gotcha we encountered today is that compass-rails only regenerates the sprite file when the sprites CSS file changes, not when you add or remove files from the globbed path.

  • 0 Shares
  • Share on Facebook
  • Share on Twitter

Topics

  • agile (778)
  • rails (113)
  • testing (87)
  • ruby (83)
  • ruby on rails (70)
  • jobs (62)
  • javascript (54)
  • techtalk (44)
  • rspec (38)
  • activerecord (29)
  • productivity (29)
  • gogaruco (29)
  • ironblogger (29)
  • git (28)
  • nyc (27)
  • rubymine (25)
  • mobile (22)
  • bloggerdome (21)
  • cucumber (20)
  • process (19)
  • pivotal tracker (19)
  • jasmine (19)
  • design (18)
  • ios (18)
  • webos (17)
  • objective-c (17)
  • android (16)
  • palm (16)
  • "soft" ware (16)
  • fun (15)
  • tracker ecosystem (15)
  • ci (15)
  • cedar (15)
  • rails3 (14)
  • performance (14)
  • bdd (14)
  • gem (13)
  • tdd (13)
  • selenium (12)
  • css (12)
  • goruco (12)
  • bundler (12)
  • meetup (11)
  • railsconf (11)
  • nyc-standup (11)
  • capybara (10)
  • mac (10)
  • mojo (10)
  • chef (10)
  • api (10)
Subscribe to rails Feed
  1. ←
  2. 1
  3. 2
  4. 3
  5. 4
  6. 5
  7. 6
  8. 7
  9. ...
  10. 12
  11. →
  • About
  • Case Studies
  • Team
  • Community
  • Careers
  • Contact
  • Labs
  • Events

Contact Us

contact@pivotallabs.com
+1 415-77-PIVOT
TwitterLinkedInFacebook

Pivotal Tracker

Tracker is the award-winning agile project management tool that enables real-time collaboration around a shared, prioritized backlog.
Visit pivotaltracker.com >