#108
May 19, 2008

named_scope

The named_scope method in Rails 2.1 makes performing finds on models very elegant and convenient. See how in this episode.
Download (12.5 MB, 11:02)
alternative download for iPod & Apple TV (12.1 MB, 11:02)

Note: there’s a lot more to the named_scope method which I didn’t cover, please see the links below for additional info.

# models/product.rb
class Product < ActiveRecord::Base
  belongs_to :category
  named_scope :cheap, :conditions => { :price => 0..5 }
  named_scope :recent, lambda { |*args| {:conditions => ["released_at > ?", (args.first || 2.weeks.ago)]} }
  named_scope :visible, :include => :category, :conditions => { 'categories.hidden' => false }
end

RSS Feed for Episode Comments 118 comments

1. Adam Hill May 19, 2008 at 02:55

Wow, and I thought working with the DB couldn't get any easier, but this is seriously cool. Thanks for this excellent overview.

I wonder if these named scopes can be used in conjunction within existing search plugins like acts_as_ferret in one line...


2. Foo May 19, 2008 at 04:11

Another great screencast.

Does this essentially make all self.finds obsolete? Will the new conventions be named_scope instead of def self.find_some_criteria?


3. grigio May 19, 2008 at 04:21

Thanks for these Rails 2.1 tips.


4. hoksitan May 19, 2008 at 04:50

Very interesting screencast ! Cool new feature ! Thanks for this tip !


5. Mauricio May 19, 2008 at 06:12

What about the performance cost of this "magic"?


6. Marcel May 19, 2008 at 06:19

Wow, this looks really cool. I especially like the efficiency of the generated SQL query when you concatenated the named_scopes. Really amazing and definately a great feature for bigger, data-filled applications.

Thanks for another great screencast!


7. Clemens Kofler May 19, 2008 at 06:41

Foo:
I would guess that yes, pretty much all finds will be replaced by named scopes in near future. Think of your own experience and some of Ryan's previous screencasts: You shouldn't really have finds anyway as soon as you're using find conditions. Like, say, you'd have find_all_activated instead of find(:all, :conditions => "activated_at IS NOT NULL")

Mauricio:
As far as I can see in the source, there's not too much going on metaprogramming-wise. So I guess it's safe to say that scoping doesn't cause performance issues. And as Marcel points out, named scopes produce really clean and efficient SQL - so no problem there either. Plus, scopes have existed before in Rails (with_scope - see here: http://api.rubyonrails.org/classes/ActiveRecord/Base.html#M001416).

Ryan:
Best episode so far, in my opinion. And not only because it was so long! ;-)


8. Ryan Bates May 19, 2008 at 08:01

@Adam, I doubt you can use this with acts_as_ferret, but other plugins which end up calling "find" should work. For example, will_paginate just adds a custom paginate class method. You can append this to the search. (Untested).

Product.recent.paginate(:page => 1)

@Foo, this definitely lowers the need to create custom "self.find..." methods. However I would hesitate getting too fancy here. If you have a complicated search which needs to dynamically build up the conditions based on the passed parameters, then I wouldn't use named_scope for this.

@Mauricio, to echo Clemens, I doubt performance will be much of an issue. There's probably a slight overhead on the ruby side to get the scoping stuff figured out, but beyond that it seems efficient.


9. Radarek May 19, 2008 at 12:15

@Ryan:
  in Ruby 1.9 you can use -> operator for lambda and put default values, like this:

named_scope :recent, ->(time = 2.weeks.ago) { {:conditions => ["released_at > ?", time]} }


10. Matt Beedle May 19, 2008 at 12:54

I've been using has_finder for a while now, and it's been a real pleasure to work with. I'm really glad it's made it into rails.


11. Jeremy May 19, 2008 at 14:07

I have been using edge rails as of late just for this amazing functionality. In addition to the new level of dynamism this feature adds to Rails, it also adds such simplicity.

My favorite has to be simply the Model.all, Model.first, and Model.last shortcuts... cleans up my controllers for sure!

Man, with each new update of Rails, so many new possibilities for refactoring!


12. Carl May 19, 2008 at 15:18

I have been trying to do some of the same things using with_scope and some of them were not working correctly (I have an idea why now after watching your screencast) and now it will be so much easier to do what I was trying to do. Thanks for telling me about this new feature!


13. Soleone May 19, 2008 at 22:58

Indeed a very cool screencast.

Thanks again for this great episode!


14. Mathijs May 19, 2008 at 23:34

I've been using the has_finder gem on which this is based for some time now, and it's really useful. One thing I still struggle with has to do with using named_scopes between models in associations.

In your example you are using 'visible' which is just a simple attribute. What if category had more advanced attributes, like hidden, private, public, read_only and stuff like that. Say Category already has some named_scopes, for example 'free_for_all' which means a category is public but not read-only.

Now it would make sense (maybe not in this example but in general) to be able to use these named_scopes in the Product model, not on instances only, but in named_scopes themselves as well. So Product.in_free_for_all can just use the 'free_for_all' scope in Category. Otherwise you would have to define this 'logic' twice, which isn't very DRY. I hope my explanation is clear enough :)

Of course I know that I could also use Category.free_for_all.map(&:products), but then all products get fetched right away which means sorting them (and other nice stuff finders have) will have to be done in ruby instead of in the DB.

Any 'nice' solutions for this?


15. Mathijs May 19, 2008 at 23:46

A solution I use at the moment is this, but I'm not fully satisfied with it yet, so any comments are very welcome...

class Product << ActiveRecord::Base
  belongs_to :category
  named_scope :in_free_for_all, lambda {{ :conditions => {:category_id => Category.free_for_all.map(&:id)} }}
end

Which will do 2 queries, which is default for :include in rails 2.1 anyway I believe. I could use :select => 'id' to speed up the query a bit since I only need id's, but in the end, it would be nicest if rails could somehow write a subquery for it. Along the lines of:

(example, doesn't work)

named_scope :in_free_for_all, :conditions => {:category => Category.free_for_all}

should translate to:
Select * from products where category_id in (select id from categories where public = 't' and read_only = 'f')

Any chance of getting behavior like this in the near future?


16. Ryan Bates May 20, 2008 at 07:55

@Mathijs, currently one named scope can't use another named scope, but I think many people are wanting this feature. There's already a couple tickets along this line:

http://rails.lighthouseapp.com/projects/8994/tickets/57
http://rails.lighthouseapp.com/projects/8994/tickets/223

However, neither of these mention using an association's scope. You may want to add a comment to those tickets about that.


17. Brad May 20, 2008 at 09:25

Thanks for a great post! My attention tends to drift after about 7 minutes, so i'll have to come back and watch again a couple times :)


18. ESPNDev May 20, 2008 at 16:26

This was a really great Railscast highlighting probably my favorite new feature of Rails. Those SQL queries are great! Can't wait to take advantage of this...

Thanks!


19. Bryan May 21, 2008 at 04:08

Wow! Truly awesome new feature!
Now I just need to get Hostgator to update to 2.1....


20. Bharat May 26, 2008 at 14:37

Hello Ryan (or anyone else who knows),
Great screencast. In your demo, you are typing the commands in the console and showing the SQL queries in the console below. How do you isolate the SQL Queries display in the window below? It is quite useful. A screencast summarizing the tips on using Rails Console for these kinds of tricks would be very useful.
Keep up the good work.
Regards,
Bharat


21. Olafski Jun 04, 2008 at 06:16

@Bharat: you could just keep a window with ``tail -f log/development.log'' open, that should show the queries. I prefer to have them in the same window though, and have explained how to achieve this here:
http://skionrails.wordpress.com/2008/05/22/loading-additional-files-when-starting-scriptconsole/

Hope that helps. Great work as always Ryan :)


22. Walter Horstman Jun 13, 2008 at 03:34

On my website there is a page to view standings for a so called soccer pool. There are member records with a name per pool, that can be left empty. Each member is linked to a user record with a name field as well. In case the name of the member is empty, the user's name is used in the standings.

When using named_scope, I see strange behavior, since the eager loading isn't quite as I expected. I guess things have been changed in Rails 2.1 in this area that have not necessarily have to do with named_scope.

Anyway, in my Member class this scope doesn't work:

named_scope :standings, :include => :user, :order => 'members.position, COALESCE(members.name, users.name)'

The query doesn't join with the users table, so a missing column error is returned. But when I add :conditions => 'users.id = users.id', it works! So is Rails looking in the conditions to see if a associated table is used?

Anybody see my points and have some clues/comments?


23. tom Jun 13, 2008 at 10:16

Hi
im getting this:
named_scope > NoMethodError

ruby-v
ruby 1.8.5 (2006-08-25) [i486-linux]

rails-v
Rails 2.1.0

gem1.8 list
*** LOCAL GEMS ***

actionmailer (2.1.0, 2.0.2)
actionpack (2.1.0, 2.0.2)
activerecord (2.1.0, 2.0.2)
activeresource (2.1.0, 2.0.2)
activesupport (2.1.0, 2.0.2)
jruby-openssl (0.2.3)
rails (2.1.0, 2.0.2)
rake (0.8.1)

my problem / question: as soon as i have a named_scope declaration within the class, im experiencing the error above ( NoMethodError)

what am i doing wrong/missing?

thx tom


24. tom Jun 13, 2008 at 10:46

never , i figures it out, its working now on the console.as a newbie i forgot to chnage envrinment.rb

thx


25. chris Jul 01, 2008 at 21:54

hi ryan, great job as usual. quick question for you... when you are working around the inability to pass in a default value for the lamdba, you splat args and then in the proc you use "args.first || 2.weeks.ago"...

my question is why? why not just leave the argument to the lambda as "t" and then in the proc use "t || 2.weeks.ago" ?

seems to work for me, but i'm wondering if you had some other rationale for using the splat/first method.


26. Nico Jul 09, 2008 at 22:02

You can also pass in a params hash into the named scope and use for example params[:newer_than] || 2.weeks.ago for the default parameter. I prefer this solution over using args when having more than one parameter as the named scope call becomes easier to understand and parameter order doesn't matter.


27. ryanL Jul 17, 2008 at 23:45

hey Ryan, still working on that image trouble. I'll let you know when i get it sorted out.

had a tricky scope question though.

Is it possible to order a find call my an associated model's attribute.

e.g.

@category.members.order_by_members_businesses_names do |member|

i would just do

@category.businesses.order_by_name do |business|

but i the member model has addtional info i need to access.

named_scope :order_by_members_businesses_names ...?


28. Matt Aug 01, 2008 at 10:33

So would this replace the need to use the scope out plugin?


29. Philip (flip) Kromer Aug 24, 2008 at 01:38

@chris ("why not just leave the argument to the lambda as "t" and then in the proc use "t || 2.weeks.ago" ?"):

It's so you can leave the arg out -- it fakes an optional parameter.

See:
  http://pastie.org/258863


30. Pete Sep 05, 2008 at 07:53

This is so easy, it's great! Thanks for the walkthrough.


31. Edgard Sep 25, 2008 at 10:26

Hi,

You didn't try the case where 2 named_scope have a block of code. In your screencast only :recent ha a block of code, but what about chaining it with :cheap that also had a block of code?

I can't make it work.


32. Zubin Oct 12, 2008 at 03:56

If anyone's interested, I've created a plugin which automagically generates common named scopes for all AR models and columns. See http://github.com/zubin/autoscope

>> Page
=> Page(id: integer, name: string, content: text, enabled: boolean, category_id: integer, created_at: datetime, updated_at: datetime)

...creates these (for example):
>> Page.enabled
>> Page.not_enabled
>> Page.named "foo"
>> Page.content_contains "bar"
>> Page.created_before 1.year.ago

Install:
./script/plugin install git://github.com/zubin/autoscope.git

Feedback welcome!


33. Achim Oct 12, 2008 at 16:00

Thank you very much for this screencast.
Your tip about working with optional arguments saved my live :-)

Really great screencast again Ryan


34. Steffen Dec 03, 2008 at 01:42

Thanks again for this great episode!
Just what I have been looking for!


35. Jason Dec 03, 2008 at 08:56

Hi Ryan,

Thanks so much for all your work. Question - I'm seeing that
scope = Product.scoped({})
is indeed doing a find which is undesired in my case. I'm on Rails 2.1. I'd like to build up the scopes before executing. Do I need to use your scope_builder?

Thanks!


36. Jason Dec 03, 2008 at 09:16

Per comment #44 by me:

I was in the console when testing this. Appears to be ok when running in Rails.

Sorry for any confusion. Still seems a bit weird though.


37. MTH Dec 31, 2008 at 00:19

In fact, I'm using your episodes instead of Rails API!

Thanks for sharing!


38. Arjun Mar 04, 2009 at 23:50

Hi,

I have been trying to get the named scopes to work in my model without any success.
I have model called Contact.

And my named scope is like the follow:-
class Contact < ActiveRecord::Base
named_scope :guardians, {:conditions =>["relationship = ?", 'Guardian']}

And in the IRB:-
>contact = Contact.find(2)
>contact.guardians

gives the following error:
NoMethodError: undefined method `gaudians' for #<Contact:0x636d4e4>
        from F:/Projects/WorkshopProjects/testproject/vendor/rails/activerecord/lib/active_record/attribute_method
s.rb:256:in `method_missing'
        from (irb):7

I am not sure what is going wrong.

I even tried using lambda as follows, but same thing happens:-
named_scope :test_guardians, lambda { { :conditions => ['relationship = ?', 'Guardian'] } }

Can you help me out here ?

Thanks in advance.

-Arjun


39. DM500C Mar 19, 2009 at 03:02

I have been trying to get the named scopes to work in my model without any success. How to do next?


40. ruby_seattle Apr 14, 2009 at 20:57

Ryan, or any other expert,

I'm such a fan of named scopes now and see so many opportunities to streamline code. I ran into a problem. How can I create a named scope that uses an association and a lambda expression for parameterization. For example how would you retrieve all the products that are from a certain category type, for example 'electronics'. When I try something analagous to this I get an error: wrong number of arguments (3 for2).

named_scope :retrieve_by_type, :include=>:category, lambda{|type_id| {:conditions=>['categories.type'=type_id]}

-Thanks in advance


41. tomas Jun 11, 2009 at 08:05

Hi,
i'm new, how can i see generated queries like you do in the bottom terminal ?


42. Mike Jun 19, 2009 at 10:15

Since this was not clearly stated in text form I thought I would include this little snippet from the documentation on named_scope:

-----------------------
Unlike Shirt.find(...), however, the object returned by Shirt.red is not an Array; it resembles the association object constructed by a has_many declaration. For instance, you can invoke Shirt.red.find(:first), Shirt.red.count, Shirt.red.find(:all, :conditions => {:size => ‘small’}). Also, just as with the association objects, named \scopes act like an Array, implementing Enumerable; Shirt.red.each(&block), Shirt.red.first, and Shirt.red.inject(memo, &block) all behave as if Shirt.red really was an Array.


44. Margaret Aug 16, 2009 at 20:10

I recently came across your blog and have been reading along. I thought I would leave my first comment. I don't know what to say except that I have enjoyed reading. Nice blog. I will keep visiting this blog very often.

Margaret

http://powerleveling.info


44. tuzcuoğlu nakliyat Aug 22, 2009 at 18:57

I am always been a great fan of your railscast. Keep up the good work.


45. ideal kilo Sep 05, 2009 at 13:33

Download it, very useful for me, thank you !


46. lm Sep 20, 2009 at 18:14

Could it be possible to have a named_scope that include columns from another association?

something like:
named_scope :my_fields,:select => "..."
or maybe another way?

Thanks


47. Jeem Oct 29, 2009 at 05:41

Nice...., very information. thanks for sharing…


48. Aşk Büyüsü Oct 29, 2009 at 08:05

thans


49. cinsellik sohbet Nov 06, 2009 at 14:24

If they are linking from the comment, I would consider it spam. If they post a comment, and it is on topic, be glad someone saw your blog and thought enough to post to it. http://www.hayda.net/


50. cinsel Nov 09, 2009 at 12:40

thanks admincik


51. Visit Kamyanets Nov 11, 2009 at 12:19

Hi! Thanks for sharing this information. :)


52. adapterlist Nov 14, 2009 at 00:08

http://www.adapterlist.com/dell/xps-m1330.htm dell xps m1330 battery
http://www.adapterlist.com/hp/510.htm hp 510 battery
http://www.adapterlist.com/hp/530.htm hp 530 battery
http://www.adapterlist.com/hp/dv2000.htm hp dv2000 battery
http://www.adapterlist.com/hp/dv6000.htm hp dv6000 battery
http://www.adapterlist.com/sony/vgp-bps2b.htm sony vgp bps2b battery
http://www.adapterlist.com/dell/e1705.htm dell e1705 laptop battery
http://www.adapterlist.com/dell/inspiron-9300.htm dell inspiron 9300 laptop battery
http://www.adapterlist.com/dell/inspiron-9400.htm dell inspiron 9400 laptop battery
http://www.adapterlist.com/sony/vgp-bps2c.htm sony vgp-bps2c battery
http://www.adapterlist.com/toshiba/pa3534u-1brs.htm toshiba pa3534u-1brs battery


53. çuval Nov 18, 2009 at 10:24

firmamız çuval ve çuval imalatı yapmaktadır


54. direk izle Nov 23, 2009 at 16:38

I recently came across your blog and have been reading along


55. oyunlar Nov 24, 2009 at 11:11

very nice thanks...


56. Jassy Nov 26, 2009 at 14:01

clear codes ... i use your class (:


57. Dans Kursları Nov 28, 2009 at 11:25

Thanks a nice theory


58. cosplay Dec 02, 2009 at 22:18

Students in class....


59. TIBIA AD Dec 03, 2009 at 19:58

<a href="http://www.gamezmoney.com/tibia-gold.htm">tibia gold</a>
<a href="http://www.guildwarsgoldmoney.com/wow-gold.htm">wow gold </a>,
<a href="http://www.gamezmoney.com/dofus-kamas.htm"> dofus kamas</a>,
<a href="http://www.10minget.com/eve.htm">tbia gold</a>
<a href="http://www.rs15min.com">Cheap rs gold and rs power leveling</a>

Get your tibia gold on our site with your lowest cost and our timely service.
We have been a an ebay seller and paypal seller of tibia gold for more than three years.
You can completely trust us and we are ready to provide our service anytime.
Never out of stock, never delay the goods. Come and get your tibia gold at your nearest convenience.

http://www.10minget.com/tibia-gold.htm
http://www.10minget.com/gw.htm
http://www.10minget.com/eve.htm
http://www.rs15min.com
http://www.rs15min.com/rsgp.htm
http://www.rs15min.com/rsyew.htm
http://www.rs15min.com/rs-power-leveling.htm
http://www.rs15min.com/rs-gold-uk-gbp.htm


60. kraloyun Dec 11, 2009 at 04:06

Thanks very good


62. Buy Viagra Dec 14, 2009 at 13:56

hello friend excellent post about named_scope thanks for sharing!!!


62. Evden eve Dec 15, 2009 at 10:16

Thanks for share


63. Nakliyeci Rehberi Dec 15, 2009 at 10:18

Thanks admin, good work


64. mod converter Dec 16, 2009 at 18:17

lalalala ....morning.


65. buy penegra Dec 18, 2009 at 06:22

hey nice blog about named_scope


66. konya chat Dec 18, 2009 at 14:23

thanks


67. forum Dec 20, 2009 at 08:40

thanks you adminbey


69. WTF Dec 20, 2009 at 15:20

thanx for that.


69. lig golleri Dec 20, 2009 at 15:20

amk nofollow ama idare edicez artık. tenks edmin.


70. yeni müzik Dec 20, 2009 at 15:24

thank you and admins


71. Sinema izle Dec 20, 2009 at 15:28

Thanks very good..


72. full oyun Dec 20, 2009 at 15:38

thankss perfect


75. araba resimleri Dec 20, 2009 at 18:27

thanx,caniiiim


75. resimler Dec 20, 2009 at 18:29

great post, ellerin dert görmesin


75. muhteşem kraliçe Dec 21, 2009 at 02:50

muhteşem kraliçe dizisi trt1


76. kurumsalseo.com R10 lida fx15 pohudey zayıflama Dec 21, 2009 at 03:05

Good post thanks for sharing.


77. Mustafa Can Dec 21, 2009 at 05:19

Thanks for a great post! My attention tends to drift after about 7 minutes, so i'll have to come back and watch again a couple times :)


78. tecavüz pornosu Dec 21, 2009 at 07:41

very good thanks


79. oyun indir Dec 21, 2009 at 08:49

Thanks for a great post! My attention tends to drift after about 7 minutes, so i'll have to come back and watch again a couple times :)


80. Orhan Dec 21, 2009 at 09:20

good performance, thanks


81. rimeysa Dec 21, 2009 at 09:22

thanks wery good.


82. ssk Dec 21, 2009 at 09:24

hello
good performance thanks


83. 0 km Dec 21, 2009 at 10:38

Nice post


84. Sigorta Dec 21, 2009 at 11:26

Thanks
http://www.sigortasorgulama.net


85. galatasaray Dec 21, 2009 at 12:52

thanks admins


86. su deposu Dec 23, 2009 at 02:09

thanks admin very good


87. besmele Dec 24, 2009 at 03:32

a great site. I too enjoy. I wish you success


88. Dans Kursu Dec 24, 2009 at 04:43

Very nice sharing thanks


89. karın germe Dec 25, 2009 at 13:35

karın germe ameliyatı


90. 招聘 Dec 26, 2009 at 00:19

thanks admins


92. sikiş Dec 30, 2009 at 03:03

I recently came across your blog and have been reading along. I thought I would leave my first comment. I don't know what to say except that I have enjoyed reading. Nice blog. I will keep visiting this blog very often.


93. order from this site Jan 10, 2010 at 15:05

ef ewfwefwefw


94. skelaxin without prescription Jan 10, 2010 at 15:09

dfd gse fef efef


95. arama rehberi Jan 12, 2010 at 01:36

Hi I found your site from google. I enjoy your site too. thanks


96. wholesale scarves Jan 13, 2010 at 22:49

Such a good article, caught my sympathy!
-


97. wholesale nike shoes Jan 13, 2010 at 22:49

A very good article, I will always come in.


98. wholesale nike shoes Jan 13, 2010 at 22:50

A very good article, I will always come in.


99. wholesale scarves Jan 13, 2010 at 22:50

Such a good article, caught my sympathy!
-


100. Çene Ameliyatı Jan 14, 2010 at 05:15

to friends here agree. They all say the right things likewise.


101. iyimi Jan 16, 2010 at 04:43

A very good article, I will always come in.


102. sarki sözleri Jan 16, 2010 at 04:45

thank you


103. orjin Jan 17, 2010 at 22:38

to friends here agree. They all say the right things likewise.


104. sikis izle Jan 20, 2010 at 18:14

Thanks for another great screencast!


105. amatorsikis Jan 20, 2010 at 18:15

Very nice sharing thanks


106. sicaksikis Jan 20, 2010 at 18:16

I've been using has_finder for a while now, and it's been a real pleasure to work with. I'm really glad it's made it into rails


107. lice Jan 22, 2010 at 02:29

Thank you for the post, really helped me a lot :)


108. {{!COL1)) Jan 23, 2010 at 19:04

{{!COL4))


109. {{!COL1)) Jan 23, 2010 at 19:52

{{!COL4))


110. augmentin no prescription Jan 23, 2010 at 20:42

love this info i will read this more often


111. javon Jan 25, 2010 at 22:37

Nice post.


112. Oyunu Oyna Jan 26, 2010 at 01:30

Nice post.


113. us drugstore Jan 28, 2010 at 22:55

Thanks for the review, but I think many people are wanting this feature.


114. Muhabbet Jan 30, 2010 at 17:27

Tnaks


115. forumturka Feb 02, 2010 at 08:40

thank you.. nice


116. diyugg Feb 02, 2010 at 22:37

hi,I am very happy to have landed here.


117. cheap wow gold Feb 04, 2010 at 18:10

hi,I am very happy to have landed here.


118. GHD hair straightener Feb 07, 2010 at 23:29

thank you for give me the chance to read the post .The <a href="http://www.topghdmart.com">GHD</a> beauty products are sure to keep you satisfied for many more years to come


119. Chi Hair Straightener on sale Feb 07, 2010 at 23:29

ok,i agree with it .<a href="http://www.chiflatiron4u.com">CHI hair straightener</a> will make you more style,you want be the center around the people ,right ?

Add your comment:

(SKIP THIS ONE)

(required)

(not shown)


(use pastie or gist for code)

sponsored by:
if you want to help:
required:
Get Quicktime Player
Give Back to Open Source