Bruno
Bruno

Reputation: 6449

Previous/Next links based on model's function

How do I display previous/next links according to vehicle.vehicle_status

In my show view:

- if @vehicle.previous
  = link_to "< Previous", @vehicle.previous
- if @vehicle.next
  = link_to "Next >", @vehicle.next

In my model:

def previous
  ?
end

def next
  ?
end

vehicles/index.html.haml view:

- @vehicles.each do |vehicle|
  %tr
    %td.dashbox{:class => vehicle.vehicle_status, :style =>'width:18px;', :onclick=>"top.location=#{vehicle_url(vehicle)}"}

vehicle_status in model:

def vehicle_status
  if self.maintenance_status=='c1' or self.fuel_efficiency_status=='c1' or self.system_status=='c1'
  'c1'
  elsif self.maintenance_status=='c2' or self.fuel_efficiency_status=='c2' or self.system_status=='c2'
  'c2'
  elsif self.maintenance_status=='c4' or self.fuel_efficiency_status=='c4' or self.system_status=='c4'
  'c4'
  else
  'c3'
  end
end

Upvotes: 0

Views: 103

Answers (1)

PinnyM
PinnyM

Reputation: 35531

scope :previous, lambda { |vehicle| 
  where("vehicles.vehicle_status < ?", vehicle.vehicle_status).
    order(:vehicle_status).reverse
}

scope :next, lambda { |vehicle|
  where("vehicles.vehicle_status > ?", vehicle.vehicle_status).
    order(:vehicle_status)
}

def previous
  @previous ||= Vehicle.previous(self).first
end

def next
  @next ||= Vehicle.next(self).first
end

In light of the fact that vehicle_status is a calculation and not a static field, and that there are other factors involved in the sorting, you can modify the scopes to look like this (using a helper method for the CASE string):

def self.vehicle_status_sql
  <<-SQL
    CASE 
      WHEN 'c1' IN (maintentance_status, fuel_efficiency_status, system_status) THEN 'c1'
      WHEN 'c2' IN (maintentance_status, fuel_efficiency_status, system_status) THEN 'c2'
      WHEN 'c4' IN (maintentance_status, fuel_efficiency_status, system_status) THEN 'c4'
      ELSE 'c3'
    END
  SQL
end

scope :previous, lambda { |vehicle| 
  where("#{vehicle_status_sql} < :status OR (#{vehicle_status_sql} = :status AND (vehicles.odometer < :odometer OR (vehicles.odometer = :odometer AND vehicles.id < :id)))", 
    status: vehicle.vehicle_status, odometer: vehicle.odometer, id: vehicle.id).
  order("#{vehicle_status_sql} DESC, vehicles.odometer DESC")
}

scope :next, lambda { |vehicle| 
  where("#{vehicle_status_sql} > :status OR ((#{vehicle_status_sql} = :status AND (vehicles.odometer > :odometer OR (vehicles.odometer = :odometer AND vehicles.id > :id)))",
    status: vehicle.vehicle_status, odometer: vehicle.odometer, id: vehicle.id).
  order("#{vehicle_status_sql}, vehicles.odometer)
}

Upvotes: 0

Related Questions