ramamoorthy_villi
ramamoorthy_villi

Reputation: 2055

handle ruby send nil

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

Answers (1)

Schwern
Schwern

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

Related Questions