The Artima Developer Community
Sponsored Link

Ruby Buzz Forum
Named Scope: It's Not Just for Conditions, Ya Know?

0 replies on 1 page.

Welcome Guest
  Sign In

Go back to the topic listing  Back to Topic List Click to reply to this topic  Reply to this Topic Click to search messages in this forum  Search Forum Click for a threaded view of the topic  Threaded View   
Previous Topic   Next Topic
Flat View: This topic has 0 replies on 1 page
rwdaigle

Posts: 312
Nickname: rwdaigle
Registered: Feb, 2003

Ryan is a passionate ruby developer with a strong Java background.
Named Scope: It's Not Just for Conditions, Ya Know? Posted: Aug 20, 2008 8:49 AM
Reply to this message Reply

This post originated from an RSS feed registered with Ruby Buzz by rwdaigle.
Original Post: Named Scope: It's Not Just for Conditions, Ya Know?
Feed Title: Ryan's Scraps
Feed URL: http://feeds.feedburner.com/RyansScraps
Feed Description: Ryan Daigle's various technically inclined rants along w/ the "What's new in Edge Rails" series.
Latest Ruby Buzz Posts
Latest Ruby Buzz Posts by rwdaigle
Latest Posts From Ryan's Scraps

Advertisement

Named scopes in Rails are great, everybody knows that. They’re usually used to create granular, chainable sets of SQL conditions that nicely encapsulate your domain query logic. Here’s a simple example:

1
2
3
4
5
6
7
8
9
10
11
12
class Article < ActiveRecord::Base
  
  # Get all articles that have been published
  named_scope :published, :conditions => ['published = ?', true]

  # Get all articles that were created recently
  named_scope :recent, lambda { { :conditions => ['created_at >= ?', 1.week.ago] } }

end

# Get all recently created articles that have been published
Article.published.recent #=> [<Article id: ...>, <..>]

However, as much as I use named_scope for this purpose, I also use it for some smaller and still useful functions. For instance, I find that I often need to just fetch the first X number of results for any particular query. Instead of having to call find with the :limit option you could create the following named_scope:

1
2
3
4
5
6
7
8
9
class Article < ActiveRecord::Base
  
  # Only get the first X results
  named_scope :limited, lambda { |num| { :limit => num } }

end

# Get the first 5 articles - instead of Article.find(:all, :limit => 5)
Article.limited(5) #=> [<Article id: ...>, <..>]

Hey, any less typing I’ll take, and I find myself using this limited named_scope a lot. But let’s pimp it a little so that you don’t always have to supply the number, and make it default to the per_page value that exists on the class if you’re using will_paginate.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Article < ActiveRecord::Base
  
  # Only get the first X results.  If no arg is given then try to
  # use the per_page value that will_paginate uses.  If that
  # doesn't exist then use 10
  named_scope :limited, lambda { |*num|
    { :limit => num.flatten.first || (defined?(per_page) ? per_page : 10) }
  }

  def per_page; 15; end

end

# Get the first 15 articles
Article.limited #=> [<Article id: ...>, <..>]

# Get the first 5 articles
Article.limited(5) #=> [<Article id: ...>, <..>]

Note that we have to use the variable length *num argument in the lambda to allow for no arguments.

Cool, so we’ve got a handy little tool for our toolbox now. Here’s another one I find myself using that isn’t strictly a conditional scope – ordered:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Article < ActiveRecord::Base
  
  # Order the results by the given argument, or 'created_at DESC'
  # if no arg is given
  named_scope :ordered, lambda { |*order|
    { :order => order.flatten.first || 'created_at DESC' }
  }

end

# Get all articles ordered by 'created_at DESC'
Article.ordered #=> [<Article id: ...>, <..>]

# Get all articles ordered by 'updated_at DESC'
Article.ordered('updated_at DESC') #=> [<Article id: ...>, <..>]

I’ve bundled these scopes up into a “utility scopes:http://github.com/yfactorial/utility_scopes” plugin/gem if you think they look useful to you. I’ve also added some class-level convenience initializers to let you override the default values (like the default limit and default order clause):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Article < ActiveRecord::Base

  # This class's default ordering (if not specified
  # defaults to 'created_at DESC'
  ordered_by 'published_at DESC'
  
  # By default, return 15 results (if not specified
  # defaults to 10
  default_limit 15

end

# Get the first 15 articles ordered by 'published_at DESC'
Article.ordered.limited #=> [<Article id: ...>, <..>]

# Get the first 15 articles ordered by 'popularity ASC'
Article.ordered('popularity ASC').limited #=> [<Article id: ...>, <..>]

# Get the first 20 articles ordered by 'popularity ASC'
Article.ordered('popularity ASC').limited(20) #=> [<Article id: ...>, <..>]

Need a little something else? How about the with scope which will eager load the specified associations:

1
2
3
4
5
6
7
class Article < ActiveRecord::Base
  has_many :comments
  has_many :contributors, :class_name => 'User'
end

# Get the first 10 articles along with their comments, comment authors and article contributors
Article.limit(10).with({ :comments => :author }, :contributors)

You can get all these goodies yourself by doing the following in your Rails 2.1 app. In config/environment.rb specify the gem dependency:

1
2
3
4
5
Rails::Initializer.run do |config|
  # ...
  config.gem "yfactorial-utility_scopes", :lib => 'utility_scopes', 
    :source => 'http://gems.github.com/'
end

And then to get the utility_scopes gem actually installed on your system:


rake gems:install GEM=yfactorial-utility_scopes

Or you can just install the gem as you normally would:


sudo gem install yfactorial-utility_scopes -s http://gems.github.com

Independent of whether or not you find these scopes useful, remember that named_scope is all up in your queries’ bidness – not just your queries’ conditions

Have some utility scopes you find to be indispensable? Let me know here or send me a request on github (user is yfactorial).

tags: ruby, rubyonrails

Read: Named Scope: It's Not Just for Conditions, Ya Know?

Topic: autotest reminder (or why did it go boom?) Previous Topic   Next Topic Topic: Computer Books which have made me who I am....

Sponsored Links



Google
  Web Artima.com   

Copyright © 1996-2019 Artima, Inc. All Rights Reserved. - Privacy Policy - Terms of Use