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
Adam Milligan

Rake, Set, Match!

Adam Milligan
Sunday, August 23, 2009

A few days ago I finally discovered why rake db:migrate:redo consistently angers me nearly as much as watching Paula Dean deep fry the vegetable kingdom. As any devoted connoisseur of the db rake tasks in Rails knows, db:migrate:redo always leaves your schema.rb file in the wrong state. The reason, as mentioned in our standup blog, is that rake will only invoke a given task once in a particular run.

To trivially test this try running a single task twice:

rake db:rollback db:rollback

You’ll find that your database only rolls back one migration. Now, you can set the STEP environment variable when calling db:rollback, but this is, as I said, a trivial example. It gets worse.

Take a look at the implementation of the db:migrate:redo task. The part we’re interested in looks like this:

namespace :migrate do
  task :redo => :environment do
    ...
    Rake::Task["db:rollback"].invoke
    Rake::Task["db:migrate"].invoke
  end
end

That looks fine; db:migrate:redo just verifies that your new migration will properly run down and up without blowing up. Sweet.

But, here’s what db:migrate looks like:

  task :migrate => :environment do
    # Do migratey stuff
    Rake::Task["db:schema:dump"].invoke if ActiveRecord::Base.schema_format == :ruby
  end

And rollback:

  task :rollback => :environment do
    # Do rollbacky stuff
    Rake::Task["db:schema:dump"].invoke if ActiveRecord::Base.schema_format == :ruby
  end

Both db:migrate and db:rollback dump the schema after they run, as they should. If you were to migrate or rollback your database and not dump the schema, then your schema would be in an invalid state. So, of course you can see where this is going, when you run db:migrate:redo the task performs the rollback, dumps the schema, performs the migrate, and then doesn’t dump the schema, because that task has already run. Boom, your schema is one migration behind, db:test:prepare loads the invalid schema into your test database, and all your tests fail (or, worse, pass inappropriately)

Now, I assumed this was a bug in Rake, and so I went on a little investigatory safari through the jungles of the Rake code to find it and kill it. I found the culprit, but invoking each task at most one time is, somewhat surprisingly, the expected behavior; it’s tested and everything. Now I can only wonder why. Why prevent invocation of a task more than once in a given rake run? The code contains unrelated guards against circular task dependencies, so that’s not it. Is this an example of overly-speculative defensive coding, or is there an actual use case for which this behavior is desirable? I’d like to hear from anyone who has written tasks that depend on this behavior, as well as anyone who (like me) considers this behavior unexpected and has run into problems because of it.

Assuming no one steps forward with a compelling reason that Rake should behave this way, I’d suggest that this be changed. I could see the value of it (perhaps as a performance optimization?) if rake tasks were guaranteed to not change the state of anything they operate on, or even were guaranteed to be idempotent; but neither is the case. This behavior severely limits the composability of tasks, since a task writer has to know which atomic tasks have run, and avoid any task that might try to run them again.

In the meantime, Rake provides a way to explicitly re-enable tasks that have run once, but it doesn’t seem to work. The db:schema:dump definition looks like this:

namespace :schema do
  task :dump => :environment do
    # Do dumpy stuff
    Rake::Task["db:schema:dump"].reenable
  end
end

That #reenable call is meant to tell the task “hey, task, you can run again.” I tried calling #reenable on the db:schema:dump task inside the db:migrate and db:rollback tasks as well, but without any luck.

Fellow Pivot David Stevenson would likely put it this way: Khaaaaaaaaaaaaaaann!

  • 0 Shares
  • Share on Facebook
  • Share on Twitter
Adam Milligan

Rails requests missing the HTTP body

Adam Milligan
Saturday, August 15, 2009

This is a bug in Rails that quite likely affects you, but which you’ve even more likely never experienced. I’ve posted it here for the benefit of the small number of people who will run into this problem and turn to Google for help.

In short, if you use Mongrel app servers (this may affect Passenger as well, I don’t know), the first HTTP request to your Rails app after you restart your servers, or otherwise reload your environment, will have an empty HTTP body.

I say you’ve likely never experienced this because the majority of HTTP requests to your Rails app are likely GET requests, which always have empty HTTP bodies. After that first request everything will work just fine. Even if you’re unlucky enough to receive a POST or a PUT request containing a body immediately after restart it will only fail once, which you could easily write off an an anomaly. You also won’t see this behavior in your development environment, or any environment in which you use Mongrel as a web server rather than just an app server.

If you’re interested in a patch for the bug, I’ve submitted one to Rails here.

The source of the problem lies in how ActionController initializes itself. In the actionpack gem you’ll find the lib/action_controller/cgi_ext.rb file, which does little more than load the three files in the cgi_ext directory:

require 'action_controller/cgi_ext/stdinput'
require 'action_controller/cgi_ext/query_extension'
require 'action_controller/cgi_ext/cookie'
...

The cgi_ext/query_extension.rb file is the interesting one:

require 'cgi'

class CGI #:nodoc:
  module QueryExtension
    # Remove the old initialize_query method before redefining it.
    remove_method :initialize_query

    # Neuter CGI parameter parsing.
    def initialize_query
      # Fix some strange request environments.
      env_table['REQUEST_METHOD'] ||= 'GET'

      # POST assumes missing Content-Type is application/x-www-form-urlencoded.
      if env_table['CONTENT_TYPE'].blank? && env_table['REQUEST_METHOD'] == 'POST'
        env_table['CONTENT_TYPE'] = 'application/x-www-form-urlencoded'
      end

      @cookies = CGI::Cookie::parse(env_table['HTTP_COOKIE'] || env_table['COOKIE'])
      @params = {}
    end
  end
end

This replaces the default #initialize_query method provided by Ruby’s CGI library:

    def initialize_query()
      if ("POST" == env_table['REQUEST_METHOD']) and
         %r|Amultipart/form-data.*boundary="?([^";,]+)"?|n.match(env_table['CONTENT_TYPE'])
        boundary = $1.dup
        @multipart = true
        @params = read_multipart(boundary, Integer(env_table['CONTENT_LENGTH']))
      else
        @multipart = false
        @params = CGI::parse(
                    case env_table['REQUEST_METHOD']
                    when "GET", "HEAD"
                      if defined?(MOD_RUBY)
                        Apache::request.args or ""
                      else
                        env_table['QUERY_STRING'] or ""
                      end
                    when "POST"
                      stdinput.binmode if defined? stdinput.binmode
# =====>              stdinput.read(Integer(env_table['CONTENT_LENGTH'])) or ''
                    else
                      read_from_cmdline
                    end
                  )
      end

      @cookies = CGI::Cookie::parse((env_table['HTTP_COOKIE'] or env_table['COOKIE']))
    end

The interesting line is the one I’ve marked with a comment rocket. Notice how it reads from stdinput; this leaves the read pointer at the end of the input stream. Now look back at the Rails override for this method, and notice how it does not read from stdinput, thus leaving the read pointer at the start of the input stream.

This is all fine and dandy as long as all of the ActionController code loads up and patches the CGI library properly. However, ActionController doesn’t load the cgi_ext.rb file (or its dependencies) until it references either the CgiRequest or CGIHandler classes (which require cgi_process.rb, which require cgi_ext.rb), as part of the first request, which is after the default Ruby CGI library has read the input stream containing the request body. ActionController then tries to read the request body assuming the read pointer is at the start of the stream. Oops. Subsequent requests work fine, because everything has now been loaded.

Finding the source of this bug took some doing (Chris Heisterkamp, aka “The Hammer” and I tracked it down together), but the fix is easy. If you look at the patch you’ll see it’s simply a single require in action_controller.rb. You can achieve the same result by requiring ‘action_controller/cgi_ext’ in an initializer file in your app.

Like many problems, this one should go away in Rails 3. Rails has deprecated use of the CGI library, and the CGI extensions have already been removed from the Rails master branch. However, it’s a real problem now, and will remain so for at least some amount of time.

  • 0 Shares
  • Share on Facebook
  • Share on Twitter
Adam Milligan

The Rails identity crisis

Adam Milligan
Sunday, August 9, 2009

Imagine, if you will, that you’re a bookseller. You sell books. Big books, small books, serious books, silly books; if it’s got pages and a cover you’ll sell it. Times being what they are you’ve decided to harness the power of the intertubes to sell your books (a novel idea; ho ho ho). In fact, you’ve decided to build a website, and to expose an API with which your business partners can sell books through their websites. Huzzah.

As it turns out you’re an accomplished Rails developer as well as a thriving bibliophile, so you get to work. Fortunately, you thought ahead and already have information for all of your books in a database. Being well read as you are, you choose to make a RESTful Books resource to show off your books. Any customer can check out a book of their choosing by navigating their browser thusly:


http://www.amazzahn.com/books/1

Huzzah again. Sort of.

You’ve heard about this SEO thing, and you hate how ugly that URL is, so you override #to_param on your Book model to return a nice looking slug. Now that URL from above looks like this:


http://www.amazzahn.com/books/stickwick-stapers

You go about your business, quite pleased with yourself, until you receive a phone call from one of the business partners who use your API; it seems they can no longer look at books through your web service.

Here’s the problem: they’re using ActiveResource to consume your RESTful interface. To get a catalog of books they call Book#find(:all), which executes a books#index request. This returns some XML looking like this:

<books>
  <book>
    <id>1</id>
    <title>Stickwick Stapers</title>
    <author>Farles Wickens</author>
  </book>
  <book>
    <id>2</id>
    <title>Karnaby Fudge</title>
    <author>Darles Chickens</author>
  </book>
etc...
</books>

Now, if they’re interested in Stickwick Stapers by Farles Wickens they call Book#find(1), which returns a 404 error. Oops, of course it does, you’re not looking up books by their database ID any more, you’re looking them up by their URL slug. Your customer needs to call Book#find(’stickwick-stapers’).

Unfortunately, your book XML doesn’t include the URL slug, so your partners are in a bind. Back to work. You change the #to_xml method for your Book model to return something that looks like this:

<book>
  <id>stickwick-stapers</id>
  <title>Stickwick Stapers</title>
  <author>Farles Wickens</author>
</book>

After all, the consumers of your API aren’t really interested in the database ID; or, they shouldn’t be. All is well again, until you get another phone call. It seems now your partners can no longer purchase books through your service.

You’ve exposed the Purchases resource for your partners who want to buy books. A purchase involves simply POSTing to this resource with the ID of the book you want to buy and a quantity (you handle payment offline using a complicated barter system). The POST body looks like this:

<purchase>
  <book_id>ethel-the-aardvard-goes-quantity-surveying</book_id>
  <quantity>7</quantity>
</purchase>

OOPS! ActiveRecord doesn’t expect the URL slug for the book, it wants the database ID.

Well, crap. This is a big problem, and one that has no particularly satisfying solution. Here are the candidates:

  1. Send both the database ID and the URL slug in the API, and try to educate all of your API consumers about when to use one vs. the other. Get ready for some serious customer support time.

  2. Override the #book_id= method in the Purchase model to expect a URL slug for the book. Unfortunately, the web site you developed, at great expense, has all sorts of drop-downs and the like stuffed chock full of book IDs. Changing all of that would be a significant expense, never mind the bugs guaranteed to creep in as developers consistently forget that #book_id= doesn’t actually take an ID.

  3. Write the #book_slug= on the Purchase model, and ask your API uses to start using this method instead. Unfortunately, this means changing the web sites that they have developed, at great expense. You just cost them money, never mind the bugs guaranteed to creep in as developers consistently forget that the method to set the book ID is #book_slug=, not #book_id=.

  4. Stop using those silly slugs and just go back to database IDs. Integers are really quite beautiful, aren’t they?

This little ditty is just an example of a fairly serious problem with Rails:

Sometimes we reference domain objects by their database ID (when creating associations), sometimes we reference domain objects by their URL representation (when finding objects in a controller), but in both cases we call the reference that we use the ID.

ActiveResource is an obvious example of the problem. It expects that the XML it receives for an object will have the <id> attribute, and it uses this attribute to build the URL for that object.

Rails routing codifies the problem with its URL parameter naming convention:

map.resources :books # => /books/:id (show/update/destroy)

Is there any surprise this leads to code that looks like this?

def show
  @book = Book.find_by_id(params[:id])
  ...

Or this?

it "should succeed" do
  get :show, :id => @book.id
  ...

ActiveRecord, whether by intention or not, further enforces this fallacy with the unfortunate convenience that the default implementation of #to_param is simply id.to_s, and that #find_by_id will accept an integer, or a string, or even a string that starts with an integer[1]. So, oftentimes when a project chooses to start using something other than database IDs for URLs the code has a confusing mishmash of methods that use the two interchangeably. Have fun picking that apart.

So, what to do about it? The Rails conventions are largely set in stone, after all, it’s not likely the names of these references will ever change. But, we can be smarter about how we use them:

  1. Stop using #find_by_id in controllers. After all, you’re more than likely not looking for anything there by the database ID. I like the find_by_param plugin as a nice little helper for this. It gives you the #find_by_param and #find_by_param! methods, which you should use in your controllers. It also gives you methods for easily creating URL slugs, but you don’t need to use those until you want them.

  2. Stop writing broken tests. Every time you pass an ID to a routing parameter in a functional test you’re testing a lie. Your tests will pass with the default ActiveRecord behavior, but if you ever decide to override #to_param (most likely after you’ve written about 700 tests like this), they’ll break. My experiences dealing with just this problem on client projects was no small part of the reason I wrote the Wapcaplet plugin and this Rails patch.

  3. Know what you mean and say what you mean. The fact that Rails got this wrong just means that you have to pay closer attention when referencing anything by ID.

  4. Let me know if you come up with any clever solutions.

[1] Rails will treat any string that starts with a database ID the same as the database ID itself in many cases:

  Book.find_by_id("7-biggles-combs-his-hair")
  purchase.book_id = "11-thirty-days-in-the-samarkind-desert-with-the-duchess-of-kent"
  genre.book_ids = ["13-how-to-start-a-fight", "16-blogging-for-dummies"]

This fixes the symptom in many cases, but really just further conflates the IDs. And, if you want something without that ugly integer on the front you’re out of luck.

  • 0 Shares
  • Share on Facebook
  • Share on Twitter
Adam Milligan

Worst case scenario

Adam Milligan
Monday, August 3, 2009

Years ago, after I finished college but before I started working professionally with software, I spent a couple years working as a paramedic. I learned a lot from that job, not least about interacting with people who really, really don’t want you in their lives.

One of the calls I remember most vividly happened around three in the morning, not long after schools had let out for the summer. A group of recently graduated high school girls had rolled their Ford Bronco on the highway. When we arrived an engine company was on scene, busily cutting the remains of the car into fun size Bronco strips. I followed the trajectory implied by the hole in the windshield and found my patient, the driver, on the pavement some distance from the car.

While I set about preparing to package her up for a quick trip to the hospital another engine company arrived. As I started my cursory physical exam the lieutenant rushed over and demanded I stop. To understand his reasoning you have to realize that the process of emergency medicine affords little or no dignity to trauma patients: life comes before limb; modesty comes well down the list.

So, what the fire lieutenant objected to was that I was cutting the clothes off a sixteen year old girl in the middle of the highway, directly illuminated by the halogen scene lights from our bus. He demanded that we package and transport the patient fully clothed. If you haven’t worked with firefighters, know this: they travel in packs. My partner was hanging IV bags and working the radio for another bus, so it was me, a supine patient, and five firefighters. They got what they wanted.

Of course, to protect trauma patients’ spines you have to package them fairly thoroughly. You basically strap them down to a six foot board so they can’t move, and once you finish it’s pretty much impossible to get their clothes off or do a half decent physical exam without jeopardizing their spinal cords. Which means, as the attending medic, when we got to the ED I was the one who had to explain to the trauma surgeon and ED physician why I was handing over a patient who could have had a piece of windshield glass the size of a grapefruit sticking into her kidney for all I knew. Not a shining career moment.

I remember that call not because the patient was badly hurt (just some broken bones; she was lucky), or because I made a huge difference in someone’s life, but because of the lieu’s argument for not doing the full, expected, physical exam. As his minions packaged my patient like gift-wrappers at Macy’s, and my partner made a break for the driver’s seat, he told me these exact words:

“She’s suffered enough trauma. She’ll be okay.”

Now, I knew at the time he was quite likely right (her chances having escaped major injuries were actually better than you might imagine), and it’s actually quite difficult to explain to patients why you have to cut their clothes off (try it some time), poke them, shock them, or tie them down. It’s very, very tempting to do the easy thing in these cases, and 99 out of 100 times if you avoid making the patient, or yourself, uncomfortable they do fine. But, one out of 100 times the patient dies from a ruptured spleen or flash pulmonary edema. That’s the worst case scenario; and that’s the only scenario medics really care about.

Now (finally on to my point, dear reader), I recently submitted a patch to Rails that I, and many of my colleagues, believe will help prevent invalid functional tests, and therefore prevent bugs. The response from the Rails core team:

The vast bulk of tests just pass the id in those places and they’ll work fine. Users overloading to_param are in the minority and we shouldn’t spam everyone else just to satisfy them.

Ignoring for a moment the somewhat unscientific characterization of the prevalence of #to_param overriding, the message is that the patch is potentially annoying for people with improperly written tests and most of those improperly written tests probably won’t be a problem. It’s more comfortable for the Rails team to let broken tests slide and hope all will be well, than to bother developers over the cases in which broken tests lead to broken production.

I realize that comparing HTTP 500 responses to ruptured spleens might seem overly draconian. But, consider this: while the consequences of doing the wrong thing in software are much less dire compared to medicine, it’s so much easier to do the right thing. If you doubt this, drop me a line; I’ll be happy to nasally intubate you. I guarantee after that experience spending half an hour fixing your controller tests won’t seem so bad.

  • 0 Shares
  • Share on Facebook
  • Share on Twitter
Adam Milligan

More on Wapcaplet

Adam Milligan
Sunday, August 2, 2009

Yesterday I wrote about Wapcaplet, which is really little more than a Rails patch that didn’t get accepted, but that some of us think Rails actually quite needs. To that end I submitted a second patch, which does the same thing but, by default, outputs a warning rather than raising an exception. I also included some methods for modifying the behavior on ActionController::TestCase. Specifically, if you want to ensure your tests aren’t broken:

ActionController::TestCase.treat_parameter_type_warnings_as_errors

Or if you, like Pierre, don’t care:

ActionController::TestCase.ignore_parameter_type_warnings

I don’t know if these changes will make the behavior of the patch palatable enough for the core team to commit it. We’ll see. After creating the ticket I considered pulling the new behavior back into Wapcaplet; I’ve decided not to for a few reasons:

  • First and foremost, no one pays attention to warnings. I can’t count the times I’ve preached myself blue about eliminating compiler/interpreter warnings, to little or no effect. I recently broke the builds for several projects by deleting a method that had been deprecated for a year and half, and which generated a fairly annoying deprecation warning on every build for every project that used it (keep in mind that at Pivotal projects will build many times a day).

  • Any patch applied to Rails will affect every Rails project that upgrades. I believe people should fix their broken tests, but I accept that this change will break a lot of tests. I can accept warnings as a way to show people what may be broken without bringing the world down on their heads. Wapcaplet, on the other hand, is entirely opt-in; no need to handle users with kid gloves.

  • I believe that a test failure is the right behavior. We’re talking about broken tests, they should act that way.

Remember, the lion ate Pierre.

  • 0 Shares
  • Share on Facebook
  • Share on Twitter
Adam Milligan

Wapcaplet

Adam Milligan
Saturday, August 1, 2009

Imagine for a moment that you run a big, important company. It’s important to you that your big, important company be successful at promoting, manufacturing, and distributing your big, important product, so you have decreed that the company must show a profit each and every quarter. In fact, your internal accounting software enforces this. For example:

describe "QuarterlyReportsController#create" do
  it "should reject quarterly reports that show a net loss" do
    post :create, :quarterly_report => { :net => -100 }
    response.response_code.should == 400
  end
end

Ignoring the somewhat misguided domain requirements, this test is wrong because it probably won’t fail when it should. It’s an example of a problem in Rails controller testing that bites everyone sooner or later.

The problem is that HTTP requests don’t send their parameters as integers, or booleans, or Date objects. No, HTTP request parameters are just big piles of strings. Rails does a good job of hiding the process of converting these strings into the integers and booleans and Date objects that make sense in your domain, but ActiveRecord handles that little bit of sleight of hand (using the column types from your database schema), not ActionController.

So, when you execute that test up above, the value of params[:quarterly_report][:net] will be the integer value -100, which is a value that the controller will never receive from a real HTTP request. This test fails to test a real case.

Now, if you try to use this value as an integer, either in the controller or by overriding #net= in the model, the test will still pass. But, as soon as you send a real request to the controller (hopefully not in production) you’ll find yourself on the business end of a 500 response. The test is broken.

In order to prevent this sort of brokenness I wrote a small patch to Rails (available here), which was summarily, and I will admit not unexpectedly, rejected. After that, I turned the patch into a tiny plugin called Wapcaplet (available here). It simply checks the parameters you pass to functional tests, and throws a friendly exception if you pass something with an inappropriate type. It accepts strings and instances of TestUploadFile in all cases. For parameter that Rails uses for routing it will also accept subclasses of ActiveRecord::Base.

Some examples:

# POST users/
post :create, :user => { :likes_ice_cream => true } # BOOM
post :create, :user => { :likes_ice_cream => "1" } # OK

post :create, :user => { :best_friend => @other_user } #BOOM
post :create, :user => { :best_friend_id => @other_user.id } # BOOM
post :create, :user => { :best_friend_id => @other_user.id.to_s } #OK

# GET users/:id
get :show, :id => @user.id # BOOM
get :show, :id => @user.to_param # OK
get :show, :id => @user # OK

# PUT users/:user_id/profile
put :update,
  :user_id => @user,
  :profile => { :photo => File.open("some/file" } # BOOM
put :update,
  :user_id => @user,
  :profile => { :photo => fixture_file_upload("some/file", "image/jpg" } #OK

Incidentally, notice that this will catch the pathological case, which seems to afflict every Rails developer, in which you pass #id rather than #to_param for a routing parameter.

In anticipation of the misguided comments that I know will come, no, it would not be better to have the plugin (or patch) call #to_s or #to_param on every incoming parameter to functional tests. Consider the example of boolean values:

true.to_s # => "true"
false.to_s # => "false"
true.to_param # => true
false.to_param # => false

Neither #to_s nor #to_param return a value likely to appear in a real HTTP request. It doesn’t take much imagination to come up with other examples of types that would not convert to meaningful request values. Worse, it takes only a little more imagination to come up with a scenario in which the implicit string conversion in the test would create subtlely wrong behavior that would be an enormous pain to track down.

So, take Wapcaplet out for a spin, I hope it saves you some time. Special thanks to Parker for getting bit by this problem enough times to get angry and demand I fix it.

  • 0 Shares
  • Share on Facebook
  • Share on Twitter
Jacob Maine

Standup 7/28/2009: Rails 2.3.3 Woes

Jacob Maine
Tuesday, July 28, 2009

Interesting Things

  • A few people have had problems with a change to named scope in Rails 2.3.3. The gist of the change is that if you chain named scopes, one of which uses a lambda that executes queries with the same model class, those queries are evaluated with the scope built up by the chain, not the default scope of the model. with_exclusive_scope may get around this, but could lose the default scope (or break things like acts_as_paranoid).

  • Rails 2.3.3 + Passenger fails with certain system configurations. Rails 2.3.3 does not bundle Rack, although 2.3.2 did. This may also be the cause of Mongrel failures someone noticed with script/server.

  • 0 Shares
  • Share on Facebook
  • Share on Twitter
Adam Milligan

Refactoring a dead horse

Adam Milligan
Sunday, May 10, 2009

A while back I made the point that the HasOneThroughAssociation class in Rails shouldn’t be a subclass of HasManyThroughAssociation. I also submitted a Rails patch in which I changed the superclass of HasOneThroughAssociation from HasManyThroughAssociation to HasOneAssociation and moved the shared Through functionality into a module. Despite support from the teeming millions, Rails core team member Pratik rejected the patch for being “just a refactoring.”

Despondent, I brought the issue up here at Pivotal a few months later, after the Release of Rails 2.3. Nate added a callout for support for the ticket to the daily Pivotal standup blog. The response was heartwarming (thanks to all who added a +1), but resulted only in Pratik removing himself from the ticket (I assume so he would stop getting comment notifications).

All is not lost, however. At RailsConf last week, Jeff Dean — Pivot, raconteur, international playboy, and refactoring paladin — called out the Rails core team regarding their stance on refactorings. The response: bullish (sort of).

Taking into account the responses from the Rails core team, I’ve done the following:

  • Recreated the patch for current Rails edge. Fortunately, I had to make only one small change to the patch from six months ago.
  • Ran a search on GitHub for any code using the HasOneThroughAssociation class (thanks to Jeff for the idea). As far as I can tell no code outside of Rails depends on the implementation of that class.
  • Added Jeremy Kemper as the owner of the Rails ticket. He was the most immediately supportive of refactoring patches, so hopefully he’ll advocate for this one.

We’ll see what happens.

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

Follow-ups from my RailsConf talk

Davis W. Frank
Wednesday, May 6, 2009

First, thanks to everyone who came – especially those who laughed at all the right spots. If I didn’t get to your question, I’m here through Thursday afternoon.

There were a couple of questions during the talk and lots after the talk about how to deal with remote pairs. Since it’s RailsConf and most folks are on MacOS, ScreenSharing.app came up.

Chad Woolley, King Remote Pivot, wrote up a great detailed discussion of his setup back in December. It should have answers to your tool & equipment questions.

The key element is the Full Screen mode in ScreenSharing.app. In Full Screen mode the remote Mac just becomes a terminal on the host machine – which means keystrokes like CMD-TAB, CMD-Space and a few others go over the wire instead of to your local box.

But Apple killed this feature as of 10.5.5 – but you can get it back! Follow the instructions at this post at MacWorld – use the second, more complex method – to hack on your ScreenSharing.app bundle to restore the awesomeness.

Once you’ve got the new app, replace the current ScreenSharing.app so you are always awesome:

sudo mv /System/Library/CoreServices/Screen Sharing.app/ /System/Library/CoreServices/Lame Screen Sharing.app/

sudo cp Awesome Screen Sharing.app/ /System/Library/CoreServices/Screen Sharing.app/

Then, run these two commands from Terminal:

defaults write com.apple.ScreenSharing ShowBonjourBrowser_Debug 1

'NSToolbar Configuration ControlToolbar' -dict-add 'TB Item Identifiers'  '(Scale,Control,Share,Curtain,Capture,FullScreen,GetClipboard,SendClipboard,Quality)'

We keep a copy of this app around which we renamed to AwesomeScreenSharing.app, so we don’t lose the feature on subsequent Software Updates.

One last thing: Quicksilver doesn’t index into the /System directory by default, but you can change that as well:

  • Go to QuickSilver preferences
  • Go to Catalog (top right)
  • Go to Custom (bottom left)
  • Hit the plus (system bar) to add a new location
  • Pick File & Folder scanner
  • Navigate to /System/Library/CoreServices

Now you can launch ScreenSharing via QS. Enjoy!

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

More on my RailsConf talk

Davis W. Frank
Thursday, March 26, 2009

As I’ve mentioned before, I’ll be giving a talk at RailsConf on how I “got more agile” once I was able to practice every day. The goal is for my story to help you in your career, telling some good stories in the process.

To celebrate/entice you to come to RailsConf & my talk, (Tuesday, 2:50pm, Ballroom A) and to thank those of you who contributed your own tips, I have two things for you.

First is a promise of Pivotal Labs swag (content TBD) to anyone who submitted a tip & to the first five comment authors who claim it below and identify themselves at the actual session – no sneaking off to Scott’s Advanced Git talk.

Second, for everyone, is a RailsConf discount of 15% in case you haven’t registered yet. When you register, use the promo code RC09FOS. Note that as of yesterday, the Hilton’s room rate has dropped to $99 a night. w00t!

  • 0 Shares
  • Share on Facebook
  • Share on Twitter

Topics

  • agile (780)
  • rails (113)
  • testing (88)
  • ruby (83)
  • ruby on rails (70)
  • jobs (62)
  • javascript (55)
  • techtalk (44)
  • rspec (38)
  • ironblogger (32)
  • productivity (30)
  • activerecord (29)
  • gogaruco (29)
  • git (28)
  • nyc (27)
  • rubymine (26)
  • bloggerdome (23)
  • mobile (22)
  • process (21)
  • pivotal tracker (20)
  • cucumber (20)
  • 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)
  • css (13)
  • tdd (13)
  • selenium (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. ...
  4. 5
  5. 6
  6. 7
  7. 8
  8. 9
  9. 10
  10. 11
  11. 12
  12. →
  • 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 >