Flowdock
method

named_scope

Importance_5
Ruby on Rails latest stable (v4.1.8) - 16 notes - Class: ActiveRecord::NamedScope::ClassMethods

Method deprecated or moved

This method is deprecated or moved on the latest stable version. The last existing version (v3.0.9) is shown here.

named_scope(*args, &block) public

No documentation

This method has no description. You can help the Ruby on Rails community by adding new notes.

Show source
Register or log in to add new notes.
July 24, 2008 - (v2.1.0)
20 thanks

automatically generate scopes for model states

or better known as “throw on some more tasty meta-programming” :). Given an example of a model which has a state (String) which must from a set of defined values, e.g. pending, approved, denied.

class User < ActiveRecord::Base
  STATES = [ 'pending', 'approved', 'denied' ]

  validates_inclusion_of :state, :in => STATES

  # Define a named scope for each state in STATES
  STATES.each { |s| named_scope s, :conditions => { :state => s } }
end

This automatically defines a named_scope for each of the model states without having to define a named_scope manually for each state (nice and DRY).

June 27, 2008
15 thanks

Passing find() arguments

I you need to pass additional arguments to a scope (e.g. limit), do this:

Shirt.colored('red').all(:limit => 10)
March 10, 2009 - (>= v2.1.0)
8 thanks

Use lambda to avoid caching of generated query

If you’re using a named_scope that includes a changing variable you need to wrap it in a lambda to avoid the query being cached and thus becoming unaffected by future changes to the variable, example:

named_scope :translated, :conditions => { :locale => I18n.locale }

Will always return the same locale after the first hit even though I18n.locale might change. So do this instead:

named_scope :translated, lambda { { :conditions => { :locale => I18n.locale } } }

Ugly, but at least it’s working as we expect it…

December 12, 2008
7 thanks

acts_as_state_machine named scopes

If you are using the acts_as_state_machine plugin, this will generate all named scopes for your various states.

Place it after the acts_as_state_machine and state declarations.

class Task < ActiveRecord::Base
  acts_as_state_machine :initial => :waiting
  state :waiting
  state :running
  state :finished    

  states.each { |s| named_scope s, :conditions => { :state => s.to_s } }
end

Then doing a Task.waiting will return the corresponding tasks.

March 21, 2009
4 thanks

Passing optional arguments with defaults to a named_scope

An easy way to do this. (This also shows how you can use joins in a named_scope as well.)

Class User << ActiveRecord::Base
belongs_to :semester 

named_scope :year, lambda { |*year|
  if year.empty? || year.first.nil?
    { :joins => :semester, :conditions => ["year = #{CURRENT_SEMESTER}"]}
  else
    { :joins => :semester, :conditions => ["year = #{year}"]}
  end
  }

end

You can then call:

User.year     # defaults to CURRENT_SEMESTER constant
User.year()  # same as above
User.year(nil)  # same as above; useful if passing a param value that may or may not exist, ie, param[:year]
User.year(2010)
February 16, 2010 - (>= v2.1.0)
3 thanks

Extract the aggregated scoping options

If you want to get the aggregated scoping options of a chain of named scopes use ActiveRecord::Base.current_scoped_methods

It works in the fashion of:

Shirt.red.medium.alphabetical.current_scoped_methods
# ==>
{
  :create => {}, 
  :find => {
    :conditions => {:color => 'red', :size => 'medium'}, 
    :order => 'shirts.name ASC'
  } 
}
May 18, 2010
2 thanks

How using Array methods

It’s not possible to use Array methods with a scope because it’s not an Array but an ActiveRecord::NamedScope::Scope :

this

Article.promotion.sum(&:price)

doesn’t run.

But you can use the to_a method to transform the ActiveRecord::NamedScope::Scope to an Array :

Article.promotion.to_a.sum(&:price)
March 4, 2010
1 thank

AASM named scopes

If you are using the aasm plugin/gem, this will generate all named scopes for your various states.

Code example

Class Article <  ActiveRecord::Base

  include AASM

  aasm_initial_state :created

  aasm_state :published
  aasm_state :unpublished
  aasm_state :deleted
  aasm_state :created

  aasm_event :publish do
    transitions :to => :published, :from => [:created]
  end

  aasm_event :unpublish do
    transitions :to => :unpublished, :from => [:created, :published]
  end

  aasm_event :delete do
    transitions :to => :deleted, :from => [:published, :unpublished]
  end

  aasm_states.each { |s| named_scope s, :conditions => { :state => s.to_s } }  

end
March 23, 2010
1 thank

named_scopes and Acts as State Machine

As of AASM 2.1 named_scope(s) are defined by default for each state of a model.

March 21, 2009
1 thank

Generating empty conditions

In some cases, you might find it useful for your lamba to generate empty conditions based on the passed parameter.

Class Article << ActiveRecord::Base

named_scope :category, lambda { |cat|
  if cat == :all
    { :conditions => {} }
  else
    { :conditions => { :category_id => cat } }
  end  
}

end

Allows you to call something like this:

categories = user_is_admin ? :all : @current_category
Article.category(categories)

Mostly useful when chaining named_scopes together. Avoids more complicated if statements.

August 4, 2010 - (>= v2.0.0)
1 thank

Testing Named Scopes

Thanks for the example of testing named_scopes. Being new to Rails, I struggled to find examples that I could understand. Here is another “simple” test for a named_scope

Mine differs slightly from the one above in that I had to remove a set of {} in the :conditions in my test to avoid an “odd number list for Hash” error. I also replace the param-binding “?” with the number I expect to send in as an argument. My test would did know what args[0] was. I got an “undefined local variable” error.

The named scope in my model:

named_scope :up_to_and_including_year, lambda{ |*args| {

:conditions => [“to_char(grad_dt1,‘YYYY’) <= ?”, args[0]] }}

The test:

test "named_scope :up_to_and_including_year" do
  expected_options = { :conditions =>  ["to_char(grad_dt1,'YYYY') <= ?", '2010'] }
  assert_equal expected_options, Sso::CourseTaken.up_to_and_including_year('2010').proxy_options
end
September 21, 2010
1 thank

using joins, group, having

Code example

named_scope :red, :joins =>   [:color_lis => :color], :group => "color.id", :having => ["color.xx IS NULL"]
October 31, 2010
1 thank

A named_scope also responds to model class methods

for instance

class Student < ActiveRecord::Base

   named_scope :sophomore, :conditions => 'year=2'

   def self.eligible_to_vote
     select{|s| s.age >= 18}
   end

end

ss = Student.sophomore.eligible_to_vote
October 30, 2008
0 thanks

Anyone know the order the scopes assemble conditions?

It seems like last scope = first condition in sql. Can anyone confirm?

March 21, 2009
0 thanks

Remember, named_scope returns an array

named_scope always returns a named_scope object, that acts like an array, even if you’re using it to only find one record. So if you’re trying to perform an association on the results of a named_scope, use the first method to return the model object and not the named_scope object.

Ie:

user = User.my_name_scope
user.articles   # assuming User has_many Articles

will return an error. use this instead:

user = User.my_named_scope.first
user.articles

(Of course this is a poor example because what you should be doing is performing the named_scope on Article with user as the condition, instead of on User. But if you do need to use the results of a named_scope to perform an association call, you have to do it this way to avoid an error.)

February 9, 2011 - (<= v2.3.8)
0 thanks

some gotchas

Works

named_scope :public, :conditions => "public = true"

Works

PUBLIC_CONDITIONS = "public = true"
named_scope :public, :conditions => SomeModel::PUBLIC_CONDITIONS

Works

named_scope :public, lamba { {:conditions => SomeModel.public_conditions} }
def self.public_conditions
  "public = true"
end

Doesn’t work

named_scope :public, :conditions => SomeModel.public_conditions
def self.public_conditions
  "public = true"
end