Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Conditional chaining with ActiveRecord

I've tried to implement conditional chaining and this is what I got:

Controller index action code:

@range_start = params[:range_start]
@range_stop = params[:range_stop]
Contract.within_range(@range_start, @range_stop)

Model code:

def self.within_range(range_start = Date.today - 1.month, range_stop = nil)
  self.started_after(range_start).started_before(range_stop)
end

def self.started_after(range_start)
  if range_start.blank?
    self
  else
    self.where('start_date >=?', range_start)
  end
end

def self.started_before(range_stop)
  if range_stop.blank?
    self
  else
    self.where('start_date<=?', range_stop)
  end
end

It works, but does not looks good. I tried to improve it a bit using tap, without success. How this code can be improved?

UPDATE: In can be converted to inline conditional, but maybe something else can be improved?

range_start.blank? ? self : self.where('start_date >=?', range_start)

UPDATE2: If range_stop is not set, this code is not really works, started_after condition does not apply.

What I have to return from started_before to do not loose first condition?

like image 355
denis.peplin Avatar asked Dec 03 '22 01:12

denis.peplin


1 Answers

Time has passed and the solution of denis.peplin is already deprecated. Otherwise it's right, you need a relation for chaining. So instead of using scoped you should use all like this:

def self.started_before(range_stop)
  if range_stop.blank?
    all
  else
    where('start_date<=?', range_stop)
  end
end

But you could also write this as a scope for more brevity:

scope :started_before, ->(range_stop){ range_stop.blank? ? all : where('start_date<=?', range_stop) }
like image 113
wdspkr Avatar answered Jan 05 '23 20:01

wdspkr