Modularized Association Methods in Rails 3.2

— January 20, 2012 at 11:03 PST


Happy Friday! It's Rails 3.2 day! The official release announcement mentions a few of the big changes, but I'd like to take a moment to highlight a relatively small change I was responsible for, one that I hope may make your life a little easier.

From the ActiveRecord CHANGELOG:

Generated association methods are created within a separate module to allow overriding and
composition using `super`. For a class named `MyModel`, the module is named
`MyModel::GeneratedFeatureMethods`. It is included into the model class immediately after
the `generated_attributes_methods` module defined in ActiveModel, so association methods
override attribute methods of the same name. *Josh Susser*

The point of this change is to allow more flexibility in working with associations in your model classes. When you define an association, ActiveRecord automagically generates some methods for you to work with the association. For example, a has_many :patches association generates the methods patches and patches= (and a few others).

Previously, those association methods were inserted directly into your model class. This change moves those methods into their own module which is then included in your model class. Your model gets the same methods through inheritance, but also gets to override those methods and still call them using super. Let's take a look at two ways this makes things easier for you.

Sometimes you want to replace the standard generated association methods. That's always been easy to do simply by defining new methods in your model class. The only wrinkle was that you had to make sure you defined your method after you set up the association, or calling has_many would overwrite your method, since last writer wins. That was usually not a problem, but sometimes plugins or other monkey patching extensions could add an association after your model's class was defined, which wouldn't give you a chance to add your method afterwards. With this change, you don't have to worry about those order dependencies anymore. Since those methods are generated in their own module, the order doesn't matter. This is a pretty small issue all told and I doubt it affected many people, but it's still worth mentioning.

The real reason for this change is being able to compose your own methods with the standard generated methods. Before this change, you'd have to use alias_method_chain or some other fancy footwork to layer your own logic on top of the standard association functionality. Either that or you'd have to somehow duplicate the standard behavior in your own method. Ick. Now you can compose methods using inheritance and super, the way Alan Kay intended you to. Here's the example from the docs:

class Car < ActiveRecord::Base
  belongs_to :owner
  belongs_to :old_owner

  def owner=(new_owner)
    self.old_owner = self.owner
    super
  end
end

If you're familiar with ActiveRecord it's probably fairly obvious what's going on there, but I'll spell it out for the new kids. When you define the belongs_to :owner association, that generates a standard owner= method, and puts it in the module named Car::GeneratedFeatureMethods, which is the closest ancestor of class Car. If you're curious what this looks like, fire up the rails console and type Car.ancestors to see the class's inheritance chain. (Or use your own app and model, since that will be much easier than making up a new app just to see that one thing.)

In this Car class, you can see that changing owners keeps track of the old owner, so the new owner knows who to call when he can't figure out how to open the trunk. The generated owner= method does a fair amount of stuff including managing counter caches, running callbacks, setting inverse associations, etc. Skipping that could break a number of things, so after saving the old owner, you also want to run the generated method. Since it's in a module that Car inherits from, you only have to call super to get that to run. No muss, no fuss!

One more step towards simpler OOP in Rails! Thanks to my fellow Ruby Rogues Avdi Grimm and James Edward Gray II for complaining about the old state of things enough to motivate me to finally go fix this.

7 commentsactiverecord, associations, rails

Yak Shaving

— January 4, 2012 at 08:23 PST


As coders, most of us are not only familiar with the term yak shaving, but spend many of our days doing nothing but. I often struggle to explain to non-technical folks what I actually spend my time doing when I'm working and what it feels like. This is the most accessible explanation I can come up with.

Say you want to go see a movie with your friend Joe. You can't get away with leaving the house when the kitchen is such a mess, so you have to load and run the dishwasher before you go. Unfortunately you're out of detergent, which means you have to run to the store to pick some up. You want to ride your bike or it will take too long to get to the store. But your bike's front tire is kind of low, so you have to pump it up first. However, your roommate borrowed your tire pump and you don't know where it is, so you have to go find your roommate and ask him about it. He's over at a neighbor's place having band practice, but it's just a short walk. When you get there they are in the middle of practice so you have to wait for a few minutes. The only place to sit is on that ratty old sofa, right next to the drummer's sister, Monica, who will only let you sit there on the condition you smoke a joint with her. But before you can do that you have to dig around in the seat cushions to find the lighter she just realized she lost. You manage to find the lighter, and before too long you are smoking out with Monica. The band finishes the number and your roommate comes over to see what's up. You take another hit off the joint and say "Hey, we should order a pizza."

9 commentsjargon, programming

I heard you liked files

— December 1, 2011 at 21:35 PST


I was going to try and be clever and do a funny riff on this whole subject, but I just can't manage it. Here's the thing. Makefile was a dumb name for a file when Stuart Feldman wrote the make utility in 1977, but you have to forgive him because file systems were quite limited back then and filenames could only be a few characters long. The pattern was <filename.ext> - 8 chars for the name, 3 for the extension. I guess config.make wouldn't fit, config.mak looked weird, so Makefile it was.

Now we have no excuse. At all.

I respect and adore Jim Weirich, but I hope he feels at least a little shame for inflicting "Rakefile" on us all. That name choice seems to have set the stage for a proliferation of copycats. Now we have an ever-growing assortment of files that helpfully tell us they are files right there in the file name. Because something siting in a directory in the file system might be something else, like maybe a turnip or a bad hair day. Capfile, Gemfile, Assetfile, Vagrantfile, Guardfile...

You may ask: What's the problem? Why should anyone care about a cute little naming convention that continues a tradition going back over 30 years?

It may not be a huge deal, but there are a couple issues with this. All of these file formats are actually a variation on a well-accepted language: Ruby. But with a name that omits the standard .rb extension, language-aware tools have no chance to help us out. Syntax highlighting? Nope. Will awk search those files for you? No way. Will RubyMine figure out the structure of the code in those files? Forget it. OK, you can add those files to all your tools' configurations, then you're good to go. Until someone creates a new Crapfile and you have to go through and update all those configurations again.

Just because your configuration file's contents are written in a DSL does not mean you should pretend it's not Ruby anymore.

I urge every maintainer of a project that uses a name like Crapfile for the configuration file to move toward using a name that is compatible with language-aware tools. If you can't think of a name yourself, allow me to suggest this:

filename.sub(/file$/, '_config.rb').downcase

UPDATE: It has been pointed out to me that RubyMine actually does a pretty good job of dealing with these file names. Not perfect, but pretty good. Anyway, I don't want to come off as bashing RubyMine (I'm spending more time with it now and it's starting to grow on me), so substitute vim or emacs or TextMate or your most-hated editor instead.

19 commentsruby

Refactoring: be eager, not reckless

— October 19, 2011 at 09:54 PDT


The illustrious Chris Eppstein recently tweeted:

If some code should be refactored, stop what you are doing and refactor it.

I was about to respond, but realized I had more to say than would fit in a tweet. (Waiting for someone to fix that problem!) (Then I got distracted and didn't finish this article for a few days, oops.)

Now, Chris is really smart and probably doesn't mean exactly what he said, but it's easy to misinterpret his advice. I'll agree with him that you should be eager to refactor code when you discover the need. Don't let that technical debt accrue interest longer than necessary! However, you shouldn't be reckless about it.

Please keep this in mind:

Don't do a refactoring in the middle of making another change.

If you are working on a story and in the middle of making a code change when you discover the need to refactor something, make a note of it (I usually create a chore in Pivotal Tracker) and forget about it until you're done with the change in progress. After you complete the change, come back and do the refactoring. Make sure all tests are green before starting to refactor, and are green when done. The refactoring change should be a separate commit in git (separate checkin in SVN, etc).

OK, I'm pragmatic and realize that that approach doesn't work all the time, but it's a good ideal to shoot for. I considered discussing cases where it would be OK to refactor something in the middle of another change, but on second thought I think I'll leave that be for now. You'll learn that for yourself better than by following someone else's advice on the subject.

7 commentsagile, refactoring

Fifteen Protips for Conference Speakers

— July 18, 2011 at 13:26 PDT


Do you dream of someday speaking at a technical conference? Have you spoken at a conference but felt like your journey to the podium wasn't as smooth as it might have been? Well here are a couple tips to make things go smoothly and endear you to your conference organizers.

I'm writing this from the perspective of a conference organizer where my main focus is the technical program. I've run into a lot of these issues when putting together Golden Gate Ruby Conference, and also seen things from the other side when speaking at other conferences.

A lot of this list is about not being a problem for the conference organizers. I hope that doesn't come off as too negative, but I figure most speakers don't realize the potential impact of seemingly little things. Making things easier for the organizers makes for a better conference for everyone, and your presentation will be even more awesome.

Continue reading...

5 commentsconference, presentation

Archives

January 2012 Modularized Association Methods in Rails 3.2 Yak Shaving December 2011 I heard you liked files October 2011 Refactoring: be eager, not reckless July 2011 Fifteen Protips for Conference Speakers just a thought June 2011 Slightly more readable Ruby GoGaRuCo 2011 CFP Limitless Strings for PostgreSQL July 2010 GoGaRuCo 2010 December 2009 No returns November 2009 RubyConf 2009 Lightning Talks RubyConf Schedule September 2009 Pair programming isn't right for all projects Circle of death July 2009 Discipline and creativity June 2009 It's a wrap! April 2009 Not the post The Week Of February 2009 The tyranny of choice: It's our turn now January 2009 Announcing Golden Gate Ruby Conference December 2008 Agile git and the story branch pattern Saying Goodbye to New York, Speaking at nyc.rb September 2008 Hello, New York August 2008 Sorting things out June 2008 Extra geeky: the recursive lambda An extra special case me me me! The Great Test Framework Dance-off May 2008 Quick RailsConf Update See you at RailsConf A simple alternative to namespaced models April 2008 Symbols are not pretty strings GitHubba-hubba simple pages March 2008 Migration Concordance February 2008 count vs length vs size January 2008 Segregated page cache storage Feed readers are lame and URLs are forever Speaking at RailsConf 2008 One Hundred, Two Hosts, Three Engines December 2007 Book Review: The Rails Way November 2007 step, step, pivot, step October 2007 Self-referential has_many :through associations RubyConf and QCon Book Review: Pro Active Record MicroPlace: invest wisely, end poverty Simpler than dirt: RESTful Dynamic CSS Everything old is new again September 2007 it's easy being redgreen August 2007 Show flash messages on cached pages July 2007 New on edge: inferred foreign key name change Validate your existence Check out your routes June 2007 new differences in assert_difference May 2007 Laying Tracks slides Getting arbitrary with assert_difference April 2007 April SF Ruby Meetup notes Who are these guys? Speaking at SDForum SVRC March 2007 New on Edge: dynamic finders with hash attributes for creation Using your connections February 2007 Pragmatic Rails Studio in Sunnyvale Happy Blogday Powerset de-cloaking (and hiring too) January 2007 Blog status RFP: Silicon Valley Ruby Conf 2007 Using faux accessors to initialize values Basic Rails association cardinality Don't make a new one on my account December 2006 Stop using the rails command Meet the new blog November 2006 Rails 1.2 RC1 and test cases October 2006 Merb is the new black gang aft agley Life at Powerset September 2006 Twisting the rope: looking for code examples Finding unassociated objects August 2006 Validate all your records in one fell swoop New on edge: Magic join model creation How dynamic finders work Site upgrade The Caboose Rails Documentation Project New job! July 2006 Speaking at RubyConf 2006 more on naming and the CRUD Patch test plugin: dynamic finders with belongs_to names validates_numericality_of :resource_name June 2006 CRUDdy searches Working with the relationship model RailsConf Recovery RailsConf update Twixt RailsDay and RailsConf the geoff and josh show 2:30am wired on redbull Critical mass When associations aren't enough, part 2 When associations aren't enough Work hunt update, Rails Day, Meetups, and Stuff Will work for money May 2006 Come on, Eileen! Getting rid of the middle man A gentle reminder about pluralizations Laying Tracks SF Ruby Meetup tonight has_many :through gets :uniq Presenting: ME April 2006 Ruby Conference in Silicon Valley Want some gum? Self-referential has_many :through associations Many-to-many Dance-off! Ruby sweetness Why aren't join models proxy collections? Missing out on Canada on Rails Ruby Meetup My first Ruby on Rails patch Getting Real redux Conferences and user groups The other side of polymorphic :through associations Stability Rich associations: OUT, join models: IN SQL on Rails Getting Real in Chicago March 2006 hosts upgrade to 1.1 - DOOM! The other ways :through maintenance Dirt simple .rcss templates Rails 1.1 Release Candidate Silicon Valley Ruby Conf DabbleDB DRYing up parameter checks Symbol to Proc shorthand Here I go New association goodness in Rails 1.1, part 2 DreamHost: getting to stats pages February 2006 New association goodness in Rails 1.1 TextMate - my new blogging tool test modified rake task my_blog = Blog.new(:kind => "geek")


You are viewing a mobilized version of this site...
View original page here

Mobilized by Mowser Mowser