About

James Golick

James Golick's software experience ranges from artificial intelligence to web front-end and JavaScript development. Most recently, James has fallen back in love with web development thanks to Ruby on Rails.

Since discovering Rails, James has become a prolific contributor to its open source ecosystem. He is the author of several popular plug-ins and gems, and a contributor to countless others, including the framework itself.

James is an advocate for well-written, well-tested code and he blogs regularly about the practice of developing software. He speaks regularly at software development conferences and user groups. James is a partner in Nine Lives, Inc.

Latest Tweets

follow me on Twitter

James on the Web

Business Logic Bleeding in to Views and Controllers

Jul 16 2008

I've been doing a fair bit of training recently — both while bringing Mat up to speed on the latest and greatest best practices, and going and speaking to clients' teams. A few concepts keep coming up, so I'm going to try to blog about them as they do. Here's the first one.

I see this all over client projects, and admittedly, some of my older ones:

<%- if @post.creator == current_user -%>
  <%= link_to "Edit", edit_post_path(@post) %>
<%- end -%>

Seems innocuous — the post can only be be edited by its creator. But, that is a business logic rule, so it belongs in your model (and your tests).

context "Posts" do
  setup do
    @creator      = create_user
    @post         = @creator.posts.create!(hash_for_post)
    @another_user = create_user
  end

  should "be editable by their creator" do
    assert @post.can_be_edited_by?(@user)
  end
  
  should "not be editable by another random user" do
    assert !@post.can_be_edited_by?(@another_user)
  end
end
class Post < ActiveRecord::Base
  def can_be_edited_by?(user)
    user == creator
  end
end

Why? A few reasons. First, because your model classes should represent a complete picture of your data's structure, and business logic rules. Second, a rule like that deserves testing, even if it's as simple as the one in this example. Finally, because later on, you might want admins to be able to edit posts, too.

context "Posts" do
  setup do
    @creator      = create_user
    @post         = @creator.posts.create!(hash_for_post)
    @another_user = create_user
    @admin        = create_user :admin => true
  end

  should "be editable by their creator" do
    assert @post.can_be_edited_by?(@user)
  end
  
  should "be editable by an admin" do
    assert @post.can_be_edited_by?(@admin)
  end
  
  should "not be editable by another random user" do
    assert !@post.can_be_edited_by?(@another_user)
  end
end
class Post < ActiveRecord::Base
  def can_be_edited_by?(user)
    user == creator || user.admin?
  end
end

If we're using the can_be_edited_by? method all over our controllers and views, a change to the access policy shouldn't entail anything other than editing a couple of lines of code in our models and unit tests.

Subtler

Here's another one I see all the time (especially in my code). This one tends to be harder to spot.

class MessagesController
  before_filter :login_required
  
  protected
    def project
      @project ||= current_user.projects.find(params[:project_id])
    end
  
    def messages
      project.messages.find(:all)
    end
end

The idea here is that we're using the association as an implicit access control mechanism. If the user row is associated with the project row, the user has access to that project. I know that there are several r_c users who have used this pattern, since it's so easy to implement with r_c. I've even recommended it. Ouch.

The problem with this pattern is lack of encapsulation. There are a good handful of situation in which you might want the access rule to change such that you'd have to go and change every call to current_user.projects. Which is ugly.

What if you decided to make ProjectMembership a join model, for example? Rather than actually deleting membership rows, you decide you'd like, for record keeping purposes, to have a revoked_at field which denotes a former membership made invalid. You might think — no problem, I can just change the conditions of the association.

class User
  has_many :projects, :through => :project_memberships, :conditions => "project_memberships.revoked_at IS NULL"
end

Aside from ambiguous naming, this remains an incomplete solution. At some point, you're going to decide that admins have access to all projects. You could add that condition to your SQL, too, but that approach is problematic for the same reason we're talking about, here: the definition of an admin may change. So, we need a different strategy.

class Project
  has_many :project_memberships
  has_many :users, :through => :project_memberships
  
  named_scope :with_active_membership_for, lambda { |user| { :include => :project_memberships, :conditions => ['project_memberships.user_id = ? AND project_memberships.revoked_at IS NULL', user.id] } }
  
  def self.for(user)
    user.admin? ? self : self.with_active_membership_for(user)
  end
end

This isn't a perfect solution, since the definition of a revoked membership is living in the SQL; ideally that would be defined in ProjectMembership. But, with a join model, I'm not sure of any other way. So, at least in this instance, we can use the Project.for method in our controllers, and views, and not have to worry about a change in the project access rules causing a need for major refactoring later on.

class MessagesController
  before_filter :login_required
  
  protected
    def project
      @project ||= Project.for(current_user).find(params[:project_id])
    end
  
    def messages
      project.messages.find(:all)
    end
end

But, Not Always

One could look at these examples and decide to engage in reductio ad absurdum. Why not encapsulate the messages collection, they'd ask?

The rule I tend to stick to is that if I know that there's any kind of access control policy being enforced on an object or collection, it gets encapsulated, and tested in the model.

In the fictional examples above, the assumption was that provided access to the project, a user would be allowed to access all of messages within. In that case, I wouldn't have encapsulated, because there would have been no rule to encapsulate.

As soon as there is a policy, though, it belongs in tested methods in your models.

The controller's responsibility in all of this is to control access to a resource in the sense that it actually performs the check, and redirects the user to a login screen, or shows an access denied message if they are not entitled to perform said action on said resource. The controller is not, however, responsible for deciding who it is that gets access; that's the model's job.

Like a bouncer at the door of a nightclub, your controller shouldn't make the rules, it should only enforce them. Luckily for you, cute 17 year old girls won't have the same effect on your controller that they might on a bouncer.


An Introduction to Association Proxy

Feb 10 2008

@post.comments << Comment.new(:title => 'something')
Comment.find(:all,  :conditions => ['post_id = ? AND title like ?', @post.id, 'something'])
Comment.count(:all, :conditions => ['post_id = ?', @post.id])

There is an easier way to do all of that. So, if you're still manipulating ActiveRecord associations by hand, stop; there is a better way.

AssociationProxy

When you request a collection of associated models, ActiveRecord extends that array with several helpful methods. You can treat that array like a model class, except all of the methods are automatically scoped to the association's parent. It responds to methods like find, create, new, count, etc, and, it's called AssociationProxy.

So, what if we wanted to create a comment, scoped to our post model?

@post.comments.create(params[:comment])

Making use of AssociationProxy, the code reads better, and requires fewer keystrokes. We can also use AssociationProxy to find elements in our collection.

@post.comments.find(:all, :conditions => {:title => 'title we are looking for'})

We can even use dynamic, attribute-based finders through AssociationProxy.

@post.comments.find_by_title 'title we are looking for'

It Gets Better

Since assoc proxy responds to many of the same methods as a model class, the two can be interchanged for many operations. In resource_controller, for example, nested controllers depend heavily on association proxies. Let me show you what I mean.

If we had, for example, a typical show action.

def show
  @comment = Comment.find(params[:id])
end

With very little effort, we can allow comments to be shown nested, or unnested.

def show
  @comment = model.find(params[:id])
end

private
  def model
    params[:post_id] ? Post.find(params[:post_id]).comments : Comment
  end

Since we know that AssociationProxy responds to other model class methods, we can base our create method on this technique, too.

def show
  @comment = model.find(params[:id])
end

def create
  @comment = model.new(params[:comment])
  if @comment.save
    redirect_to @comment
  else
    render :action => 'new'
  end
end

private
  def model
    params[:post_id] ? Post.find(params[:post_id]).comments : Comment
  end

In fact, this is nearly exactly how resource_controller is built.

So, association proxy is useful in simple and complex situations alike. It can save you a lot of code, and increase readability. It's a win-win really.


An Introduction to Ruby's Enumerable Module

Jan 05 2008

If you're still writing for loops, stop; there's a better way. Exactly why merits some examples.

[1, 2, 3].each { |number| puts number }

That's a pretty straightforward one. It says: with each element in this array, execute the given block. But, what if we wanted to do something more complicated, like determine whether there were any even numbers in the array?

[1, 2, 3].any? { |number| number % 2 == 0 } # => true
[1, 3, 5].any? { |number| number % 2 == 0 } # => false

The any? method says: are there any elements in the array for which this block evaluates to true? We might also want to know whether all? of the elements were even.

[2, 4, 6].all? { |number| number % 2 == 0 } # => true
[1, 2, 3].all? { |number| number % 2 == 0 } # => false

We can see that making good use of Enumerable methods produces highly readable code. Before we move on, there are a couple more methods that are worth demonstrating.

We've already seen how we can easily look inside of an array, using any?, and all?. Conveniently, Enumerable provides similar methods for extracting objects. What if we wanted, for example, to retrieve all of the even numbers.

[1, 2, 3, 4].select { |number| number % 2 == 0 } # => [2, 4]

...or, the first even number...

[1, 2, 3, 4].detect { |number| number % 2 == 0 } # => 2

Let's pick up the pace.

Putting the Pieces Together

If I was writing some blogging software, I might want to display recent activity in the administration area. With a big array of notification objects, I can use select to easily divide them up for display, based on recency.

today     = @notifications.select { |notification| notification.created_at > 1.day.ago.to_date }
yesterday = @notifications.select { |notification| notification.created_at < 1.day.ago.to_date && notification.created_at > 2.days.ago.to_date }
earlier   = @notifications.select { |notification| notification.created_at < 2.days.ago.to_date }

I'm actually doing something very similar to this in an app I'm working on. Since I love fat models, I created some helper methods on AR::Base. They look (something) like this:

class ActiveRecord::Base
  def today?
    created_at > 1.day.ago.to_date
  end
  
  def yesterday?
    created_at < 1.day.ago.to_date && created_at > 2.days.ago.to_date
  end
  
  def earlier?
    created_at < 2.days.ago.to_date
  end
end

So, now, we can greatly simplify our use of the select method, making it far clearer what we're up to.

today     = @notifications.select(&:today?)
yesterday = @notifications.select(&:yesterday?)
earlier   = @notifications.select(&:earlier?)

...wait, what? The ampersand operator, as described by the PickAxe book:

If the last argument to a method is preceded by an ampersand, Ruby assumes that it is a Proc object. It removes it from the parameter list, converts the Proc object into a block, and associates it with the method

But, a symbol isn't a Proc object. Luckily, ruby calls to_proc on the object to the right of the ampersand, in order to try and convert it to one. Symbol#to_proc is defined in ActiveSupport; it creates a block that calls the method named by the symbol on the object passed to it. So, for the above examples, the blocks send today?, yesterday?, or earlier?, respectively, to the each object that is yielded. Written out by hand, the expanded blocks would look like this:

today     = @notifications.select { |notification| notification.today?  }
yesterday = @notifications.select { |notification| notification.yesterday? }
earlier   = @notifications.select { |notification| notification.earlier? }

For additional to_proc coolness, it's worth mentioning Reg Braithwaite's String#to_proc (or get the code). I won't go on any further about that today, though.

Let's look at one last example — this time from real software. In order to add support for polymorphic, deep nesting in resource_controller, I had to write an algorithm that would determine which of the possible sets of parent resources were present at the invocation of a controller action. This is done by testing to see which of the params (parent_type_id) are present. So, if I say belongs_to [:project, :message], [:project, :ticket] in my comments controller, I need to determine: for which of those two possible sets are both necessary params present? Since belongs_to is just a simple accessor, the algorithm is easy to write.

belongs_to.detect { |set| set.all? { |parent_type| params["#{parent_type}_id".to_sym].nil? } }

Recap

Enumerable's biggest advantage over the for loop, as we've seen, is clarity. Using Enumerable's looping power tools, like any?, all?, and friends makes your code read semantically. Especially combined with Symbol#to_proc, code "...seems to describe what I want done instead of how I want the computer to do it.", to quote Raganwald.

Finally, in order to take your Enumerable usage to the next level, there are a few more methods you should have in your toolbox.

I'd also recommend keeping the Enumerable, and Array documentation bookmarked, so that you can quickly refer to them. As a bonus, most of these methods exist in prototype.js, too; just take a look at the documentation.


Promiscuity for Fun and Profit

Aug 30 2007

Sometimes, we advanced rails users take our knowledge of the framework for granted, have unfair expectations for less advanced rails coders. The worst examples of such unreasonable demands can be found on a daily basis in the IRC channel (#rubyonrails on Freenode, for the uninitiated). And, while the IRC channel can certainly be harsh, even those of us who don't throw around the term "noob" like it's going out of style sometimes (often) complain more than we help. As one of my peers likes to remind me, I'm present in that category more often than I'd like to admit (if I didn't have to). As an aside: While Gary is often the one I'm ranting to, his code is never the subject of the rant. I'd really like to turn my negative energy in to something positive. This will be the first of many articles that seek to add to the pool of resources on rails best practices, shortcuts, tips, and tricks. I hope you like it.

Today's Topic: Polymorphic Associations

It was a check-in today that sparked the round of complaining that sparked the round of Gary telling me to shut up that sparked the desire to write this article. The check-in added a bunch of tables to a project, with a schema that looked (something) like this:
create_table :cities do |t|
  t.column :name, :string
  ...
end

create_table :city_aliases do |t|
  t.column :city_id, :integer
  t.column :alias, :string
end

create_table :provinces do |t|
  t.column :name, :string
  ...
end

create_table :province_aliases do |t|
  t.column :province_id, :integer
  t.column :alias, :string
end
Well, it's definitely not the worst schema ever, but it can be improved drastically with a polymorphic association. What the heck is that, you ask?

Promiscuous Models

Essentially, a polymorphic association is a model that can belong_to any other table. Polymorphic associations are the way that a lot of popular plugins work. Ever wonder how acts_as_taggable just magically adds tagging to any model, without any migration? Well, it's super easy. Just replace your duplicate tables with one of these babies:
create_table :name_aliases do |t|
  t.column :aliasable_type, :string
  t.column :aliasable_id, :integer
  t.column :name, :string
end
You'll need a model, too:
class NameAlias < ActiveRecord::Base
  belongs_to :aliasable, :polymorphic => true
end
Note: I chose the name NameAlias because alias is a reserved word in ruby, and it may cause you some problems if you try to name a model that.

Going back to our example, we can redefine our models as follows:
class City < ActiveRecord::Base
  has_many :name_aliases, :as => :aliasable
end

class Province < ActiveRecord::Base
  has_many :name_aliases, :as => :aliasable
end

Now What?

A polymorphic association works just like any normal association. That means you can use all of your favorite AssociationProxy methods, and everything.
City.find_by_name("montreal").name_aliases.create :name => "mtl"
...will work just as it always has.

How'd you do that?

When you tell rails that :polymorphic => true, in your belongs_to options, it knows that it needs to store the id and the type of the associated class. You give the association a generic name like aliasable or taggable, to let rails know what the fields are named in the database. For example, if you call your association aliasable, you need to have the fields aliasable_type and aliasable_id. Make sure aliasable_type is a long enough string column to store the name of your longest model in it. In production, both of these fields should probably be indexed. When you associate a class with your polymorphic model, you have to tell it to associate as your generic association name, instead of its own, to let rails know how to join the tables up properly: :as => :aliasable.

Name Aliases that Rock

Because this example is a particularly useful one, it's worth showing you a method that I write often. It will work with any association, but I often use it with aliases. It adds an extra finder, which allows you to find_by_name_alias.
class Person
  has_many :name_aliases, :as => :aliasable
    
  def self.find_by_name_alias(name)
      Person.find(:all, :include => :name_aliases, :conditions => ["name_aliases.name = ?", name])
  end
end

Feedback, please!

So, there you have it: polymorphic associations. This is where you come in. I have some questions:
  • How'd you like it?
  • What could be improved?
  • Should I use a different format (like a screencast)?
  • Are there any topics you'd like to see?
Thanks for reading.