25 Oct, 2007

Published at 04:28AM

Tagged with plugin, programming, and rails

This post has 3 comments

Scoping out a model

That didn’t come out right. What I meant to say was there is a great new Rails plugin called scope_out that assists with AR class methods, and you should try it out.

First of all, you shouldn’t have something like Whatever.find(:all, :conditions => 'something IS NOT NULL') in your controllers. That find should be put into the model ( Whatever.find_something instead). Well, scope_out makes that process a little nicer.

I’ll use Golf Trac as an example. So, in Golf Trac, there are 9 hole and 18 hole courses all over the place. At some point, I may want to show a list of each, independent of the other. Here’s what I might do normally:

1
2
3
4
5
6
7
8
9
class Course < ActiveRecord::Base
  def self.find_nine
    find(:all, :conditions => ['is_eighteen = ?', false])
  end

  def self.find_eighteen
    find(:all, :conditions => ['is_eighteen = ?', true])
  end
end

I definitely can’t complain about that, but there’s an even nicer way. Let’s look at how scope_out can help…

1
2
3
4
class Course < ActiveRecord::Base
  scope_out :nine,     :conditions => { :is_eighteen => false }
  scope_out :eighteen, :conditions => { :is_eighteen => true  }
end

That’s pretty cool. That allows Course.find_nine and Course.find_eighteen just like the regular class method implementation. It creates methods with find_ appended to whatever you’re “scoping out.” Another nice thing about it is you can still pass in additional options to the finder.

1
2
Course.find_nine(:first)
Course.find_eighteen(:all, :order => 'created_at DESC')

It also allows the ability to use it in a “with_scope” fashion. For instance…

1
2
3
4
Course.with_eighteen do
  @recent = Course.find(:order => 'created_at DESC', :limit => 5)
end
# => five most recent eighteen hole courses

Dynamic finders also come as a bonus with this plugin. So find_all_by_whatever now has a cousin or two, find_all_nine_by_whatever and find_all_eighteen_by_whatever.

That’s great and all, but the more typical case would be what nine hole and eighteen hole courses a user has. Well, since scope_out works with associations, too, it’s not a problem:

1
2
3
4
5
current_user.courses.find_nine
# => all nine hole courses this user has added

current_user.courses.find_eighteen
# => all eighteen hole courses this user has added

There are a few other cool things this plugin supports. If you can look beyond the fact that this doesn’t make any sense, you can see how combining two scopes is done:

1
2
3
4
5
class Course < ActiveRecord::Base
  scope_out :nine,     :conditions => [ 'is_eighteen = ?', false ]
  scope_out :eighteen, :conditions => [ 'is_eighteen = ?', true  ]  
  combined_scope :both, [:nine, :eighteen]
end

Again, that’s dumb. Course.both is the same as Course.find_all since it’s a boolean condition, but you get the idea. To install with_scope:

script/plugin install http://scope-out-rails.googlecode.com/svn/trunk/

That will put a “trunk” folder in your plugins directory, which you should rename. Enjoy.

Comments

Chris Thursday, 25 Oct, 2007 Posted at 05:25AM

I like it ;-) I’m sort of on a quest to get my controllers on a diet – I can’t stand to look at some of them, they’re so obese.

Now I have one for you to aid your journey to REST: resources_controller. I just tried it out and I love how much code it removes from the controller.

Dave O. Thursday, 25 Oct, 2007 Posted at 05:43AM

Hey, I resemble that remark Chris ;p

Ryan, very cool article. Thanks.

Ryan Thursday, 25 Oct, 2007 Posted at 06:45AM

Whoa, that looks sweet. It should definitely help in the conversion.

I haven’t converted to REST just yet, but the other evening (when you mentioned the noun rule) I went through everything (controllers, models, helpers, views) and restructured it all. It feels much cleaner now.

It’s amazing how much you can improve over just a couple of months. I should start doing a mandatory re-factor every 3 months—I bet I’d be surprised at the “old” code every time.

Do you have something to say about this post?
Retype the image to the right Spam Hint: Are You Human? Textile Formatting Tips

or

Ryan Heath | Site Management A Ruby on Rails production.

This site is a Formed Function. Formed Function LLC | @formedfunction | Get in Touch