class MutableChain
attr_reader :subject
def initialize(subject)
@subject = subject
end
def method_missing(method_name, *args, &block)
if subject.respond_to?(method_name)
@subject = subject.send(method_name, *args, &block)
else
super
end
end
def respond_if_missing?(method_name, include_private = false)
subject.respond_to?(method_name, include_private) || super
end
end
Complex construction of an ActiveRecord::Relation. Each scope returns a new relation, but we're really trying to chain them together to build one complex chain:
def results
criteria = Booking.confirmed
if filter == :pick_ups
criteria = criteria.origin(location) if location
criteria = criteria.start_time_between(date_range)
elsif filter == :drop_offs
criteria = criteria.destination(location) if location
criteria = criteria.end_time_between(date_range)
else
criteria = criteria.origin_or_destination(location) if location
criteria = criteria.start_or_end_time_between(date_range)
end
criteria = criteria.includes(:drivers)
criteria.page(page)
end
Methods can now be chained without variable reassignment:
def results
criteria = MutableChain.new(Booking)
criteria.confirmed
if filter == :pick_ups
criteria.origin(location) if location
criteria.start_time_between(date_range)
elsif filter == :drop_offs
criteria.destination(location) if location
criteria.end_time_between(date_range)
else
criteria.origin_or_destination(location) if location
criteria.start_or_end_time_between(date_range)
end
criteria.includes(:drivers)
criteria.page(page)
end