Reputation: 2055
scope :
class Car < ApplicationRecord
scope :sold_between, -> (start_date, end_date,exclude_used_cars=true){
_used = exclude_used_cars ? "exclude_used_cars" : ""
Car.where("start_date <= ?", start_date ).and("end_date <= ?", end_date ).send(_used)
}
scope :exclude_used_cars, -> {
where.not(state: :used)
}
Problem:
stuck with .send(_used)
I need to pass some valid symbols, but actually I have nil value exclude_used_cars
when it is false.
Any better way solving this. Thanks
Upvotes: 1
Views: 509
Reputation: 165110
This can be solved by using a normal if
and taking advantage of the chaining nature of queries.
Note that your where
clause isn't quite right. Values need to be passed in using placeholders. While there is a .or
there is no .and
. Additional .where
calls will go together with and
.
Also note that I've avoided hard coding the Car
class name in the scope. This ensures it will work with subclasses.
scope :sold_between, -> (start_date, end_date,exclude_used_cars=true){
query = where(
"start_date <= :start_date and end_date >= :end_date",
{ start_date: start_date, end_date: end_date }
)
if exclude_used_cars
query = query.exclude_used_cars
end
query
}
Because you can chain queries and scopes like this consider whether there's a need for a special exclude_used_cars
parameter, especially one that defaults to true
. The user of sold_between
can as easily add the scope themselves. This is simpler and more explicit.
scope :sold_between, -> (start_date, end_date) {
where(
"start_date <= :start_date and end_date >= :end_date",
{ start_date: start_date, end_date: end_date }
)
}
# All cars
Cars.sold_between(start, end)
# Without used cars
Cars.sold_between(start, end).exclude_used_cars
Upvotes: 1