Is it possible to have a scope with optional arguments?
Solution 1
Yes. Just use a *
like you would in a method.
scope :print_args, lambda {|*args|
puts args
}
Solution 2
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)}
Call:
Model.cheap
Model.cheap(15)
Solution 3
I used scope :name, ->(arg1, arg2 = value) { ... }
a few weeks ago, it worked well, if my memory's correct. To use with ruby 1.9+
Solution 4
You can conditionally modify your scope based on a given argument.
scope :random, ->(num = nil){ num ? order('RANDOM()').limit(num) : order('RANDOM()') }
Usage:
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) }
Usage:
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.
Solution 5
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)
end
end
This can give a cleaner approach.
Related videos on Youtube
tonymarschall
Updated on June 11, 2022Comments
-
tonymarschall almost 2 years
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) } Model.with_optional_args('foo') Model.with_optional_args
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)
-
Paul Simpson about 12 yearsWouldn't you want to include a fallback for when no args are passed?
-
tonymarschall about 12 yearsI got an error if i do not pass an argument: ArgumentError: wrong number of arguments (0 for 1)
-
Christian about 12 yearsYou could use Proc.new instead of lambda to avoid the argument error. See this old discussion on this here