Take the 2-minute tour ×

Is it possible to write a scope with optional arguments so that i can call the scope with and without arguments?

Something like:

scope :with_optional_args,  lambda { |arg|
  where("table.name = ?", arg)


I can check in the lambda block if an arg is given (like described by Unixmonkey) but on calling the scope without an argument i got an ArgumentError: wrong number of arguments (0 for 1)

share|improve this question

6 Answers 6

up vote 13 down vote accepted

Yes. Just use a * like you would in a method.

scope :print_args, lambda {|*args|
    puts args
share|improve this answer


scope :with_optional_args,  Proc.new { |arg|
  if arg.present?
    where("table.name = ?", arg)
share|improve this answer
Wouldn't you want to include a fallback for when no args are passed? –  Paul Simpson Apr 26 '12 at 18:01
I got an error if i do not pass an argument: ArgumentError: wrong number of arguments (0 for 1) –  tonymarschall Apr 26 '12 at 18:11
You could use Proc.new instead of lambda to avoid the argument error. See this old discussion on this here –  Christian Apr 26 '12 at 18:53

I used scope :name, ->(arg1, arg2 = value) { ... } a few weeks ago, it worked good, if memory's correct. To use with ruby 1.9+

share|improve this answer

Ruby 1.9 extended blocks to have the same features as methods do (default values are among them):

scope :cheap, lambda{|max_price=20.0| where("price < ?", max_price)}


share|improve this answer

Just wanted to let you know that according to the guide, the recommended way for passing arguments to scopes is to use a class method, like this:

class Post < ActiveRecord::Base
  def self.1_week_before(time)
    where("created_at < ?", time)

This can give a cleaner approach.

share|improve this answer

You can conditionally modify your scope based on a given argument.

scope :random, ->(num = nil){ num ? order('RANDOM()').limit(num) : order('RANDOM()') }


Advertisement.random # => returns all records randomized
Advertisement.random(1) # => returns 1 random record

Or, you can provide a default value.

scope :random, ->(num = 1000){ order('RANDOM()').limit(num) }


Product.random # => returns 1,000 random products
Product.random(5) # => returns 5 random products

NOTE: The syntax shown for RANDOM() is specific to Postgres. The syntax shown is Rails 4.

share|improve this answer

Your Answer


