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
  • Tools
  • Contact
    • Press Room
    • Press Releases
    • In The News
    • Press Kit
  • All
  • Labs
  • Standup
  • Tracker

Rails Associations With Multiple Foreign Keys

Joseph Palermo
Friday, May 31, 2013

Recently we had a situation where we inherited a schema and two of the models were joined using multiple foreign keys. The Rails associations API doesn’t appear to offer any good solutions to this problem. You can specify a single foreign_key and a single primary_key, but nothing really for multiple keys. One solution would be to use the Proc syntax for the :conditions option to specify the second column.

has_many :others, 
  :foreign_key => :fk_1,
  :primary_key => :first_primary_column,
  :conditions => Proc.new {
    {:fk_2 => other_primary_column}
  }

Here the proc is called on our instance of the primary model, so we can just reference the other_primary_column and the value of the current instance will be used in the conditions.

This will work for single models, but will not work if you are trying to eager load the association with an `includes` statement. For eager loading, what we really want to do is join the association table which is how eager loading was done prior to Rails 2.1.

Rails will fall back to joining an included association, but only if it detects that you are trying to reference it in your conditions for the primary model that you are finding. Since we are referencing it in the conditions of the association instead, we’ll have to tell it to join ourselves whenever we do the eager load.

Model.joins(:others).includes(:others)

Now we need to specifying the join conditions for the association, we can do this right in the conditions:

has_many :others, 
  :foreign_key => :fk_1,
  :primary_key => :first_primary_column,
  :conditions => 'others.fk_2 = other_primary_column'

The problem here is that the association now ONLY works if you join and eager load it. If you have a single instance where the association was not eager loaded, the association won’t work.

We can combine the two solutions by relying on the fact that when you do an eager load, the conditions proc gets passed the JoinAssociation. We don’t really need the JoinAssociation, but we can use it to switch between the two cases.

has_many :others, 
  :foreign_key => :fk_1, 
  :primary_key => :first_primary_column,
  :conditions => Proc.new { |join_association|
    if join_association
      'others.fk_2 = other_primary_column'
    else
      {:fk_2 => other_primary_column}
    end
  }

Now our association will behave correctly if we load it from a single instance, or if we try to eager load it with an `includes` statement (as long as we remember to also `joins` the association too).

Keep in mind that eager loading by doing a join was changed from the default in Rails 2.1 for a good reason. If you include a few associations and one or more of them is a has_many, you end up returning a lot of extra data that is not used. Doing a single query per table is more efficient in general, but with multiple foreign keys you have to do a join to eager load them.

  • 0 Shares
  • Share on Facebook
  • Share on Twitter

Why Pivots don’t do their best work at night

Joseph Palermo
Sunday, January 20, 2013

There is an interesting article by Swizec Teller over at Business Insider talking about why programmers do their best work late at night.

This is not the case at Pivotal.  Generally when we have clients committing code late at night, the team ends up having to refactor it and get tests around it the next day.  Often leading to a net loss of productivity even if the amount of time invested was greater.  So why then do so many developers seem to agree with the article?

The article has two general theories, and unfortunately I think they are correct for most developers.  However, rather than having developers commit all their code at night, Pivotal has better solutions to problems the article talks about.

The first theory is that developers need to hold the whole code base in their head, and any interruptions will force them to start over.  So late at night is the only time developers are able to get work done without interruptions.

At Pivotal, we have large open spaces that would generally provide enough distraction to keep any work from being done if this theory were always true.  So how do we get anything done then?  We avoid the problem altogether.  We don’t keep the whole code base in our heads, we simply don’t have to.  Since all of our code is test driven, you are focused only on making a single test pass at a time.  You don’t have to worry about the whole system.  Once your test passes, you can run all of the tests, and they will tell you if you’ve broken any other part of the system.  Test driving code also tends to make code that is more loosely coupled, meaning it is easier to change one part of the system without changing the others.  So we don’t have to worry about the other parts all at once, we can do them one piece at a time.

The second theory, is really just the first one but from the developers perspective.  He says that once it is late enough, you are so tired that nothing can distract you from writing code.  Essentially, once nobody else is distracting a developer, they have a tendency to distract themselves by checking email, web, IM, etc.  And once it is late enough, these distractions either go away, or you are too tired to devote attention to them any longer.

I certainly agree with the problem stated here.  If left to my own devices, I will often find a dozen other things to occupy my time, rather than writing code, even if I find the code interesting.  This is, in my opinion, one of the biggest advantages of pair programming.  Your pair is simply not interested in your email.  Because of this, a pair of developers is able to stay on task all day long.  The productivity boost from this is tremendous.  I simply had no idea how productive I could be until I started pair programming.  There are many other benefits to pairing: training of the weaker developer, knowledge transfer, shared ownership of code, better code design.  If I could only pick one benefit though, keeping everybody on task would probably be it.

Unfortunately, it is also one of the hardest selling points of pairing programming.  The decision of pairing or not, is usually not made by the developers.  Most managers are going to see the situation of two people working on the same problem as a waste of time.  Splitting them up should double the productivity right?  Unfortunately it’s really hard to say, “We don’t actually work as hard when we are working by ourselves.”  It’s not a proud fact, and you don’t really feel that it should by the foundation of your “why we should pair” argument.  So try to sell them on the other benefits first…

Since Pivotal developers are so productive during the work day, couldn’t we be extra productive by going home and working late into the night?  Maybe, but probably not.  Working late tends to throw schedules off.  It’s hard to get to work at 9 if you go to bed at 4.  Everybody starting at the same time means everybody pairs.  It’s one of the few drawbacks of working at Pivotal, your work schedule is not flexible if you are pairing.

Working at Pivotal can also be very tiring.  We only work 40 hours a week, but because we are pairing full time, you can get exhausted by the end of the day.  You especially see this in new Pivots.  Their first couple of weeks are pretty intense.  After that people seem to fall into the rhythm of things.

The original article wasn’t trying to solve a problem, it was only explaining why developers tend to do their best work at night.  So if you are developer, I’d recommend using the solutions Pivotal uses rather than working until 4am.  If you manage developers who do this, your job is more difficult.  Developers are not easy to change.  The reason it works at Pivotal is we only hire people who are capable of working this way.  Some people are simply not good socially, and will not be a good pair.  So it will be a struggle, and may require new people, but in the end, your development will be better off.

  • 0 Shares
  • Share on Facebook
  • Share on Twitter

[Standup][SF] 08/28/12: They at least strongly dislike each other

Joseph Palermo
Tuesday, August 28, 2012

Helps

  • Recommendations for static site generators for Heroku?

It looks like there’s a lot of them – does anyone have any personal recommendations?

Interestings

  • Draper and CI Reporter hate each other

This goes back to the Help a couple of weeks ago re: JSON being undefined. We blame Draper & its RSpec integration, but don’t yet have a solution.

  • eager_load and rake tasks

Eager loading doesn’t happen from rake tasks. This causes a problem if you are running in thread safe mode and dependency loading is disabled.

This has been fixed in master.

But until that is released, you can possibly branch your thread safe declaration on the existence of the $rails_rake_task global.

Events

  • eXtreme Tuesday

Come and talk about programming, and other aspects of XP. 6:30pm

  • 0 Shares
  • Share on Facebook
  • Share on Twitter

06/26/12: Headless is fine, double headless is trouble

Joseph Palermo
Tuesday, June 26, 2012

Interestings

  • Don’t Lose Your Head (twice)

Using rake ci:headless[...] AND having an around filter in your spec_helper to run your capybara JS specs headlessly is not a winning combo. Pick one.

  • 0 Shares
  • Share on Facebook
  • Share on Twitter

06/25/12: capybara-webkit on Centos?

Joseph Palermo
Monday, June 25, 2012

Helps

  • capybara-webkit and Centos

Capybara webkit works with one app using lobot with a trivial spec. With another app, it fails with a Errno::EPIPE: Broken pipe every time. It seems this error message means “something went wrong” which isn’t particularly helpful. We’re wondering if anyone else is using capybara webkit on centos with success?

Some talk of font differences and CSS selectors was mentioned.

Interestings

  • filepicker.io

The guys from filepicker dropped by the SFDevOps hack day on Sunday, and it looks like it could be an interesting way to handle file uploads. They have various integrations, and your user can chose to “upload” a file from dropbox/box/facbook and gives you back a url for your app to grab it from. Haven’t tried it, but it seems like it could be a quick win.

Events

  • eXtreme Tuesday Club

We meet each Tuesday to discuss TDD, XP and architecture over pizza and Tuesday lunch’s leftovers.

See the meetup.com page for more information.

  • 0 Shares
  • Share on Facebook
  • Share on Twitter

Standup 01/13/2012: Will the real 13th please stand up

Joseph Palermo
Friday, January 13, 2012

Ask for Help

“When using the wkhtmltopdf library via the PDFKit gem, if you use an HTML snippet that does not have a height defined, it generates a PDF that appears to only be an image, the text is not searchable or selectable. If you give your element a height however, it behaves as you would expect. Both PDF documents visually look the same though.”

  • 0 Shares
  • Share on Facebook
  • Share on Twitter

Standup 01/13/2012: I certainly don’t have a branch named "-"

Joseph Palermo
Friday, January 13, 2012

Ask for Help

“Trying to write a custom Rails I18n exception handler to catch MissingTranslationData exceptions”

The API didn’t seem to do what it claimed it should.

“RubyMine EAP undo behavior seems broken, it only wants to undo a file deletion, and then go back no farther in history.”

It was suggested that RubyMine undo is context sensitive, and having focus on the file browser has a different undo stack from the editor window.

“mysql2 gem on Lion is giving us an error: “Library not loaded… Image not found” and then a path pointing down into our RVM directory.”

Building the gem with options pointing to your mysql directory was suggested.

Interesting Things

“git checkout -” will toggle you between your last two checkouts (branches or just plain SHA’s). Handy if you are switching back and forth. Can’t seem to find it mentioned anywhere in the docs though.

  • 0 Shares
  • Share on Facebook
  • Share on Twitter

SF Standup 06/16/2011: Instantiate Paperclip model?

Joseph Palermo
Thursday, June 16, 2011

Ask for Help

“I have paperclip columns from a custom sql query. Is there any way to instantiate the associated objects just to generate the paperclip urls for those attachments?”

Calling new on the base class and passing in the data does not seem to work.

Interesting Things

The script tab of the webkit inspector has breakpoints for all kinds of events. Is a click event not behaving like you think it should? You can easily check a box and have all click events open the debugger.

  • 0 Shares
  • Share on Facebook
  • Share on Twitter

SF Standup 06/14/2011: Case Sensitive File System

Joseph Palermo
Tuesday, June 14, 2011

Ask for Help

“Why do NULL values get inserted as strings when using mysql LOAD DATA INFILE after dumping the data with mysql -e”

Unfortunately this team only has control over the import, not the existing export. Their only option found was to replace occurrences of NULL with N after getting the import file.

Interesting Things

A team again reminds us to be aware that the default file system in OSX is case insensitive. They thought this was the reason git would not commit a lowercase file rename for them. However, this setting was later found for your .git/config file.

[core]
ignorecase = false
  • 0 Shares
  • Share on Facebook
  • Share on Twitter

Standup 11/23/2010: Cucumber eating sessions

Joseph Palermo
Tuesday, November 23, 2010

Ask for Help

“Why is Cucumber clearing our sessions between requests?”

A team is doing Cucumber/WebRat tests of a SAML authentication flow using Devise. No matter what they do, their session seem to be getting cleared between requests. It was suggested to write a vanilla Rails integration test to see if the problem is in Cucumber or the App.

“Any recommendations for a CMS to use with Rails?”

The textarea backed by a single model just isn’t cutting it anymore and we probably don’t want to end up building our own. Any success or horror stories?

  • 0 Shares
  • Share on Facebook
  • Share on Twitter
Joseph Palermo

Joseph Palermo
San Francisco

Subscribe to Joseph's Feed

Author Topics

activerecord (1)
associations (1)
ruby on rails (3)
agile (18)
named_scope (1)
bug (1)
performance (1)
  • About
  • Case Studies
  • Team
  • Community
  • Careers
  • Tools
  • 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 >